/// <summary> /// Process shader source lines to resolve #include directives. /// </summary> /// <param name="includeLibrary"> /// A <see cref="ShaderIncludeLibrary"/> determining the shader include file system. /// </param> /// <param name="cctx"> /// A <see cref="ShaderCompilerContext"/> that specify the compiler parameteres. /// </param> /// <param name="shaderSource"> /// A <see cref="IEnumerable{String}"/> that specify the shader source lines. Null items in the enumeration /// will be ignored. /// </param> /// <returns> /// It returns the processed source lines <paramref name="shaderSource"/>, but without any #include directive. Each #include /// directive will be replaced by the corresponding text depending on <paramref name="cctx"/>. /// </returns> /// <remarks> /// <para> /// </para> /// </remarks> /// <exception cref="ArgumentNullException"> /// Exception throw if <paramref name="includeLibrary"/>, <paramref name="cctx"/> or <paramref name="shaderSource"/> is null. /// </exception> public static List<string> Process(ShaderIncludeLibrary includeLibrary, ShaderCompilerContext cctx, List<string> shaderSource) { if (includeLibrary == null) throw new ArgumentNullException("includeLibrary"); if (cctx == null) throw new ArgumentNullException("cctx"); if (shaderSource == null) throw new ArgumentNullException("sSource"); IncludeProcessorContext ictx = new IncludeProcessorContext(); return (Process(includeLibrary, cctx, ictx, shaderSource)); }
/// <summary> /// Process shader source lines to resolve #include directives. /// </summary> /// <param name="includeLibrary"> /// A <see cref="ShaderIncludeLibrary"/> determining the shader include file system. /// </param> /// <param name="cctx"> /// A <see cref="ShaderCompilerContext"/> that specify the compiler parameteres. /// </param> /// <param name="shaderSource"> /// A <see cref="IEnumerable{String}"/> that specify the shader source lines. Null items in the enumeration /// will be ignored. /// </param> /// <returns> /// It returns the processed source lines <paramref name="shaderSource"/>, but without any #include directive. Each #include /// directive will be replaced by the corresponding text depending on <paramref name="cctx"/>. /// </returns> /// <remarks> /// <para> /// </para> /// </remarks> /// <exception cref="ArgumentNullException"> /// Exception throw if <paramref name="includeLibrary"/>, <paramref name="cctx"/> or <paramref name="shaderSource"/> is null. /// </exception> public static List <string> Process(ShaderIncludeLibrary includeLibrary, ShaderCompilerContext cctx, List <string> shaderSource) { if (includeLibrary == null) { throw new ArgumentNullException("includeLibrary"); } if (cctx == null) { throw new ArgumentNullException("cctx"); } if (shaderSource == null) { throw new ArgumentNullException("sSource"); } IncludeProcessorContext ictx = new IncludeProcessorContext(); return(Process(includeLibrary, cctx, ictx, shaderSource)); }
/// <summary> /// Construct a GraphicsContext specifying the implemented OpenGL version. /// </summary> /// <param name="deviceContext"> /// A <see cref="IDeviceContext"/> that specify the device context which has to be linked this /// this Render context. /// </param> /// <param name="sharedContext"> /// A <see cref="GraphicsContext"/> that specify the render context which has to be linked this /// this Render context (to share resource with it). /// </param> /// <param name="version"> /// A <see cref="KhronosVersion"/> that specify the minimum OpenGL version required to implement. /// </param> /// <param name="flags"> /// A <see cref="GraphicsContextFlags"/> that specify special features to enable in the case they are supported. /// </param> /// <exception cref="ArgumentException"> /// Exception thrown in the case <paramref name="version"/> is different from the currently implemented by the derive, /// and the OpenGL extension WGL_ARB_create_context_profile or WGL_ARB_create_context are not implemented. /// </exception> /// <exception cref="ArgumentException"> /// This exception is thrown in the case <paramref name="version"/> specify a forward compatible version (greater than or equal to /// <see cref="GLVersion.Version_3_2"/>), and the OpenGL extension WGL_ARB_create_context_profile or WGL_ARB_create_context /// are not implemented. /// </exception> /// <exception cref="ArgumentException"> /// This exception is thrown in the case <paramref name="devctx"/> is <see cref="IntPtr.Zero"/>. /// </exception> /// <exception cref="InvalidOperationException"> /// This exception is thrown in the case it's not possible to create a valid OpenGL context. /// </exception> /// <exception cref="ArgumentException"> /// This exception is thrown if <paramref name="sharedContext"/> is not null and it was created by a thread different from the calling one. /// </exception> /// <exception cref="ArgumentException"> /// This exception is thrown if <paramref name="sharedContext"/> is not null and it is disposed. /// </exception> public GraphicsContext(IDeviceContext deviceContext, GraphicsContext sharedContext, KhronosVersion version, GraphicsContextFlags flags) { try { IntPtr sharedContextHandle = (sharedContext != null) ? sharedContext._RenderContext : IntPtr.Zero; #if DEBUG _ConstructorStackTrace = Environment.StackTrace; #endif // Store thread ID of the render context _RenderContextThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; // Store thread ID of the device context _DeviceContextThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; if (deviceContext == null) throw new ArgumentNullException("deviceContext"); if ((sharedContext != null) && (sharedContext._DeviceContext == null)) throw new ArgumentException("shared context disposed", "hSharedContext"); if ((sharedContext != null) && (sharedContext._RenderContextThreadId != _RenderContextThreadId)) throw new ArgumentException("shared context created from another thread", "hSharedContext"); if ((version != null) && (version != _CurrentVersion) && ((CurrentCaps.PlatformExtensions.CreateContext_ARB == false) && (CurrentCaps.PlatformExtensions.CreateContextProfile_ARB == false))) throw new ArgumentException("unable to specify OpenGL version when GL_ARB_create_context[_profile] is not supported"); // Store device context handle _DeviceContext = deviceContext; _DeviceContext.IncRef(); // Allow version to be null (fallback to current version) version = version ?? _CurrentVersion; // Set flags _ContextFlags = flags; if ((CurrentCaps.PlatformExtensions.CreateContext_ARB || CurrentCaps.PlatformExtensions.CreateContextProfile_ARB) && (version.Major >= 3)) { List<int> cAttributes = new List<int>(); #region Context Version // Requires a specific version Debug.Assert(Wgl.CONTEXT_MAJOR_VERSION_ARB == Glx.CONTEXT_MAJOR_VERSION_ARB); Debug.Assert(Wgl.CONTEXT_MINOR_VERSION_ARB == Glx.CONTEXT_MINOR_VERSION_ARB); cAttributes.AddRange(new int[] { Wgl.CONTEXT_MAJOR_VERSION_ARB, version.Major, Wgl.CONTEXT_MINOR_VERSION_ARB, version.Minor }); #endregion #region Context Profile uint contextProfile = 0; // Check binary compatibility between WGL and GLX Debug.Assert(Wgl.CONTEXT_PROFILE_MASK_ARB == Glx.CONTEXT_PROFILE_MASK_ARB); Debug.Assert(Wgl.CONTEXT_CORE_PROFILE_BIT_ARB == Glx.CONTEXT_CORE_PROFILE_BIT_ARB); Debug.Assert(Wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB == Glx.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); Debug.Assert(Wgl.CONTEXT_ES_PROFILE_BIT_EXT == Glx.CONTEXT_ES_PROFILE_BIT_EXT); // By default, Core profile // Core profile? if ((flags & GraphicsContextFlags.CoreProfile) != 0) contextProfile |= Wgl.CONTEXT_CORE_PROFILE_BIT_ARB; // Compatibility profile? if ((flags & GraphicsContextFlags.CompatibilityProfile) != 0) contextProfile |= Wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; // OpenGL ES profile? if ((flags & GraphicsContextFlags.EmbeddedProfile) != 0) contextProfile |= Wgl.CONTEXT_ES_PROFILE_BIT_EXT; if (contextProfile != 0) { cAttributes.AddRange(new int[] { Wgl.CONTEXT_PROFILE_MASK_ARB, unchecked((int)contextProfile) }); } #endregion #region Context Flags uint contextFlags = 0; // Check binary compatibility between WGL and GLX Debug.Assert(Wgl.CONTEXT_FLAGS_ARB == Glx.CONTEXT_FLAGS_ARB); Debug.Assert(Wgl.CONTEXT_FORWARD_COMPATIBLE_BIT_ARB == Glx.CONTEXT_FORWARD_COMPATIBLE_BIT_ARB); Debug.Assert(Wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB == Glx.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); Debug.Assert(Wgl.CONTEXT_DEBUG_BIT_ARB == Glx.CONTEXT_DEBUG_BIT_ARB); Debug.Assert(Wgl.CONTEXT_ROBUST_ACCESS_BIT_ARB == Glx.CONTEXT_ROBUST_ACCESS_BIT_ARB); Debug.Assert(Wgl.CONTEXT_RESET_ISOLATION_BIT_ARB == Glx.CONTEXT_RESET_ISOLATION_BIT_ARB); if (((flags & GraphicsContextFlags.CompatibilityProfile) != 0) && (_CurrentCaps.GlExtensions.Compatibility_ARB == false)) throw new NotSupportedException("compatibility profile not supported"); if (((flags & GraphicsContextFlags.Robust) != 0) && (_CurrentCaps.GlExtensions.Robustness_ARB == false && _CurrentCaps.GlExtensions.Robustness_EXT == false)) throw new NotSupportedException("robust profile not supported"); // Context flags: debug context if ((flags & GraphicsContextFlags.Debug) != 0) contextFlags |= Wgl.CONTEXT_DEBUG_BIT_ARB; // Context flags: forward compatible context if ((flags & GraphicsContextFlags.ForwardCompatible) != 0) contextFlags |= Wgl.CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; // Context flags: robust behavior if ((flags & GraphicsContextFlags.Robust) != 0) contextFlags |= Wgl.CONTEXT_ROBUST_ACCESS_BIT_ARB; // Context flags: reset isolation if ((flags & GraphicsContextFlags.ResetIsolation) != 0) contextFlags |= Wgl.CONTEXT_RESET_ISOLATION_BIT_ARB; if (contextFlags != 0) { cAttributes.AddRange(new int[] { Wgl.CONTEXT_FLAGS_ARB, unchecked((int)contextFlags) }); } #endregion // End of attributes cAttributes.Add(0); // Create rendering context int[] contextAttributes = cAttributes.ToArray(); _RenderContext = _DeviceContext.CreateContextAttrib(sharedContextHandle, contextAttributes); Debug.Assert(_RenderContext != IntPtr.Zero); } else { // Create rendering context _RenderContext = _DeviceContext.CreateContext(sharedContextHandle); Debug.Assert(_RenderContext != IntPtr.Zero); } if (_RenderContext == IntPtr.Zero) throw new InvalidOperationException(String.Format("unable to create context {0}", version)); // Allow the creation of a GraphicsContext while another GraphicsContext is currently current to the // calling thread: restore currency after the job get done GraphicsContext prevContext = GetCurrentContext(); IDeviceContext prevContextDevice = (prevContext != null) ? prevContext._CurrentDeviceContext : null; // This will cause OpenGL operation flushed... not too bad MakeCurrent(deviceContext, true); // Get the current OpenGL implementation supported by this GraphicsContext _Version = KhronosVersion.Parse(Gl.GetString(StringName.Version)); // Get the current OpenGL Shading Language implementation supported by this GraphicsContext _ShadingVersion = KhronosVersion.Parse(Gl.GetString(StringName.ShadingLanguageVersion)); // Query context capabilities _CapsStack.Push(GraphicsCapabilities.Query(this, deviceContext)); // Determine this GraphicsContext object namespace if (sharedContext != null) { // Sharing same object name space _ObjectNameSpace = sharedContext._ObjectNameSpace; } else { // Reserved object name space _ObjectNameSpace = Guid.NewGuid(); } // Create shader include library (GLSL #include support) _ShaderIncludeLibrary = new ShaderIncludeLibrary(); _ShaderIncludeLibrary.Create(this); // Restore previous current context, if any. Otherwise, make uncurrent if (prevContext != null) prevContext.MakeCurrent(prevContextDevice, true); else MakeCurrent(deviceContext, false); } catch { // Rethrow the exception throw; } }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting managed/unmanaged resources. /// </summary> /// <param name="disposing"> /// </param> /// <remarks> /// This method shall be called by the same thread which has created this GraphicsContext, but only in the case the following /// constructors were called: /// - @ref GraphicsContext::GraphicsContext() /// </remarks> /// <exception cref="InvalidOperationException"> /// Exception throw if this GraphicsContext has not been disposed before finalization. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception throw if it's not possible to release correctly the OpenGL context related to this GraphicsContext. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception throw if the current thread is not the one which has constructed this GraphicsContext. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception throw if it's not possible to release correctly the GDI device context related to this GraphicsContext. /// </exception> private void Dispose(bool disposing) { if (disposing == true) { // Dispose resources if (_DrawArrayBuffer != null) _DrawArrayBuffer.Dispose(this); if (_VertexArray != null) _VertexArray.Dispose(this); if (_ShaderIncludeLibrary != null) { _ShaderIncludeLibrary.Dispose(this); _ShaderIncludeLibrary = null; } // Dispose unmanaged resources if (_RenderContext != IntPtr.Zero) { if (_DeviceContext.DeleteContext(_RenderContext) == false) throw new InvalidOperationException("unable to release OpenGL context"); _RenderContext = IntPtr.Zero; } if (_DeviceContextThreadId != System.Threading.Thread.CurrentThread.ManagedThreadId) throw new InvalidOperationException("disposing on a different thread context"); _DeviceContext.DecRef(); _DeviceContext = null; // Remove context from the current ones int threadId = 0; bool threadCurrentFound = false; lock (_RenderThreadsLock) { foreach (KeyValuePair<int, GraphicsContext> pair in _RenderThreads) { if (ReferenceEquals(pair.Value, this) == true) { threadId = pair.Key; threadCurrentFound = true; break; } } } if (threadCurrentFound == true) _RenderThreads[threadId] = null; } }
private static List<string> Process(ShaderIncludeLibrary includeLibrary, ShaderCompilerContext cctx, IncludeProcessorContext ictx, IEnumerable<string> shaderSource) { if (includeLibrary == null) throw new ArgumentNullException("includeLibrary"); if (cctx == null) throw new ArgumentNullException("cctx"); if (shaderSource == null) throw new ArgumentNullException("sSource"); List<string> processedSource = new List<string>(); // Shader includes not supported. Process them manually before submitting shader source text lines. foreach (string line in shaderSource) { // Ignore null items if (line == null) continue; if ((_RegexInclude.Match(line)).Success) { ShaderInclude shaderInclude = null; string includePath = ExtractIncludePath(line); string canonicalPath = String.Empty; if (includePath.StartsWith("/") == false) { // If <path> does not start with a forward slash, it is a path relative // to one of the ordered list of initial search points. if ((ictx.CurrentPath != String.Empty) && (_RegexIncludeAngular.Match(line).Success == false)) { // If it is quoted with double quotes in a previously included string, then the first // search point will be the tree location where the previously included // string had been found. If not found there, the search continues at // the beginning of the list of search points, as just described (see comment later). canonicalPath = NormalizeIncludePath(Path.Combine(ictx.CurrentPath, includePath)); if (includeLibrary.IsPathDefined(canonicalPath)) shaderInclude = includeLibrary.GetInclude(canonicalPath); } // If this path is quoted with angled brackets, the tree is searched relative to the // first search point in the ordered list, and then relative to each // subsequent search point, in order, until a matching path is found in // the tree. This is also the behavior if it is quoted with double // quotes in an initial (non-included) shader string. if (shaderInclude == null) { foreach (string includeSearchPath in cctx.Includes) { canonicalPath = NormalizeIncludePath(Path.Combine(includeSearchPath, includePath)); if (includeLibrary.IsPathDefined(canonicalPath)) { shaderInclude = includeLibrary.GetInclude(canonicalPath); break; } } } } else { // If <path> starts with a forward slash, whether it is quoted with // double quotes or with angled brackets, the list of search points is // ignored and <path> is looked up in the tree as described in Appendix // A. canonicalPath = includePath; if (includeLibrary.IsPathDefined(canonicalPath) == false) throw new InvalidOperationException(String.Format("absolute include path \"{0}\" not existing", canonicalPath)); shaderInclude = includeLibrary.GetInclude(canonicalPath); } if (shaderInclude == null) throw new InvalidOperationException(String.Format("include path '{0}' not found", includePath)); // Recurse on included source (it may contain other includes) IncludeProcessorContext ictxRecurse = new IncludeProcessorContext(); System.Diagnostics.Debug.Assert(String.IsNullOrEmpty(canonicalPath) == false); ictxRecurse.CurrentPath = canonicalPath; processedSource.AddRange(Process(includeLibrary, cctx, ictxRecurse, shaderInclude.Source)); } else processedSource.Add(line); } return (processedSource); }
private static List <string> Process(ShaderIncludeLibrary includeLibrary, ShaderCompilerContext cctx, IncludeProcessorContext ictx, IEnumerable <string> shaderSource) { if (includeLibrary == null) { throw new ArgumentNullException("includeLibrary"); } if (cctx == null) { throw new ArgumentNullException("cctx"); } if (shaderSource == null) { throw new ArgumentNullException("sSource"); } List <string> processedSource = new List <string>(); // Shader includes not supported. Process them manually before submitting shader source text lines. foreach (string line in shaderSource) { // Ignore null items if (line == null) { continue; } if ((_RegexInclude.Match(line)).Success) { ShaderInclude shaderInclude = null; string includePath = ExtractIncludePath(line); string canonicalPath = String.Empty; if (includePath.StartsWith("/") == false) { // If <path> does not start with a forward slash, it is a path relative // to one of the ordered list of initial search points. if ((ictx.CurrentPath != String.Empty) && (_RegexIncludeAngular.Match(line).Success == false)) { // If it is quoted with double quotes in a previously included string, then the first // search point will be the tree location where the previously included // string had been found. If not found there, the search continues at // the beginning of the list of search points, as just described (see comment later). canonicalPath = NormalizeIncludePath(Path.Combine(ictx.CurrentPath, includePath)); if (includeLibrary.IsPathDefined(canonicalPath)) { shaderInclude = includeLibrary.GetInclude(canonicalPath); } } // If this path is quoted with angled brackets, the tree is searched relative to the // first search point in the ordered list, and then relative to each // subsequent search point, in order, until a matching path is found in // the tree. This is also the behavior if it is quoted with double // quotes in an initial (non-included) shader string. if (shaderInclude == null) { foreach (string includeSearchPath in cctx.Includes) { canonicalPath = NormalizeIncludePath(Path.Combine(includeSearchPath, includePath)); if (includeLibrary.IsPathDefined(canonicalPath)) { shaderInclude = includeLibrary.GetInclude(canonicalPath); break; } } } } else { // If <path> starts with a forward slash, whether it is quoted with // double quotes or with angled brackets, the list of search points is // ignored and <path> is looked up in the tree as described in Appendix // A. canonicalPath = includePath; if (includeLibrary.IsPathDefined(canonicalPath) == false) { throw new InvalidOperationException(String.Format("absolute include path \"{0}\" not existing", canonicalPath)); } shaderInclude = includeLibrary.GetInclude(canonicalPath); } if (shaderInclude == null) { throw new InvalidOperationException(String.Format("include path '{0}' not found", includePath)); } // Recurse on included source (it may contain other includes) IncludeProcessorContext ictxRecurse = new IncludeProcessorContext(); System.Diagnostics.Debug.Assert(String.IsNullOrEmpty(canonicalPath) == false); ictxRecurse.CurrentPath = canonicalPath; processedSource.AddRange(Process(includeLibrary, cctx, ictxRecurse, shaderInclude.Source)); } else { processedSource.Add(line); } } return(processedSource); }