| 1 | // Copyright (C) 2019 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
| 3 | |
| 4 | #ifndef QSSGSHADERRESOURCEMERGECONTEXT_P_H |
| 5 | #define QSSGSHADERRESOURCEMERGECONTEXT_P_H |
| 6 | |
| 7 | // |
| 8 | // W A R N I N G |
| 9 | // ------------- |
| 10 | // |
| 11 | // This file is not part of the Qt API. It exists purely as an |
| 12 | // implementation detail. This header file may change from version to |
| 13 | // version without notice, or even be removed. |
| 14 | // |
| 15 | // We mean it. |
| 16 | // |
| 17 | |
| 18 | #include "qssgrendershadercodegenerator_p.h" |
| 19 | #include "qssgrendershadermetadata_p.h" |
| 20 | |
| 21 | QT_BEGIN_NAMESPACE |
| 22 | |
| 23 | class QSSGShaderResourceMergeContext |
| 24 | { |
| 25 | public: |
| 26 | // Resource bindings 0..2 are reserved for uniform buffers. |
| 27 | // (0 is cbMain, 1 is cbLights) |
| 28 | static const int FIRST_CUSTOM_RESOURCE_BINDING_POINT = 3; |
| 29 | |
| 30 | struct InOutVar { |
| 31 | QSSGShaderGeneratorStageFlags stageOutputFrom; |
| 32 | QSSGShaderGeneratorStageFlags stagesInputIn; |
| 33 | QByteArray type; |
| 34 | QByteArray name; |
| 35 | int location; |
| 36 | bool output; |
| 37 | bool flat; |
| 38 | }; |
| 39 | |
| 40 | struct Sampler { |
| 41 | QByteArray type; |
| 42 | QByteArray name; |
| 43 | QSSGRenderShaderMetadata::Uniform::Condition conditionType; |
| 44 | QByteArray conditionName; |
| 45 | int binding; |
| 46 | }; |
| 47 | |
| 48 | struct BlockMember { |
| 49 | QByteArray type; |
| 50 | QByteArray name; |
| 51 | QSSGRenderShaderMetadata::Uniform::Condition conditionType; |
| 52 | QByteArray conditionName; |
| 53 | }; |
| 54 | |
| 55 | // Using QMap intentionally - while it is not strictly required to use an |
| 56 | // ordered map, being sorted by key when iterating is helpful to get the |
| 57 | // same ordered list of vertex inputs, uniforms, etc. on every run, which |
| 58 | // in turn helps shader (disk) cache efficiency due to not generating a |
| 59 | // different shader string just because QHash decided to iterate entries in |
| 60 | // a different order. |
| 61 | QMap<QByteArray, InOutVar> m_inOutVars; |
| 62 | QMap<QByteArray, Sampler> m_samplers; |
| 63 | QMap<QByteArray, BlockMember> m_uniformMembers; |
| 64 | |
| 65 | int m_nextFreeResourceBinding = FIRST_CUSTOM_RESOURCE_BINDING_POINT; |
| 66 | QHash<int, int> m_nextFreeInLocation; |
| 67 | QHash<int, int> m_nextFreeOutLocation; |
| 68 | |
| 69 | int viewCount = 1; |
| 70 | |
| 71 | void registerInput(QSSGShaderGeneratorStage stage, const QByteArray &type, const QByteArray &name, bool flat = false) |
| 72 | { |
| 73 | auto it = m_inOutVars.find(key: name); |
| 74 | if (it != m_inOutVars.end()) { |
| 75 | it->stagesInputIn |= stage; |
| 76 | return; |
| 77 | } |
| 78 | InOutVar var { .stageOutputFrom: {}, .stagesInputIn: stage, .type: type, .name: name, .location: m_nextFreeInLocation[int(stage)]++, .output: false, .flat: flat }; |
| 79 | m_inOutVars.insert(key: name, value: var); |
| 80 | } |
| 81 | |
| 82 | void registerOutput(QSSGShaderGeneratorStage stage, const QByteArray &type, const QByteArray &name, bool flat = false) |
| 83 | { |
| 84 | auto it = m_inOutVars.find(key: name); |
| 85 | if (it != m_inOutVars.end()) { |
| 86 | it->stageOutputFrom |= stage; |
| 87 | return; |
| 88 | } |
| 89 | InOutVar var { .stageOutputFrom: stage, .stagesInputIn: {}, .type: type, .name: name, .location: m_nextFreeOutLocation[int(stage)]++, .output: true, .flat: flat }; |
| 90 | m_inOutVars.insert(key: name, value: var); |
| 91 | } |
| 92 | |
| 93 | void registerSampler(const QByteArray &type, |
| 94 | const QByteArray &name, |
| 95 | QSSGRenderShaderMetadata::Uniform::Condition conditionType = QSSGRenderShaderMetadata::Uniform::None, |
| 96 | const QByteArray &conditionName = QByteArray()) |
| 97 | { |
| 98 | if (m_samplers.contains(key: name)) |
| 99 | return; |
| 100 | Sampler var { .type: type, .name: name, .conditionType: conditionType, .conditionName: conditionName, .binding: m_nextFreeResourceBinding++ }; |
| 101 | m_samplers.insert(key: name, value: var); |
| 102 | } |
| 103 | |
| 104 | void registerUniformMember(const QByteArray &type, |
| 105 | const QByteArray &name, |
| 106 | QSSGRenderShaderMetadata::Uniform::Condition conditionType = QSSGRenderShaderMetadata::Uniform::None, |
| 107 | const QByteArray &conditionName = QByteArray()) |
| 108 | { |
| 109 | auto it = m_uniformMembers.constFind(key: name); |
| 110 | if (it != m_uniformMembers.constEnd()) { |
| 111 | if (it->conditionType != conditionType) { |
| 112 | qWarning(msg: "Encountered uniform %s with different conditions, this is not supported." , |
| 113 | name.constData()); |
| 114 | } |
| 115 | return; |
| 116 | } |
| 117 | BlockMember var { .type: type, .name: name, .conditionType: conditionType, .conditionName: conditionName }; |
| 118 | m_uniformMembers.insert(key: name, value: var); |
| 119 | } |
| 120 | }; |
| 121 | |
| 122 | QT_END_NAMESPACE |
| 123 | |
| 124 | #endif |
| 125 | |