/// <summary> /// Attempts to initialize the OpenGL context with the specified configuration. /// </summary> private Boolean TryInitializeGLContext(IntPtr masterptr, OpenGLUltravioletConfiguration configuration) { if (configuration.Debug) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, (int)SDL_GL_CONTEXT_DEBUG_FLAG); } if ((this.context = SDL_GL_CreateContext(masterptr)) == IntPtr.Zero) { if (configuration.Debug) { if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0) < 0) { throw new SDL2Exception(); } if ((this.context = SDL_GL_CreateContext(masterptr)) != IntPtr.Zero) { return(true); } } return(false); } return(true); }
/// <summary> /// Initializes a new instance of the OpenGLUltravioletContext class. /// </summary> /// <param name="host">The object that is hosting the Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for this context.</param> public OpenGLUltravioletContext(IUltravioletHost host, OpenGLUltravioletConfiguration configuration) : base(host, configuration) { Contract.Require(configuration, nameof(configuration)); IsHardwareInputDisabled = configuration.IsHardwareInputDisabled; if (!InitSDL(configuration)) { throw new SDL2Exception(); } InitOpenGLVersion(configuration, out var versionRequested, out var versionRequired, out var isGLEs); if (!configuration.EnableServiceMode) { InitOpenGLAttributes(configuration, isGLEs); } var sdlAssembly = typeof(SDLNative).Assembly; InitializeFactoryMethodsInAssembly(sdlAssembly); var sdlconfig = new SDL2PlatformConfiguration(); sdlconfig.RenderingAPI = SDL2PlatformRenderingAPI.OpenGL; sdlconfig.MultiSampleBuffers = configuration.MultiSampleBuffers; sdlconfig.MultiSampleSamples = configuration.MultiSampleSamples; sdlconfig.SrgbBuffersEnabled = configuration.SrgbBuffersEnabled; this.platform = IsRunningInServiceMode ? (IUltravioletPlatform) new DummyUltravioletPlatform(this) : new SDL2UltravioletPlatform(this, configuration, sdlconfig); PumpEvents(); if (IsRunningInServiceMode) { this.graphics = new DummyUltravioletGraphics(this); this.audio = new DummyUltravioletAudio(this); this.input = new DummyUltravioletInput(this); } else { this.graphics = new OpenGLUltravioletGraphics(this, configuration, versionRequested, versionRequired); ((OpenGLUltravioletGraphics)this.graphics).ResetDeviceStates(); this.audio = InitializeAudioSubsystem(configuration); this.input = new SDL2UltravioletInput(this); } this.content = new UltravioletContent(this); this.content.RegisterImportersAndProcessors(new[] { sdlAssembly, AudioSubsystemAssembly }); this.content.Importers.RegisterImporter <XmlContentImporter>("prog"); this.ui = new UltravioletUI(this, configuration); PumpEvents(); InitializeContext(); InitializeViewProvider(configuration); InitializePlugins(configuration); }
/// <summary> /// Initializes the context's audio subsystem. /// </summary> /// <param name="configuration">The Ultraviolet Framework configuration settings for this context.</param> /// <returns>The audio subsystem.</returns> private IUltravioletAudio InitializeAudioSubsystem(OpenGLUltravioletConfiguration configuration) { if (String.IsNullOrEmpty(configuration.AudioSubsystemAssembly)) { throw new InvalidOperationException(OpenGLStrings.MissingAudioAssembly); } Assembly asm; try { asm = Assembly.Load(configuration.AudioSubsystemAssembly); InitializeFactoryMethodsInAssembly(asm); AudioSubsystemAssembly = asm; } catch (Exception e) { if (e is FileNotFoundException || e is FileLoadException || e is BadImageFormatException) { throw new InvalidOperationException(OpenGLStrings.InvalidAudioAssembly, e); } throw; } var types = (from t in asm.GetTypes() where t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(typeof(IUltravioletAudio)) select t).ToList(); if (!types.Any() || types.Count > 1) { throw new InvalidOperationException(OpenGLStrings.InvalidAudioAssembly); } var type = types.Single(); var ctorWithConfig = type.GetConstructor(new[] { typeof(UltravioletContext), typeof(UltravioletConfiguration) }); if (ctorWithConfig != null) { return((IUltravioletAudio)ctorWithConfig.Invoke(new object[] { this, configuration })); } var ctorWithoutConfig = type.GetConstructor(new[] { typeof(UltravioletContext) }); if (ctorWithoutConfig != null) { return((IUltravioletAudio)ctorWithoutConfig.Invoke(new object[] { this })); } throw new InvalidOperationException(OpenGLStrings.InvalidAudioAssembly); }
/// <summary> /// Determines which version of OpenGL will be used by the context. /// </summary> private void InitOpenGLVersion(OpenGLUltravioletConfiguration configuration, out Version versionRequested, out Version versionRequired, out Boolean isGLES) { isGLES = (Platform == UltravioletPlatform.Android || Platform == UltravioletPlatform.iOS); versionRequired = isGLES ? new Version(2, 0) : new Version(3, 1); versionRequested = isGLES ? configuration.MinimumOpenGLESVersion : configuration.MinimumOpenGLVersion; if (versionRequested != null && versionRequested < versionRequired) { versionRequested = versionRequired; } }
/// <summary> /// Initializes a new instance of the OpenGLUltravioletGraphics class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> /// <param name="versionRequested">The OpenGL context version which is required by the application.</param> public unsafe OpenGLUltravioletGraphics(OpenGLUltravioletContext uv, OpenGLUltravioletConfiguration configuration, Version versionRequested) : base(uv) { var masterptr = ((SDL2UltravioletWindowInfo)uv.GetPlatform().Windows).GetMasterPointer(); if (!TryInitializeGLContext(masterptr, configuration)) { var attemptedVersionMajor = 0; var attemptedVersionMinor = 0; if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &attemptedVersionMajor) < 0) { throw new SDL2Exception(); } if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &attemptedVersionMinor) < 0) { throw new SDL2Exception(); } var attemptedVersion = new Version(attemptedVersionMajor, attemptedVersionMinor, 0, 0); var isGLES = (uv.Platform == UltravioletPlatform.Android || uv.Platform == UltravioletPlatform.iOS); if (isGLES && attemptedVersion >= new Version(3, 0) && (configuration.MinimumOpenGLESVersion ?? new Version(2, 0)) <= new Version(2, 0)) { if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0) < 0) { throw new SDL2Exception(); } if (!TryInitializeGLContext(masterptr, configuration)) { throw new SDL2Exception(); } } else { throw new SDL2Exception(); } } if (SDL_GL_SetSwapInterval(1) < 0 && uv.Platform != UltravioletPlatform.iOS) { throw new SDL2Exception(); } if (gl.Initialized) { gl.Uninitialize(); } gl.Initialize(new OpenGLInitializer()); if (!gl.IsVersionAtLeast(versionRequested)) { throw new InvalidOperationException(OpenGLStrings.DoesNotMeetMinimumVersionRequirement.Format(gl.MajorVersion, gl.MinorVersion, versionRequested.Major, versionRequested.Minor)); } OpenGLState.ResetCache(); if (!VerifyCapabilities()) { throw new NotSupportedException(OpenGLStrings.UnsupportedGraphicsDevice); } if (configuration.Debug && configuration.DebugCallback != null) { InitializeDebugOutput(configuration); } this.capabilities = new OpenGLGraphicsCapabilities(configuration); if (capabilities.SrgbEncodingEnabled && gl.IsFramebufferSrgbAvailable) { gl.Enable(gl.GL_FRAMEBUFFER_SRGB); gl.ThrowIfError(); } this.maxTextureStages = gl.GetInteger(gl.GL_MAX_TEXTURE_IMAGE_UNITS); this.textures = new Texture[maxTextureStages]; this.samplerStates = new SamplerState[maxTextureStages]; this.samplerObjects = capabilities.SupportsIndependentSamplerState ? new OpenGLSamplerObject[maxTextureStages] : null; this.backBufferRenderTargetUsage = configuration.BackBufferRenderTargetUsage; if (samplerObjects != null) { for (int i = 0; i < samplerObjects.Length; i++) { samplerObjects[i] = new OpenGLSamplerObject(Ultraviolet); samplerObjects[i].Bind((uint)i); } } OpenGLState.VerifyCache(); }
/// <summary> /// Initializes a new instance of the OpenGLUltravioletGraphics class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> /// <param name="versionRequested">The OpenGL context version which is requested by the application.</param> /// <param name="versionRequired">The OpenGL context version which is required by the Ultraviolet Framework.</param> public unsafe OpenGLUltravioletGraphics(OpenGLUltravioletContext uv, OpenGLUltravioletConfiguration configuration, Version versionRequested, Version versionRequired) : base(uv) { if (this.context == IntPtr.Zero && configuration.Debug) { this.context = TryCreateOpenGLContext(uv, versionRequested, versionRequired, true, false) ?? IntPtr.Zero; } if (this.context == IntPtr.Zero) { this.context = TryCreateOpenGLContext(uv, versionRequested, versionRequired, false, true) ?? IntPtr.Zero; } if (SDL_GL_SetSwapInterval(1) < 0 && uv.Platform != UltravioletPlatform.iOS) { throw new SDL2Exception(); } if (gl.Initialized) { gl.Uninitialize(); } gl.Initialize(new OpenGLInitializer()); if (!gl.IsVersionAtLeast(versionRequested ?? versionRequired)) { throw new InvalidOperationException(OpenGLStrings.DoesNotMeetMinimumVersionRequirement.Format(gl.MajorVersion, gl.MinorVersion, versionRequested.Major, versionRequested.Minor)); } OpenGLState.ResetCache(); if (!VerifyCapabilities()) { throw new NotSupportedException(OpenGLStrings.UnsupportedGraphicsDevice); } if (configuration.Debug && configuration.DebugCallback != null) { InitializeDebugOutput(configuration); } this.Capabilities = new OpenGLGraphicsCapabilities(configuration); if (Capabilities.SrgbEncodingEnabled && gl.IsFramebufferSrgbAvailable) { gl.Enable(gl.GL_FRAMEBUFFER_SRGB); gl.ThrowIfError(); } this.maxTextureStages = gl.GetInteger(gl.GL_MAX_TEXTURE_IMAGE_UNITS); this.textures = new Texture[maxTextureStages]; this.samplerStates = new SamplerState[maxTextureStages]; this.samplerObjects = Capabilities.SupportsIndependentSamplerState ? new OpenGLSamplerObject[maxTextureStages] : null; this.backBufferRenderTargetUsage = configuration.BackBufferRenderTargetUsage; if (samplerObjects != null) { for (int i = 0; i < samplerObjects.Length; i++) { samplerObjects[i] = new OpenGLSamplerObject(Ultraviolet); samplerObjects[i].Bind((uint)i); } } OpenGLState.VerifyCache(); }
/// <summary> /// Initializes a new instance of the OpenGLUltravioletGraphics class. /// </summary> /// <param name="uv">The Ultraviolet context.</param> /// <param name="configuration">The Ultraviolet Framework configuration settings for the current context.</param> /// <param name="versionRequested">The OpenGL context version which is requested by the application.</param> /// <param name="versionRequired">The OpenGL context version which is required by the Ultraviolet Framework.</param> public unsafe OpenGLUltravioletGraphics(OpenGLUltravioletContext uv, OpenGLUltravioletConfiguration configuration, Version versionRequested, Version versionRequired) : base(uv) { var isGLES = (uv.Platform == UltravioletPlatform.Android || uv.Platform == UltravioletPlatform.iOS); if (configuration.Debug) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, (int)SDL_GL_CONTEXT_DEBUG_FLAG); } var masterptr = ((SDL2UltravioletWindowInfo)uv.GetPlatform().Windows).GetMasterPointer(); var versionArray = isGLES ? KnownOpenGLESVersions : KnownOpenGLVersions; var versionMin = versionRequested ?? versionRequired; var versionCurrent = versionRequested ?? versionArray[0]; var versionCurrentIndex = Array.IndexOf(versionArray, versionCurrent); do { if (versionCurrent < versionMin) { throw new InvalidOperationException(OpenGLStrings.DoesNotMeetMinimumVersionRequirement.Format(versionMin.Major, versionMin.Minor)); } if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, versionCurrent.Major) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, versionCurrent.Minor) < 0) { throw new SDL2Exception(); } versionCurrent = versionArray[++versionCurrentIndex]; }while ((this.context = SDL_GL_CreateContext(masterptr)) == IntPtr.Zero); if (SDL_GL_SetSwapInterval(1) < 0 && uv.Platform != UltravioletPlatform.iOS) { throw new SDL2Exception(); } if (gl.Initialized) { gl.Uninitialize(); } gl.Initialize(new OpenGLInitializer()); if (!gl.IsVersionAtLeast(versionRequested ?? versionRequired)) { throw new InvalidOperationException(OpenGLStrings.DoesNotMeetMinimumVersionRequirement.Format(gl.MajorVersion, gl.MinorVersion, versionRequested.Major, versionRequested.Minor)); } OpenGLState.ResetCache(); if (!VerifyCapabilities()) { throw new NotSupportedException(OpenGLStrings.UnsupportedGraphicsDevice); } if (configuration.Debug && configuration.DebugCallback != null) { InitializeDebugOutput(configuration); } this.Capabilities = new OpenGLGraphicsCapabilities(configuration); if (Capabilities.SrgbEncodingEnabled && gl.IsFramebufferSrgbAvailable) { gl.Enable(gl.GL_FRAMEBUFFER_SRGB); gl.ThrowIfError(); } this.maxTextureStages = gl.GetInteger(gl.GL_MAX_TEXTURE_IMAGE_UNITS); this.textures = new Texture[maxTextureStages]; this.samplerStates = new SamplerState[maxTextureStages]; this.samplerObjects = Capabilities.SupportsIndependentSamplerState ? new OpenGLSamplerObject[maxTextureStages] : null; this.backBufferRenderTargetUsage = configuration.BackBufferRenderTargetUsage; if (samplerObjects != null) { for (int i = 0; i < samplerObjects.Length; i++) { samplerObjects[i] = new OpenGLSamplerObject(Ultraviolet); samplerObjects[i].Bind((uint)i); } } OpenGLState.VerifyCache(); }
/// <summary> /// Sets the SDL2 attributes which correspond to the application's OpenGL settings. /// </summary> private void InitOpenGLAttributes(OpenGLUltravioletConfiguration configuration, Boolean isGLES) { var profile = isGLES ? SDL_GL_CONTEXT_PROFILE_ES : SDL_GL_CONTEXT_PROFILE_CORE; if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, (Int32)profile) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, configuration.BackBufferDepthSize) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, configuration.BackBufferStencilSize) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0) < 0) { throw new SDL2Exception(); } if (configuration.Use32BitFramebuffer) { if (SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8) < 0) { throw new SDL2Exception(); } } else { if (SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5) < 0) { throw new SDL2Exception(); } } if (configuration.SrgbBuffersEnabled) { if (SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1) < 0) { throw new SDL2Exception(); } unsafe { var value = 0; if (SDL_GL_GetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, &value) < 0) { throw new SDL2Exception(); } if (value != 1) { configuration.SrgbBuffersEnabled = false; } } } }
/// <summary> /// Sets the SDL2 attributes which correspond to the application's OpenGL settings. /// </summary> private void InitOpenGLAttributes(OpenGLUltravioletConfiguration configuration, Version versionRequested, Version versionRequired, Boolean isGLES) { var profile = isGLES ? SDL_GL_CONTEXT_PROFILE_ES : SDL_GL_CONTEXT_PROFILE_CORE; if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, (Int32)profile) < 0) { throw new SDL2Exception(); } // NOTE: Asking for an ES 3.0 context in the emulator will return a valid // context pointer, but actually using it will cause segfaults. It seems like // the best thing to do on Android is just not ask for a specific version, // and trust the OS to give you the highest version it supports. if (Platform != UltravioletPlatform.Android) { if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, versionRequested.Major) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, versionRequested.Minor) < 0) { throw new SDL2Exception(); } } if (SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, configuration.BackBufferDepthSize) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, configuration.BackBufferStencilSize) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0) < 0) { throw new SDL2Exception(); } if (configuration.Use32BitFramebuffer) { if (SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8) < 0) { throw new SDL2Exception(); } } else { if (SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6) < 0) { throw new SDL2Exception(); } if (SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5) < 0) { throw new SDL2Exception(); } } if (configuration.SrgbBuffersEnabled) { if (SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1) < 0) { throw new SDL2Exception(); } unsafe { var value = 0; if (SDL_GL_GetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, &value) < 0) { throw new SDL2Exception(); } if (value != 1) { configuration.SrgbBuffersEnabled = false; } } } }