Example #1
0
        /// <summary>
        /// Creates a new instance of the Shader class.
        /// </summary>
        /// <param name="shaderBytecode">Byte array containing the compiled shader bytecode.</param>
        public Shader(byte[] shaderBytecode)
        {
            var bytecodeContainer = new BytecodeContainer(shaderBytecode);

            var programType = bytecodeContainer.Shader.Version.ProgramType;

            switch (programType)
            {
            case ProgramType.GeometryShader:
            case ProgramType.HullShader:
            case ProgramType.DomainShader:
            case ProgramType.ComputeShader:
                throw new NotSupportedException(string.Format(
                                                    "The '{0}' shader type is not yet supported.",
                                                    bytecodeContainer.Shader.Version.ProgramType));
            }

            _constantBuffers     = bytecodeContainer.ResourceDefinition.ConstantBuffers;
            _resourceBindings    = bytecodeContainer.ResourceDefinition.ResourceBindings;
            _inputSignature      = bytecodeContainer.InputSignature;
            _inputSignatureSize  = _inputSignature.Parameters.Sum(x => x.ByteCount);
            _outputSignature     = bytecodeContainer.OutputSignature;
            _outputSignatureSize = _outputSignature.Parameters.Sum(x => x.ByteCount);

            var numContexts = (programType == ProgramType.PixelShader) ? 4 : 1;

            _virtualMachine = new VirtualMachine(bytecodeContainer, numContexts);
        }
Example #2
0
        internal IEnumerable <FragmentQuad> Execute(
            IEnumerable <InputAssemblerPrimitiveOutput> inputs,
            PrimitiveTopology primitiveTopology,
            OutputSignatureChunk previousStageOutputSignature,
            BytecodeContainer pixelShader,
            int multiSampleCount)
        {
            // TODO: Allow selection of different viewport.
            var viewport = _viewports[0];

            var outputInputBindings = ShaderOutputInputBindings.FromShaderSignatures(
                previousStageOutputSignature, pixelShader);

            var rasterizer = PrimitiveRasterizerFactory.CreateRasterizer(
                primitiveTopology, State.Description, multiSampleCount,
                outputInputBindings, ref viewport, FragmentFilter);

            foreach (var primitive in inputs)
            {
                // Frustum culling.
                if (ViewportCuller.ShouldCullTriangle(primitive.Vertices))
                {
                    continue;
                }

                // TODO: Clipping.
                // http://simonstechblog.blogspot.tw/2012/04/software-rasterizer-part-2.html#softwareRasterizerDemo

                // Perspective divide.
                for (int i = 0; i < primitive.Vertices.Length; i++)
                {
                    PerspectiveDivide(ref primitive.Vertices[i].Position);
                }

                // Backface culling.
                if (State.Description.CullMode != CullMode.None && rasterizer.ShouldCull(primitive.Vertices))
                {
                    continue;
                }

                // Transform from clip space to screen space.
                for (int i = 0; i < primitive.Vertices.Length; i++)
                {
                    viewport.MapClipSpaceToScreenSpace(ref primitive.Vertices[i].Position);
                }

                // Rasterize.
                foreach (var fragmentQuad in rasterizer.Rasterize(primitive))
                {
                    yield return(fragmentQuad);
                }
            }
        }
        /// <summary>
        /// Registers are effectively shared between outputs of the previous stage
        /// and inputs of the next stage, so we don't need to do any mapping. We only
        /// need to keep track of the interpolation mode, and system value semantic,
        /// of the inputs.
        /// <seealso cref="http://msdn.microsoft.com/en-us/library/windows/desktop/bb509650(v=vs.85).aspx"/>
        ///
        /// TODO: Add some sort of runtime validation that signatures match. Direct3D
        /// does this, but only when debugging.
        /// </summary>
        public static ShaderOutputInputBindings FromShaderSignatures(
            OutputSignatureChunk outputSignature,
            BytecodeContainer inputShader)
        {
            var inputRegisterDeclarations = inputShader.Shader.DeclarationTokens
                                            .OfType <PixelShaderInputRegisterDeclarationToken>()
                                            .ToList();

            // Only create a binding if the value is actually used in the next shader.
            // We can gather this information from the declaration tokens. If there is
            // no declaration token for an item, then it isn't used.
            var bindings = new List <ShaderOutputInputBinding>();

            foreach (var inputParameter in inputShader.InputSignature.Parameters)
            {
                // Get register declaration for this parameter. If there is no register
                // declaration, then it isn't used, and we can move on.
                var inputRegisterDeclaration = FindInputRegisterDeclaration(
                    inputRegisterDeclarations, inputParameter);
                if (inputRegisterDeclaration == null)
                {
                    continue;
                }

                bindings.Add(new ShaderOutputInputBinding
                {
                    Register          = (int)inputParameter.Register,
                    ComponentMask     = inputParameter.Mask,
                    InterpolationMode = inputRegisterDeclaration.InterpolationMode,
                    SystemValueType   = inputParameter.SystemValueType
                });
            }

            return(new ShaderOutputInputBindings
            {
                Bindings = bindings.ToArray()
            });
        }