Exemplo n.º 1
0
        private void AddUniform(EffectReflection effectReflection, bool[] validConstantBuffers, int uniformSize, int uniformCount, string uniformName, ActiveUniformType uniformType)
        {
            // OpenGL ES 2 is adding uniform for each cbuffer member, so we need to remove array and struct indexers so that we can identify it in cbuffer and find offset
            var uniformParts = new List<UniformPart>(8);
            var uniformLastStart = 0;
            for (var index = 0; index <= uniformName.Length; index++)
            {
                char c = index == uniformName.Length ? '.' : uniformName[index]; // Treat string end same as '.'
                if (c == '.' || c == '[')
                {
                    var uniformPart = new UniformPart { Start = uniformLastStart, Count = index - uniformLastStart, Indexer = -1 };

                    // Read array index (if any)
                    if (c == '[')
                    {
                        var indexerStart = ++index;
                        while (uniformName[index] != ']')
                            index++;
                        // TODO: Avoid substring
                        uniformPart.Indexer = int.Parse(uniformName.Substring(indexerStart, index - indexerStart));
                        index++;
                    }

                    uniformParts.Add(uniformPart);
                    uniformLastStart = index + 1;
                }
            }

            var variableName = uniformName.Substring(0, uniformParts[0].Count);

            // check that this uniform is in a constant buffer
            int indexOfConstantBuffer = -1;
            int indexOfMember = -1;
            EffectConstantBufferDescription constantBufferDescription = null;
            for (int cbIndex = 0; cbIndex < effectReflection.ConstantBuffers.Count; cbIndex++)
            {
                var currentConstantBuffer = effectReflection.ConstantBuffers[cbIndex];
                for (int index = 0; index < currentConstantBuffer.Members.Length; index++)
                {
                    var member = currentConstantBuffer.Members[index];
                    if (member.RawName.Equals(variableName))
                    {
                        indexOfConstantBuffer = cbIndex;
                        indexOfMember = index;
                        constantBufferDescription = currentConstantBuffer;
                        break;
                    }
                }
                if (constantBufferDescription != null)
                    break;
            }

            if (constantBufferDescription == null)
            {
                throw new Exception("The uniform value " + variableName + " is defined outside of a uniform block, which is not supported by the engine.");
            }

            var indexOfResource = effectReflection.ResourceBindings.FindIndex(x => x.RawName == constantBufferDescription.Name);
            if (indexOfResource == -1)
            {
                reflectionResult.Error("Unable to find uniform [{0}] in any constant buffer", uniformName);
                return;
            }

            //var constantBufferDescription = effectReflection.ConstantBuffers[indexOfConstantBufferDescription];
            var constantBuffer = effectReflection.ResourceBindings[indexOfResource];

            // First time we encounter this cbuffer?
            if (!validConstantBuffers[indexOfConstantBuffer])
            {
                constantBuffer.SlotStart = ConstantBufferOffsets.Length - 1;

                // Find next cbuffer slot
                Array.Resize(ref ConstantBufferOffsets, ConstantBufferOffsets.Length + 1);

                effectReflection.ResourceBindings[indexOfResource] = constantBuffer;

                ConstantBufferOffsets[constantBuffer.SlotStart + 1] = ConstantBufferOffsets[constantBuffer.SlotStart] + constantBufferDescription.Size;

                validConstantBuffers[indexOfConstantBuffer] = true;
            }

            //var elementSize = uniformSize;

            // For array, each element is rounded to register size
            //if (uniformSize%16 != 0 && uniformCount > 1)
            //{
            //    constantBufferDescription.Size = (constantBufferDescription.Size + 15)/16*16;
            //    uniformSize = (uniformSize + 15)/16*16;
            //}

            // Check if it can fits in the same register, otherwise starts at the next one
            //if (uniformCount == 1 && constantBufferDescription.Size/16 != (constantBufferDescription.Size + uniformSize - 1)/16)
            //    constantBufferDescription.Size = (constantBufferDescription.Size + 15)/16*16;

            var variable = constantBufferDescription.Members[indexOfMember];

            // Resolve array/member
            var offset = variable.Offset;
            var type = variable.Type;

            for (int i = 0; i < uniformParts.Count; ++i)
            {
                var uniformPart = uniformParts[i];

                // Apply member
                if (i > 0)
                {
                    if (type.Members == null)
                        throw new InvalidOperationException($"Tried to find member \"{uniformName.Substring(uniformPart.Start, uniformPart.Count)}\" on a non-struct type when processing \"{uniformName}\"");

                    bool memberFound = false;
                    for (int memberIndex = 0; memberIndex < type.Members.Length; ++memberIndex)
                    {
                        var member = type.Members[memberIndex];
                        if (string.Compare(member.Name, 0, uniformName, uniformPart.Start, uniformPart.Count) == 0)
                        {
                            // Adjust offset and set new type
                            offset += member.Offset;
                            type = member.Type;

                            memberFound = true;
                            break;
                        }
                    }

                    if (!memberFound)
                        throw new InvalidOperationException($"Couldn't find member \"{uniformName.Substring(uniformPart.Start, uniformPart.Count)}\" on struct type \"{type.Name}\" when processing \"{uniformName}\"");
                }
                   
                // Apply indexer for arrays
                if (uniformPart.Indexer != -1)
                {
                    offset += (type.ElementSize + 15) / 16 * 16 * uniformPart.Indexer;
                }
            }

            // Check type
            if (type.Type != GetTypeFromActiveUniformType(uniformType))
                throw new InvalidOperationException($"Uniform [{uniformName}] of type [{variable.Type.Type}] doesn't match OpenGL shader expected type [{GetTypeFromActiveUniformType(uniformType)}]");

            // No need to compare last element padding.
            // TODO: In case of float1/float2 arrays (rare) it is quite non-optimal to do a CompareMemory
            //variable.Size = uniformSize * (uniformCount - 1) + elementSize;
            //constantBufferDescription.Members[indexOfUniform] = variable;

            Uniforms.Add(new Uniform
            {
                Type = uniformType,
                Count = uniformCount,
                CompareSize = uniformSize + (uniformSize + 15)/16*16 * (uniformCount - 1),
                ConstantBufferSlot = constantBuffer.SlotStart,
                Offset = offset,
                UniformIndex = GL.GetUniformLocation(ProgramId, uniformName)
            });
        }
Exemplo n.º 2
0
        private void _addOrUpdateStandartUniformPart(SentenceElement uniformPart, string rowNr)
        {
            Debug.Assert(rowNr == UnknownRowNr);

            var uniformPartElement = All.Find(x => x.Id == uniformPart.Id);
            if (uniformPartElement != null) return;

            var uniformPartNewElement = new UniformPart(uniformPart, rowNr, -1, -1);
            Log.DebugFormat(
                $"[{Type}]Актуализация: Создание нового ОЧ: Id = {uniformPartNewElement.Id}, Текст = {uniformPartNewElement.Text}");

            if (All.Any(x => x.RowNr == rowNr))
            {
                Log.DebugFormat(
                    $"[{Type}]Актуализация: Добавляем ОЧ с Id = {uniformPartNewElement.Id} в ряд с номером '{rowNr}'");
                // добавляем его в объект того ряда, куда он входит, если таковых еще нет.
                if (All.Find(x => x.RowNr == uniformPartNewElement.RowNr && x.Id == uniformPartNewElement.Id) == null)
                {
                    Items.ToList()
                        .Find(x => x.Values.Select(y => y.RowNr).Contains(rowNr))
                        .Add(uniformPartNewElement.Order, uniformPartNewElement);
                }
            }
            else
            {
                var uniformPartsNewRow = new UniformPartRow {{uniformPartNewElement.Order, uniformPartNewElement}};
                Log.DebugFormat($"[{Type}]Актуализация: Сформирован новый ряд ОЧ с номером '{rowNr}'");
                // добавляем ряд к результатам
                Items.Add(uniformPartsNewRow);
            }
        }
Exemplo n.º 3
0
        private void AddUniform(EffectReflection effectReflection, bool[] validConstantBuffers, int uniformSize, int uniformCount, string uniformName, ActiveUniformType uniformType)
        {
            // OpenGL ES 2 is adding uniform for each cbuffer member, so we need to remove array and struct indexers so that we can identify it in cbuffer and find offset
            var uniformParts     = new List <UniformPart>(8);
            var uniformLastStart = 0;

            for (var index = 0; index <= uniformName.Length; index++)
            {
                char c = index == uniformName.Length ? '.' : uniformName[index]; // Treat string end same as '.'
                if (c == '.' || c == '[')
                {
                    var uniformPart = new UniformPart {
                        Start = uniformLastStart, Count = index - uniformLastStart, Indexer = -1
                    };

                    // Read array index (if any)
                    if (c == '[')
                    {
                        var indexerStart = ++index;
                        while (uniformName[index] != ']')
                        {
                            index++;
                        }
                        // TODO: Avoid substring
                        uniformPart.Indexer = int.Parse(uniformName.Substring(indexerStart, index - indexerStart));
                        index++;
                    }

                    uniformParts.Add(uniformPart);
                    uniformLastStart = index + 1;
                }
            }

            var variableName = uniformName.Substring(0, uniformParts[0].Count);

            // check that this uniform is in a constant buffer
            int indexOfConstantBuffer = -1;
            int indexOfMember         = -1;
            EffectConstantBufferDescription constantBufferDescription = null;

            for (int cbIndex = 0; cbIndex < effectReflection.ConstantBuffers.Count; cbIndex++)
            {
                var currentConstantBuffer = effectReflection.ConstantBuffers[cbIndex];
                for (int index = 0; index < currentConstantBuffer.Members.Length; index++)
                {
                    var member = currentConstantBuffer.Members[index];
                    if (member.RawName.Equals(variableName))
                    {
                        indexOfConstantBuffer     = cbIndex;
                        indexOfMember             = index;
                        constantBufferDescription = currentConstantBuffer;
                        break;
                    }
                }
                if (constantBufferDescription != null)
                {
                    break;
                }
            }

            if (constantBufferDescription == null)
            {
                throw new Exception("The uniform value " + variableName + " is defined outside of a uniform block, which is not supported by the engine.");
            }

            var indexOfResource = effectReflection.ResourceBindings.FindIndex(x => x.RawName == constantBufferDescription.Name);

            if (indexOfResource == -1)
            {
                reflectionResult.Error($"Unable to find uniform [{uniformName}] in any constant buffer");
                return;
            }

            //var constantBufferDescription = effectReflection.ConstantBuffers[indexOfConstantBufferDescription];
            var constantBuffer = effectReflection.ResourceBindings[indexOfResource];

            // First time we encounter this cbuffer?
            if (!validConstantBuffers[indexOfConstantBuffer])
            {
                constantBuffer.SlotStart = ConstantBufferOffsets.Length - 1;

                // Find next cbuffer slot
                Array.Resize(ref ConstantBufferOffsets, ConstantBufferOffsets.Length + 1);

                effectReflection.ResourceBindings[indexOfResource] = constantBuffer;

                ConstantBufferOffsets[constantBuffer.SlotStart + 1] = ConstantBufferOffsets[constantBuffer.SlotStart] + constantBufferDescription.Size;

                validConstantBuffers[indexOfConstantBuffer] = true;
            }

            //var elementSize = uniformSize;

            // For array, each element is rounded to register size
            //if (uniformSize%16 != 0 && uniformCount > 1)
            //{
            //    constantBufferDescription.Size = (constantBufferDescription.Size + 15)/16*16;
            //    uniformSize = (uniformSize + 15)/16*16;
            //}

            // Check if it can fits in the same register, otherwise starts at the next one
            //if (uniformCount == 1 && constantBufferDescription.Size/16 != (constantBufferDescription.Size + uniformSize - 1)/16)
            //    constantBufferDescription.Size = (constantBufferDescription.Size + 15)/16*16;

            var variable = constantBufferDescription.Members[indexOfMember];

            // Resolve array/member
            var offset = variable.Offset;
            var type   = variable.Type;

            for (int i = 0; i < uniformParts.Count; ++i)
            {
                var uniformPart = uniformParts[i];

                // Apply member
                if (i > 0)
                {
                    if (type.Members == null)
                    {
                        throw new InvalidOperationException($"Tried to find member \"{uniformName.Substring(uniformPart.Start, uniformPart.Count)}\" on a non-struct type when processing \"{uniformName}\"");
                    }

                    bool memberFound = false;
                    for (int memberIndex = 0; memberIndex < type.Members.Length; ++memberIndex)
                    {
                        var member = type.Members[memberIndex];
                        if (string.Compare(member.Name, 0, uniformName, uniformPart.Start, uniformPart.Count) == 0)
                        {
                            // Adjust offset and set new type
                            offset += member.Offset;
                            type    = member.Type;

                            memberFound = true;
                            break;
                        }
                    }

                    if (!memberFound)
                    {
                        throw new InvalidOperationException($"Couldn't find member \"{uniformName.Substring(uniformPart.Start, uniformPart.Count)}\" on struct type \"{type.Name}\" when processing \"{uniformName}\"");
                    }
                }

                // Apply indexer for arrays
                if (uniformPart.Indexer != -1)
                {
                    offset += (type.ElementSize + 15) / 16 * 16 * uniformPart.Indexer;
                }
            }

            // Check type
            if (type.Type != GetTypeFromActiveUniformType(uniformType))
            {
                throw new InvalidOperationException($"Uniform [{uniformName}] of type [{variable.Type.Type}] doesn't match OpenGL shader expected type [{GetTypeFromActiveUniformType(uniformType)}]");
            }

            // No need to compare last element padding.
            // TODO: In case of float1/float2 arrays (rare) it is quite non-optimal to do a CompareMemory
            //variable.Size = uniformSize * (uniformCount - 1) + elementSize;
            //constantBufferDescription.Members[indexOfUniform] = variable;

            Uniforms.Add(new Uniform
            {
                Type               = uniformType,
                Count              = uniformCount,
                CompareSize        = uniformSize + (uniformSize + 15) / 16 * 16 * (uniformCount - 1),
                ConstantBufferSlot = constantBuffer.SlotStart,
                Offset             = offset,
                UniformIndex       = GL.GetUniformLocation(ProgramId, uniformName)
            });
        }
Exemplo n.º 4
0
        private void _addOrUpdateBaseOrFinalRowsUniformPart(SentenceElement uniformPart, string rowNr,
            int featureLinkConjunction, int featureLinkComma)
        {
            // если ряд неизвестен, то это эквивалентно добавление стандартного ОЧ
            if (rowNr == UnknownRowNr)
            {
                Log.DebugFormat($"[{Type}]Актуализация: ряд неизвестен, добавляем как стандартный ОЧ");
                _addOrUpdateStandartUniformPart(uniformPart, rowNr);
                return;
            }

            // когда добавляем ОЧ с наличием признака ряда, то старый надо удалить из ряда "-1"
            var uniformPartInUnknownRow = All.Find(x => x.Id == uniformPart.Id && x.RowNr == UnknownRowNr);
            if (rowNr != UnknownRowNr && uniformPartInUnknownRow != null)
            {
                Log.DebugFormat(
                    $"[{Type}]Актуализация: удаление существующего ОЧ с Id = {uniformPartInUnknownRow.Id} и рядом {uniformPartInUnknownRow.RowNr}");
                RemoveUniformPart(uniformPartInUnknownRow.Id, false);
            }

            List<UniformPart> uniformPartElements = new List<UniformPart>();
            // если надо обновить инфу об ОЧ во всех рядах (rowNr == string.Empty)
            if (rowNr == string.Empty)
                uniformPartElements.AddRange(All.FindAll(x => x.Id == uniformPart.Id));
            else // обычная ситуация
                uniformPartElements = All.FindAll(x => x.Id == uniformPart.Id && x.RowNr == rowNr);
            // ОЧ с комбинацией Id-RowNr уже существует
            if (uniformPartElements.Count > 0)
            {
                foreach (var uniformPartElement in uniformPartElements)
                {
                    if ((uniformPartElement.RowNr != rowNr)
                        || (uniformPartElement.RowNr == rowNr)
                        || uniformPartElement.FeatureLinkComma != featureLinkComma
                        || uniformPartElement.FeatureLinkConjunction != featureLinkConjunction)
                    {
                        Log.DebugFormat(
                            $"[{Type}]Возможная актуализация: Обновление ОЧ с Id = {uniformPartElement.Id}, Текст = {uniformPartElement.Text}, Ряд = {rowNr}");

                        if (rowNr != string.Empty)
                        {
                            uniformPartElement.RowNr = rowNr;
                            Log.Debug($"[{Type}]Обновлен Ряд: {rowNr}");
                        }
                        if (featureLinkComma != 0)
                        {
                            uniformPartElement.FeatureLinkComma = featureLinkComma;
                            Log.Debug($"[{Type}]Обновлен ПС Запятая: {featureLinkComma}");
                        }
                        if (featureLinkConjunction != 0)
                        {
                            uniformPartElement.FeatureLinkConjunction = featureLinkConjunction;
                            Log.Debug($"[{Type}]Обновлен ПС Союз: {featureLinkConjunction}");
                        }
                    }
                }
            }

            // // ОЧ с комбинацией Id-RowNr НЕ существует
            else
            {
                // если надо создать ряд с пустым номером ряда, то расцениваем это как создание ОЧ с № = -1.
                if (rowNr == string.Empty)
                    rowNr = UnknownRowNr;
                var uniformPartNewElement = new UniformPart(uniformPart, rowNr, featureLinkConjunction, featureLinkComma);
                Log.DebugFormat(
                    $"[{Type}]Актуализация: Создание нового ОЧ: Id = {uniformPartNewElement.Id}, Текст = {uniformPartNewElement.Text}");

                if (rowNr != string.Empty)
                {
                    // проверяем, нет ли уже объектов рядов с номером ряда, как у добавляемого
                    if (All.Any(x => x.RowNr == rowNr))
                    {
                        Log.DebugFormat(
                            $"[{Type}]Актуализация: Добавляем ОЧ с Id = {uniformPartNewElement.Id} в ряд с номером '{rowNr}'");
                        // добавляем его в объект того ряда, куда он входит, если таковых еще нет.
                        if (All.Find(x => x.RowNr == uniformPartNewElement.RowNr && x.Id == uniformPartNewElement.Id) ==
                            null)
                        {
                            Items.ToList()
                                .Find(x => x.Values.Select(y => y.RowNr).Contains(rowNr))
                                .Add(uniformPartNewElement.Order, uniformPartNewElement);
                        }
                    }
                    else
                    {
                        // если рядов не нашлось, то создаем новый ряд и добавляем туда наш элемент
                        var uniformPartsNewRow = new UniformPartRow
                        {
                            {uniformPartNewElement.Order, uniformPartNewElement}
                        };
                        Log.DebugFormat($"[{Type}]Актуализация: Сформирован новый ряд ОЧ с номером '{rowNr}'");
                        // добавляем ряд к результатам
                        Items.Add(uniformPartsNewRow);
                    }
                }
            }
            if (_needToMerge)
                _mergeRows();
        }