Esempio n. 1
0
        /// <summary>
        /// Get uniform value (vec3 variable or bvec3 variable).
        /// </summary>
        /// <param name="ctx">
        /// A <see cref="GraphicsContext"/> used for operations.
        /// </param>
        /// <param name="uniformName">
        /// A <see cref="String"/> that specify the variable name in the shader source.
        /// </param>
        /// <param name="x">
        /// A <see cref="Single"/> holding the returned uniform variabile data (first component).
        /// </param>
        /// <param name="y">
        /// A <see cref="Single"/> holding the returned uniform variabile data (second component).
        /// </param>
        /// <param name="z">
        /// A <see cref="Single"/> holding the returned uniform variabile data (third component).
        /// </param>
        public void GetUniform(GraphicsContext ctx, string uniformName, out float x, out float y, out float z)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            UniformBinding uniform = GetUniform(ctx, uniformName);

            if (uniform == null || uniform.Location == -1)
            {
                throw new InvalidOperationException(String.Format("uniform {0} is not active", uniformName));
            }

            CheckUniformType(uniform, Gl.FLOAT_VEC3, Gl.BOOL_VEC3);

            float[] value = new float[4];

            // Set uniform value
            Gl.GetUniform(ObjectName, uniform.Location, value);

            x = value[0];
            y = value[1];
            z = value[2];
        }
Esempio n. 2
0
        /// <summary>
        /// Get uniform value (ivec4 variable or bvec4 variable).
        /// </summary>
        /// <param name="ctx">
        /// A <see cref="GraphicsContext"/> used for operations.
        /// </param>
        /// <param name="uniformName">
        /// A <see cref="String"/> that specify the variable name in the shader source.
        /// </param>
        /// <param name="x">
        /// A <see cref="Int32"/> holding the returned uniform variabile data (first component).
        /// </param>
        /// <param name="y">
        /// A <see cref="Int32"/> holding the returned uniform variabile data (second component).
        /// </param>
        /// <param name="z">
        /// A <see cref="Int32"/> holding the returned uniform variabile data (third component).
        /// </param>
        /// <param name="w">
        /// A <see cref="Int32"/> holding the returned uniform variabile data (fourth component).
        /// </param>
        public void GetUniform(GraphicsContext ctx, string uniformName, out int x, out int y, out int z, out int w)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            UniformBinding uniform = GetUniform(ctx, uniformName);

            if (uniform == null || uniform.Location == -1)
            {
                throw new InvalidOperationException(String.Format("uniform {0} is not active", uniformName));
            }

            CheckUniformType(uniform, Gl.INT_VEC4, Gl.BOOL_VEC4);

            int[] value = new int[4];

            // Get uniform value (using int variant)
            Gl.GetUniform(ObjectName, uniform.Location, value);

            x = value[0];
            y = value[1];
            z = value[2];
            w = value[3];
        }
        /// <summary>
        /// Get uniform value (dvec4 variable).
        /// </summary>
        /// <param name="ctx">
        /// A <see cref="GraphicsContext"/> used for operations.
        /// </param>
        /// <param name="uniformName">
        /// A <see cref="String"/> that specify the variable name in the shader source.
        /// </param>
        /// <param name="x">
        /// A <see cref="Double"/> holding the returned uniform variabile data (first component).
        /// </param>
        /// <param name="y">
        /// A <see cref="Double"/> holding the returned uniform variabile data (second component).
        /// </param>
        /// <param name="z">
        /// A <see cref="Double"/> holding the returned uniform variabile data (third component).
        /// </param>
        /// <param name="w">
        /// A <see cref="Double"/> holding the returned uniform variabile data (fourth component).
        /// </param>
        public void GetUniform(GraphicsContext ctx, string uniformName, out double x, out double y, out double z, out double w)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            UniformBinding uniform = GetUniform(ctx, uniformName);

            if (uniform == null || uniform.Location == -1)
            {
                throw new InvalidOperationException(String.Format("uniform {0} is not active", uniformName));
            }

            CheckUniformType(uniform, Gl.DOUBLE_VEC4);

            double[] value = new double[4];

            // Set uniform value
            Gl.GetUniform(ObjectName, uniform.Location, value);

            x = value[0];
            y = value[1];
            z = value[2];
            w = value[3];
        }
Esempio n. 4
0
 public DebugLinesMaterial(ITagContainer diContainer) : base(diContainer.GetTag <GraphicsDevice>(), GetPipeline(diContainer))
 {
     Configure()
     .Add(Projection = new UniformBinding <Matrix4x4>(this))
     .Add(View       = new UniformBinding <Matrix4x4>(this))
     .Add(World      = new UniformBinding <Matrix4x4>(this))
     .NextBindingSet();
 }
Esempio n. 5
0
 public UIMaterial(ITagContainer diContainer, bool isFont) : base(diContainer.GetTag <GraphicsDevice>(), GetPipeline(diContainer, isFont))
 {
     Configure()
     .Add(Texture    = new TextureBinding(this))
     .Add(Sampler    = new SamplerBinding(this))
     .Add(ScreenSize = new UniformBinding <Vector2>(this))
     .NextBindingSet();
 }
Esempio n. 6
0
 public MapUntexturedMaterial(ITagContainer diContainer) : base(diContainer.GetTag <GraphicsDevice>(), GetPipeline(diContainer))
 {
     Configure()
     .Add(Projection   = new UniformBinding <Matrix4x4>(this))
     .Add(View         = new UniformBinding <Matrix4x4>(this))
     .Add(World        = new UniformBinding <Matrix4x4>(this))
     .Add(Uniforms     = new UniformBinding <ModelStandardMaterialUniforms>(this))
     .Add(PixelCounter = new UniformBinding <uint>(this))
     .NextBindingSet();
 }
Esempio n. 7
0
 public DebugIconMaterial(ITagContainer diContainer) : base(diContainer.GetTag <GraphicsDevice>(), GetPipeline(diContainer))
 {
     Configure()
     .Add(Texture    = new TextureBinding(this))
     .Add(Sampler    = new SamplerBinding(this))
     .Add(Projection = new UniformBinding <Matrix4x4>(this))
     .Add(View       = new UniformBinding <Matrix4x4>(this))
     .Add(World      = new UniformBinding <Matrix4x4>(this))
     .Add(Uniforms   = new UniformBinding <DebugIconUniforms>(this))
     .NextBindingSet();
 }
Esempio n. 8
0
 public ModelSkinnedMaterial(ITagContainer diContainer) : base(diContainer.GetTag <GraphicsDevice>(), GetPipeline(diContainer))
 {
     Configure()
     .Add(MainTexture = new TextureBinding(this))
     .Add(Sampler     = new SamplerBinding(this))
     .Add(Projection  = new UniformBinding <Matrix4x4>(this))
     .Add(View        = new UniformBinding <Matrix4x4>(this))
     .Add(World       = new UniformBinding <Matrix4x4>(this))
     .Add(Uniforms    = new UniformBinding <ModelStandardMaterialUniforms>(this))
     .Add(Pose        = new SkeletonPoseBinding(this))
     .NextBindingSet();
 }
        /// <summary>
        /// Set uniform state variable (variant type).
        /// </summary>
        /// <param name="ctx">
        /// A <see cref="GraphicsContext"/> used for operations.
        /// </param>
        /// <param name="uniformName">
        /// A <see cref="String"/> that specify the variable name in the shader source.
        /// </param>
        /// <param name="m">
        /// A <see cref="IMatrix4x4"/> holding the uniform variabile data.
        /// </param>
        public void SetVariantUniform(GraphicsContext ctx, string uniformName, IMatrix4x4 m)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            UniformBinding uniform = GetUniform(uniformName);

            switch (uniform.UniformType)
            {
            case ShaderUniformType.Mat4x4:
                SetUniform(ctx, uniformName, (Matrix4x4)m);
                break;

            case ShaderUniformType.DoubleMat4x4:
                SetUniform(ctx, uniformName, (MatrixDouble4x4)m);
                break;

            default:
                throw new ShaderException("unable to set double-precision floating-point matrix 4x4 data to uniform of type {0}", uniform.UniformType);
            }
        }
        /// <summary>
        /// Get uniform value (boolean variable).
        /// </summary>
        /// <param name="ctx">
        /// A <see cref="GraphicsContext"/> used for operations.
        /// </param>
        /// <param name="uniformName">
        /// A <see cref="String"/> that specify the variable name in the shader source.
        /// </param>
        /// <param name="v">
        /// A <see cref="Boolean"/> holding the returned uniform variabile data.
        /// </param>
        public void GetUniform(GraphicsContext ctx, string uniformName, out bool v)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            UniformBinding uniform = GetUniform(ctx, uniformName);

            if (uniform == null || uniform.Location == -1)
            {
                throw new InvalidOperationException(String.Format("uniform {0} is not active", uniformName));
            }

            CheckUniformType(uniform, Gl.BOOL);

            int[] value = new int[1];

            // Get uniform value (using int variant)
            Gl.GetUniform(ObjectName, uniform.Location, value);

            v = value[0] != 0;
        }
        /// <summary>
        /// Set uniform state variable (variant type).
        /// </summary>
        /// <param name="ctx">
        /// A <see cref="GraphicsContext"/> used for operations.
        /// </param>
        /// <param name="uniformName">
        /// A <see cref="String"/> that specify the variable name in the shader source.
        /// </param>
        /// <param name="m">
        /// A <see cref="Matrix3x3"/> holding the uniform variabile data.
        /// </param>
        public void SetVariantUniform(GraphicsContext ctx, string uniformName, Matrix3x3d m)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            UniformBinding uniform = GetUniform(ctx, uniformName);

            switch (uniform.UniformType)
            {
            case ShaderUniformType.Mat3x3:
                SetUniform(ctx, uniformName, (Matrix3x3f)m);
                break;

#if !MONODROID
            case ShaderUniformType.DoubleMat3x3:
                SetUniform(ctx, uniformName, m);
                break;
#endif
            default:
                throw new ShaderException("unable to set double-precision floating-point matrix 3x3 data to uniform of type {0}", uniform.UniformType);
            }
        }
        /// <summary>
        /// Set uniform variable from double-precision floating-point data (variant type).
        /// </summary>
        /// <param name="ctx">
        /// A <see cref="GraphicsContext"/> used for operations.
        /// </param>
        /// <param name="uniformName">
        /// A <see cref="String"/> that specify the variable name in the shader source.
        /// </param>
        /// <param name="x">
        /// A <see cref="Double"/> holding the uniform variabile data (first component).
        /// </param>
        /// <param name="y">
        /// A <see cref="Double"/> holding the uniform variabile data (second component).
        /// </param>
        /// <param name="z">
        /// A <see cref="Double"/> holding the uniform variabile data (third component).
        /// </param>
        /// <param name="w">
        /// A <see cref="Double"/> holding the uniform variabile data (fourth component).
        /// </param>
        /// <remarks>
        /// <para>
        /// The uniform variable type could be one of the following :
        /// - float, vec2, vec3, vec4
        /// - double, dvec2, dvec3, dvec4
        /// - int, ivec2, ivec3, ivec4
        /// - uint, uvec2, uvec3, uvec4
        /// </para>
        /// <para>
        /// In the case the uniofmr variable length is less than 4, the higher components specified as
        /// arguments are ignored. The single-precision floating-point data is converted accordingly
        /// to the uniform variable type.
        /// </para>
        /// </remarks>
        public void SetVariantUniform(GraphicsContext ctx, string uniformName, double x, double y, double z, double w)
        {
            if (ctx == null)
            {
                throw new ArgumentNullException("ctx");
            }

            UniformBinding uniform = GetUniform(ctx, uniformName);

            switch (uniform.UniformType)
            {
            case ShaderUniformType.Float:
                SetUniform(ctx, uniformName, (float)x);
                break;

            case ShaderUniformType.Vec2:
                SetUniform(ctx, uniformName, (float)x, (float)y);
                break;

            case ShaderUniformType.Vec3:
                SetUniform(ctx, uniformName, (float)x, (float)y, (float)z);
                break;

            case ShaderUniformType.Vec4:
                SetUniform(ctx, uniformName, (float)x, (float)y, (float)z, (float)w);
                break;

#if !MONODROID
            case ShaderUniformType.Double:
                SetUniform(ctx, uniformName, x);
                break;

            case ShaderUniformType.DoubleVec2:
                SetUniform(ctx, uniformName, x, y);
                break;

            case ShaderUniformType.DoubleVec3:
                SetUniform(ctx, uniformName, x, y, z);
                break;

            case ShaderUniformType.DoubleVec4:
                SetUniform(ctx, uniformName, x, y, z, w);
                break;
#endif
            case ShaderUniformType.Int:
                SetUniform(ctx, uniformName, (int)x);
                break;

            case ShaderUniformType.IntVec2:
                SetUniform(ctx, uniformName, (int)x, (int)y);
                break;

            case ShaderUniformType.IntVec3:
                SetUniform(ctx, uniformName, (int)x, (int)y, (int)z);
                break;

            case ShaderUniformType.IntVec4:
                SetUniform(ctx, uniformName, (int)x, (int)y, (int)z);
                break;

            case ShaderUniformType.UInt:
                SetUniform(ctx, uniformName, (uint)x);
                break;

            case ShaderUniformType.UIntVec2:
                SetUniform(ctx, uniformName, (uint)x, (uint)y);
                break;

            case ShaderUniformType.UIntVec3:
                SetUniform(ctx, uniformName, (uint)x, (uint)y, (uint)z);
                break;

            case ShaderUniformType.UIntVec4:
                SetUniform(ctx, uniformName, (uint)x, (uint)y, (uint)z);
                break;

            default:
                throw new ShaderException("unable to set double-precision floating-point data to uniform os type {0}", uniform.UniformType);
            }
        }
Esempio n. 13
0
        /// <summary>
        /// Link this ShaderProgram.
        /// </summary>
        /// <param name="ctx">
        /// A <see cref="GraphicsContext"/> used for linking this ShaderProgram.
        /// </param>
        /// <param name="cctx">
        /// A <see cref="ShaderCompilerContext"/> that specify additional compiler parameters.
        /// </param>
        /// <remarks>
        /// <para>
        /// Generate shader program source code, compile and link it. After a successfull
        /// link, obtain every information about active uniform and input variables.
        /// </para>
        /// <para>
        /// This routine generate the source code of each attached ShaderObject instance and
        /// compile it. This step is performed only if really required (tendentially every
        /// shader object is already compiled).
        /// </para>
        /// <para>
        /// After having compiled every attached shader object, it's performed the linkage between
        /// shader objects. After this process the ShaderProgram instance can be bound to issue
        /// rendering commands.
        /// </para>
        /// </remarks>
        /// <exception cref="InvalidOperationException">
        /// Exception thrown in the case this ShaderProgram is already linked.
        /// </exception>
        /// <exception cref="ShaderException">
        /// Exception throw in the case this ShaderProgram is not linkable.
        /// </exception>
        private void Link(GraphicsContext ctx, ShaderCompilerContext cctx)
        {
            CheckCurrentContext(ctx);

            if (cctx == null)
            {
                throw new ArgumentNullException("cctx");
            }

            // Using a deep copy of the shader compiler context, since it will be modified by this ShaderProgram
            // instance and the attached ShaderObject instances
            cctx = new ShaderCompilerContext(cctx);

            #region Compile and Attach Shader Objects

            // Be sure to take every attached shader
            uint[] shadersObject = null;
            int    shadersCount;

            Gl.GetProgram(ObjectName, Gl.ATTACHED_SHADERS, out shadersCount);

            if (shadersCount > 0)
            {
                shadersObject = new uint[shadersCount];
                Gl.GetAttachedShaders(ObjectName, out shadersCount, shadersObject);
                Debug.Assert(shadersCount == shadersObject.Length);
            }

            foreach (ShaderObject shaderObject in _ProgramObjects)
            {
                // Create shader object, if necessary
                if (shaderObject.Exists(ctx) == false)
                {
                    shaderObject.Create(ctx, cctx);
                }

                // Do not re-attach the same shader object
                if ((shadersObject != null) && Array.Exists(shadersObject, delegate(uint item) { return(item == shaderObject.ObjectName); }))
                {
                    continue;
                }

                // Attach shader object
                Gl.AttachShader(ObjectName, shaderObject.ObjectName);
            }

            #endregion

            #region Transform Feedback Definition

            IntPtr[] feedbackVaryingsPtrs = null;

            if ((_FeedbackVaryings != null) && (_FeedbackVaryings.Count > 0))
            {
                sLog.Debug("Feedback varyings ({0}):", cctx.FeedbackVaryingsFormat);
                sLog.Indent();
                foreach (string feedbackVarying in _FeedbackVaryings)
                {
                    sLog.Debug("- {0}", feedbackVarying);
                }
                sLog.Unindent();

                if (ctx.Caps.GlExtensions.TransformFeedback2_ARB || ctx.Caps.GlExtensions.TransformFeedback_EXT)
                {
                    string[] feedbackVaryings = _FeedbackVaryings.ToArray();

                    // Bug in NVIDIA drivers? Not exactly, but the NVIDIA driver hold the 'feedbackVaryings' pointer until
                    // glLinkProgram is executed, causing linker errors like 'duplicate varying names are not allowed' or garbaging
                    // part of the returned strings via glGetTransformFeedbackVarying
                    feedbackVaryingsPtrs = feedbackVaryings.AllocHGlobal();

                    // Specify feedback varyings
                    Gl.TransformFeedbackVaryings(ObjectName, feedbackVaryingsPtrs, (int)cctx.FeedbackVaryingsFormat);
                }
                else if (ctx.Caps.GlExtensions.TransformFeedback2_NV)
                {
                    // Nothing to do ATM
                }
                else
                {
                    throw new InvalidOperationException("transform feedback not supported");
                }
            }

            #endregion

            #region Bind Fragment Locations

            if (ctx.Caps.GlExtensions.GpuShader4_EXT)
            {
                // Setup fragment locations, where defined
                foreach (KeyValuePair <string, int> pair in _FragLocations)
                {
                    if (pair.Value >= 0)
                    {
                        Gl.BindFragDataLocation(ObjectName, (uint)pair.Value, pair.Key);
                    }
                }
            }

            #endregion

            #region Link Shader Program Objects

            int lStatus;

            sLog.Debug("Link shader program {0}", Identifier ?? "<Unnamed>");

            // Link shader program
            Gl.LinkProgram(ObjectName);
            // Check for linking errors
            Gl.GetProgram(ObjectName, Gl.LINK_STATUS, out lStatus);

            // Release feedback varyings unmanaged memory
            if (feedbackVaryingsPtrs != null)
            {
                feedbackVaryingsPtrs.FreeHGlobal();
            }

            if (lStatus != Gl.TRUE)
            {
                const int MaxInfoLength = 4096;

                StringBuilder logInfo = new StringBuilder(MaxInfoLength);
                int           logLength;

                // Obtain compilation log
                Gl.GetProgramInfoLog(ObjectName, MaxInfoLength, out logLength, logInfo);

                // Stop link process
                StringBuilder sb = new StringBuilder(logInfo.Capacity);

                string[] compilerLogLines = logInfo.ToString().Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string logLine in compilerLogLines)
                {
                    sb.AppendLine("  $ " + logLine);
                }

                sLog.Error("Shader program \"{0}\" linkage failed: {1}", Identifier ?? "<Unnamed>", sb.ToString());

                throw new ShaderException("shader program is not valid. Linker output for {0}: {1}\n", Identifier ?? "<Unnamed>", sb.ToString());
            }
            // Set linked flag
            _Linked = true;

            #endregion

            #region Collect Active Program Uniforms

            int uniformBufferSize, attributeBufferSize;
            int uniformCount;

            // Get active uniforms count
            Gl.GetProgram(ObjectName, Gl.ACTIVE_UNIFORMS, out uniformCount);
            // Get uniforms maximum length for name
            Gl.GetProgram(ObjectName, Gl.ACTIVE_UNIFORM_MAX_LENGTH, out uniformBufferSize);

            // Clear uniform mapping
            _UniformMap.Clear();
            _DefaultBlockUniformSlots = 0;

            // Collect uniform information
            for (uint i = 0; i < (uint)uniformCount; i++)
            {
                int uniformNameLength, uniformSize, uniformType;

                // Mono optimize StringBuilder capacity after P/Invoke... ensure enought room
                StringBuilder uNameBuilder = new StringBuilder(uniformBufferSize + 2);
                uNameBuilder.EnsureCapacity(uniformBufferSize);

                // Obtain active uniform informations
                Gl.GetActiveUniform(ObjectName, i, uniformBufferSize, out uniformNameLength, out uniformSize, out uniformType, uNameBuilder);

                string uniformName = uNameBuilder.ToString();

                // Obtain active uniform location
                int uLocation = Gl.GetUniformLocation(ObjectName, uniformName);

                UniformBinding uniformBinding = new UniformBinding(uniformName, i, uLocation, (ShaderUniformType)uniformType);

                // Map active uniform
                _UniformMap[uniformName] = uniformBinding;
                // Keep track of used slot
                _DefaultBlockUniformSlots += GetUniformSlotCount(uniformBinding.UniformType);
            }

            // Log uniform location mapping
            List <string> uniformNames = new List <string>(_UniformMap.Keys);

            // Make uniform list invariant respect the used driver (ease log comparation)
            uniformNames.Sort();

            sLog.Debug("Shader program active uniforms:");
            foreach (string uniformName in uniformNames)
            {
                sLog.Debug("\tUniform {0} (Type: {1}, Location: {2})", uniformName, _UniformMap[uniformName].UniformType, _UniformMap[uniformName].Location);
            }

            sLog.Debug("Shader program active uniform slots: {0}", _DefaultBlockUniformSlots);

            #endregion

            #region Collect Active Program Inputs

            // Get active inputs count
            int activeInputs;

            Gl.GetProgram(ObjectName, Gl.ACTIVE_ATTRIBUTES, out activeInputs);
            // Get inputs maximum length for name
            Gl.GetProgram(ObjectName, Gl.ACTIVE_ATTRIBUTE_MAX_LENGTH, out attributeBufferSize);

            // Clear input mapping
            _AttributesMap.Clear();

            // Collect input location mapping
            for (uint i = 0; i < (uint)activeInputs; i++)
            {
                StringBuilder nameBuffer = new StringBuilder(attributeBufferSize);
                int           nameLength, size, type;

                // Mono optimize StringBuilder capacity after P/Invoke... ensure enought room for the current loop
                nameBuffer.EnsureCapacity(attributeBufferSize);

                // Obtain active input informations
                Gl.GetActiveAttrib(ObjectName, i, attributeBufferSize, out nameLength, out size, out type, nameBuffer);
                // Obtain active input location
                string name = nameBuffer.ToString();

                int location = Gl.GetAttribLocation(ObjectName, name);
                // Map active input
                _AttributesMap[name] = new AttributeBinding((uint)location, (ShaderAttributeType)type);
            }

            // Log attribute mapping
            List <string> attributeNames = new List <string>(_AttributesMap.Keys);

            // Make attribute list invariant respect the used driver (ease log comparation)
            attributeNames.Sort();

            sLog.Debug("Shader program active attributes:");
            foreach (string attributeName in attributeNames)
            {
                sLog.Debug("\tAttribute {0} (Type: {1}, Location: {2})", attributeName, _AttributesMap[attributeName].Type, _AttributesMap[attributeName].Location);
            }

            #endregion

            #region Collect Fragment Locations

            if (ctx.Caps.GlExtensions.GpuShader4_EXT)
            {
                // Get fragment locations, just in the case automatically assigned
                foreach (string fragOutputName in new List <string>(_FragLocations.Keys))
                {
                    _FragLocations[fragOutputName] = Gl.GetFragDataLocation(ObjectName, fragOutputName);
                }
            }

            #endregion

            #region Collect Feedback Varyings

            if ((_FeedbackVaryings != null) && (_FeedbackVaryings.Count > 0))
            {
                if (ctx.Caps.GlExtensions.TransformFeedback2_ARB || ctx.Caps.GlExtensions.TransformFeedback_EXT)
                {
                    // Map active feedback
                    int feebackVaryings, feebackVaryingsMaxLength;

                    Gl.GetProgram(ObjectName, Gl.TRANSFORM_FEEDBACK_VARYINGS, out feebackVaryings);
                    Gl.GetProgram(ObjectName, Gl.TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, out feebackVaryingsMaxLength);

                    for (uint i = 0; i < feebackVaryings; i++)
                    {
                        StringBuilder sb = new StringBuilder(feebackVaryingsMaxLength);
                        int           length = 0, size = 0, type = 0;

                        Gl.GetTransformFeedbackVarying(ObjectName, (uint)i, feebackVaryingsMaxLength, out length, out size, out type, sb);
                        _FeedbacksMap.Add(sb.ToString(), new FeedbackBinding((ShaderAttributeType)type, (uint)size));
                    }
                }
                else if (ctx.Caps.GlExtensions.TransformFeedback2_NV)
                {
                    // Activate varyings
                    foreach (string feedbackVaryingName in _FeedbackVaryings)
                    {
                        Gl.ActiveVaryingNV(ObjectName, feedbackVaryingName);
                    }

                    // Map active feedback
                    int feebackVaryings, feebackVaryingsMaxLength;

                    Gl.GetProgram(ObjectName, Gl.ACTIVE_VARYINGS_NV, out feebackVaryings);
                    Gl.GetProgram(ObjectName, Gl.ACTIVE_VARYING_MAX_LENGTH_NV, out feebackVaryingsMaxLength);

                    for (uint i = 0; i < feebackVaryings; i++)
                    {
                        StringBuilder sb = new StringBuilder(feebackVaryingsMaxLength * 2);
                        int           length = 0, size = 0, type = 0;

                        Gl.GetActiveVaryingNV(ObjectName, (uint)i, feebackVaryingsMaxLength * 2, out length, out size, out type, sb);

                        _FeedbacksMap.Add(sb.ToString(), new FeedbackBinding((ShaderAttributeType)type, (uint)size));
                    }

                    // Specify feedback varyings
                    List <int> feedbackLocations = new List <int>();

                    foreach (string feedbackVaryingName in _FeedbackVaryings)
                    {
                        int location = Gl.GetVaryingLocationNV(ObjectName, feedbackVaryingName);

                        if (location >= 0)
                        {
                            feedbackLocations.Add(location);
                        }
                    }

                    Gl.TransformFeedbackVaryingsNV(ObjectName, feedbackLocations.ToArray(), (int)cctx.FeedbackVaryingsFormat);

                    // Map active feedback
                }

                Debug.Assert(_FeedbacksMap.Count > 0);

                // Log feedback mapping
                sLog.Debug("Shader program active feedbacks:");
                foreach (string feedbackName in _FeedbacksMap.Keys)
                {
                    sLog.Debug("\tFeedback {0} (Type: {1})", feedbackName, _FeedbacksMap[feedbackName].Type);
                }
            }

            #endregion
        }
Esempio n. 14
0
 public GlobalBindingPair(UniformBinding binding, ConstantBufferDataProvider dataProvider)
 {
     Binding      = binding;
     DataProvider = dataProvider;
 }
Esempio n. 15
0
		/// <summary>
		/// Link this ShaderProgram.
		/// </summary>
		/// <param name="ctx">
		/// A <see cref="GraphicsContext"/> used for linking this ShaderProgram.
		/// </param>
		/// <param name="cctx">
		/// A <see cref="ShaderCompilerContext"/> that specify additional compiler parameters.
		/// </param>
		/// <remarks>
		/// <para>
		/// Generate shader program source code, compile and link it. After a successfull
		/// link, obtain every information about active uniform and input variables.
		/// </para>
		/// <para>
		/// This routine generate the source code of each attached ShaderObject instance and
		/// compile it. This step is performed only if really required (tendentially every
		/// shader object is already compiled).
		/// </para>
		/// <para>
		/// After having compiled every attached shader object, it's performed the linkage between
		/// shader objects. After this process the ShaderProgram instance can be bound to issue
		/// rendering commands.
		/// </para>
		/// </remarks>
		/// <exception cref="InvalidOperationException">
		/// Exception thrown in the case this ShaderProgram is already linked.
		/// </exception>
		/// <exception cref="ShaderException">
		/// Exception throw in the case this ShaderProgram is not linkable.
		/// </exception>
		private void Link(GraphicsContext ctx, ShaderCompilerContext cctx)
		{
			if (ctx == null)
				throw new ArgumentNullException("ctx");
			if (cctx == null)
				throw new ArgumentNullException("cctx");
			
			// Using a deep copy of the shader compiler context, since it will be modified by this ShaderProgram
			// instance and the attached ShaderObject instances
			cctx = new ShaderCompilerContext(cctx);
			
			#region Compile and Attach Shader Objects
			
			// Ensure cached shader objects
			foreach (ShaderObject shaderObject in _ProgramObjects) {
				// Create shader object, if necessary
				if (shaderObject.Exists(ctx) == false)
					shaderObject.Create(ctx, cctx);
				// Attach shader object
				Gl.AttachShader(ObjectName, shaderObject.ObjectName);
			}

			#endregion

			#region Transform Feedback Definition

			IntPtr[] feedbackVaryingsPtrs = null;

			if ((_FeedbackVaryings != null) && (_FeedbackVaryings.Count > 0)) {
				sLog.Debug("Feedback varyings ({0}):", cctx.FeedbackVaryingsFormat);
				sLog.Indent();
				foreach (string feedbackVarying in _FeedbackVaryings)
					sLog.Debug("- {0}", feedbackVarying);
				sLog.Unindent();

				if (ctx.Caps.GlExtensions.TransformFeedback2_ARB || ctx.Caps.GlExtensions.TransformFeedback_EXT) {
					string[] feedbackVaryings = _FeedbackVaryings.ToArray();

					// Bug in NVIDIA drivers? Not exactly, but the NVIDIA driver hold the 'feedbackVaryings' pointer untill
					// glLinkProgram is executed, causing linker errors like 'duplicate varying names are not allowed' or garbaging
					// part of the returned strings via glGetTransformFeedbackVarying
					feedbackVaryingsPtrs = feedbackVaryings.AllocHGlobal();

					// Specify feedback varyings
					Gl.TransformFeedbackVaryings(ObjectName, feedbackVaryingsPtrs, (int)cctx.FeedbackVaryingsFormat);
				} else if (ctx.Caps.GlExtensions.TransformFeedback2_NV) {
					// Nothing to do ATM
				} else
					throw new InvalidOperationException("transform feedback not supported");
			}

			#endregion

			#region Bind Fragment Locations

			if (ctx.Caps.GlExtensions.GpuShader4_EXT) {
				// Setup fragment locations, where defined
				foreach (KeyValuePair<string, int> pair in _FragLocations) {
					if (pair.Value >= 0)
						Gl.BindFragDataLocation(ObjectName, (uint) pair.Value, pair.Key);
				}
			}

			#endregion

			#region Link Shader Program Objects

			int lStatus;

			sLog.Debug("Link shader program {0}", Identifier ?? "<Unnamed>");

			// Link shader program
			Gl.LinkProgram(ObjectName);
			// Check for linking errors
			Gl.GetProgram(ObjectName, Gl.LINK_STATUS, out lStatus);

			// Release feedback varyings unmanaged memory
			if (feedbackVaryingsPtrs != null)
				feedbackVaryingsPtrs.FreeHGlobal();

			if (lStatus != Gl.TRUE) {
				const int MaxInfoLength = 4096;

				StringBuilder logInfo = new StringBuilder(MaxInfoLength);
				int logLength;

				// Obtain compilation log
				Gl.GetProgramInfoLog(ObjectName, MaxInfoLength, out logLength, logInfo);

				// Stop link process
				StringBuilder sb = new StringBuilder(logInfo.Capacity);

				string[] compilerLogLines = logInfo.ToString().Split(new char[] {'\n'}, StringSplitOptions.RemoveEmptyEntries);
				foreach (string logLine in compilerLogLines)
					sb.AppendLine("  $ " + logLine);

				sLog.Error("Shader program \"{0}\" linkage failed: {1}", Identifier ?? "<Unnamed>", sb.ToString());

				throw new ShaderException("shader program is not valid. Linker output for {0}: {1}\n", Identifier ?? "<Unnamed>", sb.ToString());
			}
			// Set linked flag
			_Linked = true;

			#endregion

			#region Collect Active Program Uniforms

			int uniformBufferSize, attributeBufferSize;
			int uniformCount;

			// Get active uniforms count
			Gl.GetProgram(ObjectName, Gl.ACTIVE_UNIFORMS, out uniformCount);
			// Get uniforms maximum length for name
			Gl.GetProgram(ObjectName, Gl.ACTIVE_UNIFORM_MAX_LENGTH, out uniformBufferSize);

			// Clear uniform mapping
			_UniformMap.Clear();
			_DefaultBlockUniformSlots = 0;

			// Collect uniform information
			for (uint i = 0; i < (uint)uniformCount; i++) {
				int uniformNameLength, uniformSize, uniformType;

				// Mono optimize StringBuilder capacity after P/Invoke... ensure enought room
				StringBuilder uNameBuilder = new StringBuilder(uniformBufferSize + 2);
				uNameBuilder.EnsureCapacity(uniformBufferSize);

				// Obtain active uniform informations
				Gl.GetActiveUniform(ObjectName, i, uniformBufferSize, out uniformNameLength, out uniformSize, out uniformType, uNameBuilder);

				string uniformName = uNameBuilder.ToString();

				// Obtain active uniform location
				int uLocation = Gl.GetUniformLocation(ObjectName, uniformName);

				UniformBinding uniformBinding = new UniformBinding(uniformName, i, uLocation, (ShaderUniformType)uniformType);

				// Map active uniform
				_UniformMap[uniformName] = uniformBinding;
				// Keep track of used slot
				_DefaultBlockUniformSlots += GetUniformSlotCount(uniformBinding.UniformType);
			}

			// Log uniform location mapping
			List<string> uniformNames = new List<string>(_UniformMap.Keys);

			// Make uniform list invariant respect the used driver (ease log comparation)
			uniformNames.Sort();

			sLog.Debug("Shader program active uniforms:");
			foreach (string uniformName in uniformNames)
				sLog.Debug("\tUniform {0} (Type: {1}, Location: {2})", uniformName, _UniformMap[uniformName].UniformType, _UniformMap[uniformName].Location);

			sLog.Debug("Shader program active uniform slots: {0}", _DefaultBlockUniformSlots);

			#endregion

			#region Collect Active Program Inputs

			// Get active inputs count
			int activeInputs;

			Gl.GetProgram(ObjectName, Gl.ACTIVE_ATTRIBUTES, out activeInputs);
			// Get inputs maximum length for name
			Gl.GetProgram(ObjectName, Gl.ACTIVE_ATTRIBUTE_MAX_LENGTH, out attributeBufferSize);

			// Clear input mapping
			_AttributesMap.Clear();

			// Collect input location mapping
			for (uint i = 0; i < (uint)activeInputs; i++) {
				StringBuilder nameBuffer = new StringBuilder(attributeBufferSize);
				int nameLength, size, type;

				// Mono optimize StringBuilder capacity after P/Invoke... ensure enought room for the current loop
				nameBuffer.EnsureCapacity(attributeBufferSize);

				// Obtain active input informations
				Gl.GetActiveAttrib(ObjectName, i, attributeBufferSize, out nameLength, out size, out type, nameBuffer);
				// Obtain active input location
				string name = nameBuffer.ToString();

				int location = Gl.GetAttribLocation(ObjectName, name);
				// Map active input
				_AttributesMap[name] = new AttributeBinding((uint)location, (ShaderAttributeType)type);
			}

			// Log attribute mapping
			List<string> attributeNames = new List<string>(_AttributesMap.Keys);

			// Make attribute list invariant respect the used driver (ease log comparation)
			attributeNames.Sort();

			sLog.Debug("Shader program active attributes:");
			foreach (string attributeName in attributeNames)
				sLog.Debug("\tAttribute {0} (Type: {1}, Location: {2})", attributeName, _AttributesMap[attributeName].Type, _AttributesMap[attributeName].Location);

			#endregion

			#region Collect Fragment Locations

			if (ctx.Caps.GlExtensions.GpuShader4_EXT) {
				// Get fragment locations, just in the case automatically assigned
				foreach (string fragOutputName in new List<string>(_FragLocations.Keys))
					_FragLocations[fragOutputName] = Gl.GetFragDataLocation(ObjectName, fragOutputName);
			}

			#endregion
			
			#region Collect Feedback Varyings
			
			if ((_FeedbackVaryings != null) && (_FeedbackVaryings.Count > 0)) {
				if (ctx.Caps.GlExtensions.TransformFeedback2_ARB || ctx.Caps.GlExtensions.TransformFeedback_EXT) {
					// Map active feedback
					int feebackVaryings, feebackVaryingsMaxLength;

					Gl.GetProgram(ObjectName, Gl.TRANSFORM_FEEDBACK_VARYINGS, out feebackVaryings);
					Gl.GetProgram(ObjectName, Gl.TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, out feebackVaryingsMaxLength);

					for (uint i = 0; i < feebackVaryings; i++) {
						StringBuilder sb = new StringBuilder(feebackVaryingsMaxLength);
						int length = 0, size = 0, type = 0;

						Gl.GetTransformFeedbackVarying(ObjectName, (uint)i, feebackVaryingsMaxLength, out length, out size, out type, sb);
						_FeedbacksMap.Add(sb.ToString(), new FeedbackBinding((ShaderAttributeType)type, (uint)size));
					}
				} else if (ctx.Caps.GlExtensions.TransformFeedback2_NV) {
					// Activate varyings
					foreach (string feedbackVaryingName in _FeedbackVaryings) {
						Gl.ActiveVaryingNV(ObjectName, feedbackVaryingName);
					}
					
					// Map active feedback
					int feebackVaryings, feebackVaryingsMaxLength;

					Gl.GetProgram(ObjectName, Gl.ACTIVE_VARYINGS_NV, out feebackVaryings);
					Gl.GetProgram(ObjectName, Gl.ACTIVE_VARYING_MAX_LENGTH_NV, out feebackVaryingsMaxLength);

					for (uint i = 0; i < feebackVaryings; i++) {
						StringBuilder sb = new StringBuilder(feebackVaryingsMaxLength * 2);
						int length = 0, size = 0, type = 0;

						Gl.GetActiveVaryingNV(ObjectName, (uint)i, feebackVaryingsMaxLength * 2, out length, out size, out type, sb);

						_FeedbacksMap.Add(sb.ToString(), new FeedbackBinding((ShaderAttributeType)type, (uint)size));
					}

					// Specify feedback varyings
					List<int> feedbackLocations = new List<int>();

					foreach (string feedbackVaryingName in _FeedbackVaryings) {
						int location = Gl.GetVaryingLocationNV(ObjectName, feedbackVaryingName);

						if (location >= 0)
							feedbackLocations.Add(location);
					}

					Gl.TransformFeedbackVaryingsNV(ObjectName, feedbackLocations.ToArray(), (int)cctx.FeedbackVaryingsFormat);

					// Map active feedback

				}

				Debug.Assert(_FeedbacksMap.Count > 0);

				// Log feedback mapping
				sLog.Debug("Shader program active feedbacks:");
				foreach (string feedbackName in _FeedbacksMap.Keys)
					sLog.Debug("\tFeedback {0} (Type: {1})", feedbackName, _FeedbacksMap[feedbackName].Type);
			}
			
			#endregion
		}
		private static void CheckUniformType(UniformBinding uniform, params int[] uniformRequestTypes)
		{
			if (uniform == null)
				throw new ArgumentNullException("uniform");
			if (uniformRequestTypes == null)
				throw new ArgumentNullException("uniformRequestTypes");

			/* ! Check: required uniform type shall correspond */
			foreach (int uniformReqtype in uniformRequestTypes)
				if ((int)uniform.UniformType == uniformReqtype)
					return;

			// 3.3.0 NVIDIA 310.44 confuse float uniforms (maybe in structs?) as vec4
			if (uniform.UniformType == ShaderUniformType.Vec4)
				return;

			throw new InvalidOperationException("uniform type mismatch");
		}