| 1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
|---|---|
| 2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
| 3 | #include "Material/BsPass.h" |
| 4 | #include "RenderAPI/BsRasterizerState.h" |
| 5 | #include "RenderAPI/BsBlendState.h" |
| 6 | #include "RenderAPI/BsDepthStencilState.h" |
| 7 | #include "Private/RTTI/BsPassRTTI.h" |
| 8 | #include "Material/BsMaterial.h" |
| 9 | #include "RenderAPI/BsGpuParams.h" |
| 10 | #include "RenderAPI/BsGpuProgram.h" |
| 11 | #include "RenderAPI/BsGpuPipelineState.h" |
| 12 | #include "CoreThread/BsCoreObjectSync.h" |
| 13 | |
| 14 | namespace bs |
| 15 | { |
| 16 | template<bool Core> |
| 17 | TPass<Core>::TPass() |
| 18 | { |
| 19 | mData.stencilRefValue = 0; |
| 20 | } |
| 21 | |
| 22 | template<bool Core> |
| 23 | TPass<Core>::TPass(const PASS_DESC& data) |
| 24 | :mData(data) |
| 25 | { |
| 26 | |
| 27 | } |
| 28 | |
| 29 | template<bool Core> |
| 30 | bool TPass<Core>::hasBlending() const |
| 31 | { |
| 32 | bool transparent = false; |
| 33 | |
| 34 | for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++) |
| 35 | { |
| 36 | // Transparent if destination color is taken into account |
| 37 | if (mData.blendStateDesc.renderTargetDesc[i].dstBlend != BF_ZERO || |
| 38 | mData.blendStateDesc.renderTargetDesc[i].srcBlend == BF_DEST_COLOR || |
| 39 | mData.blendStateDesc.renderTargetDesc[i].srcBlend == BF_INV_DEST_COLOR || |
| 40 | mData.blendStateDesc.renderTargetDesc[i].srcBlend == BF_DEST_ALPHA || |
| 41 | mData.blendStateDesc.renderTargetDesc[i].srcBlend == BF_INV_DEST_ALPHA) |
| 42 | { |
| 43 | transparent = true; |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | return transparent; |
| 48 | } |
| 49 | |
| 50 | template<bool Core> |
| 51 | const GPU_PROGRAM_DESC& TPass<Core>::getProgramDesc(bs::GpuProgramType type) const |
| 52 | { |
| 53 | switch(type) |
| 54 | { |
| 55 | default: |
| 56 | case GPT_VERTEX_PROGRAM: |
| 57 | return mData.vertexProgramDesc; |
| 58 | case GPT_FRAGMENT_PROGRAM: |
| 59 | return mData.fragmentProgramDesc; |
| 60 | case GPT_GEOMETRY_PROGRAM: |
| 61 | return mData.geometryProgramDesc; |
| 62 | case GPT_HULL_PROGRAM: |
| 63 | return mData.hullProgramDesc; |
| 64 | case GPT_DOMAIN_PROGRAM: |
| 65 | return mData.domainProgramDesc; |
| 66 | case GPT_COMPUTE_PROGRAM: |
| 67 | return mData.computeProgramDesc; |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | template<bool Core> |
| 72 | void TPass<Core>::createPipelineState() |
| 73 | { |
| 74 | if (isCompute()) |
| 75 | { |
| 76 | SPtr<GpuProgramType> program = GpuProgramType::create(mData.computeProgramDesc); |
| 77 | mComputePipelineState = ComputePipelineStateType::create(program); |
| 78 | } |
| 79 | else |
| 80 | { |
| 81 | PipelineStateDescType desc; |
| 82 | |
| 83 | if(!mData.vertexProgramDesc.source.empty()) |
| 84 | desc.vertexProgram = GpuProgramType::create(mData.vertexProgramDesc); |
| 85 | |
| 86 | if(!mData.fragmentProgramDesc.source.empty()) |
| 87 | desc.fragmentProgram = GpuProgramType::create(mData.fragmentProgramDesc); |
| 88 | |
| 89 | if(!mData.geometryProgramDesc.source.empty()) |
| 90 | desc.geometryProgram = GpuProgramType::create(mData.geometryProgramDesc); |
| 91 | |
| 92 | if(!mData.hullProgramDesc.source.empty()) |
| 93 | desc.hullProgram = GpuProgramType::create(mData.hullProgramDesc); |
| 94 | |
| 95 | if(!mData.domainProgramDesc.source.empty()) |
| 96 | desc.domainProgram = GpuProgramType::create(mData.domainProgramDesc); |
| 97 | |
| 98 | desc.blendState = BlendStateType::create(mData.blendStateDesc); |
| 99 | desc.rasterizerState = RasterizerStateType::create(mData.rasterizerStateDesc); |
| 100 | desc.depthStencilState = DepthStencilStateType::create(mData.depthStencilStateDesc); |
| 101 | |
| 102 | mGraphicsPipelineState = GraphicsPipelineStateType::create(desc); |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | template <bool Core> |
| 107 | template <class P> |
| 108 | void TPass<Core>::rttiEnumFields(P p) |
| 109 | { |
| 110 | p(mGraphicsPipelineState); |
| 111 | p(mComputePipelineState); |
| 112 | } |
| 113 | |
| 114 | template class TPass < false > ; |
| 115 | template class TPass < true >; |
| 116 | |
| 117 | Pass::Pass(const PASS_DESC& desc) |
| 118 | :TPass(desc) |
| 119 | { } |
| 120 | |
| 121 | SPtr<ct::Pass> Pass::getCore() const |
| 122 | { |
| 123 | return std::static_pointer_cast<ct::Pass>(mCoreSpecific); |
| 124 | } |
| 125 | |
| 126 | SPtr<ct::CoreObject> Pass::createCore() const |
| 127 | { |
| 128 | ct::Pass* pass = new (bs_alloc<ct::Pass>()) ct::Pass(mData); |
| 129 | |
| 130 | SPtr<ct::Pass> passPtr = bs_shared_ptr(pass); |
| 131 | passPtr->_setThisPtr(passPtr); |
| 132 | |
| 133 | return passPtr; |
| 134 | } |
| 135 | |
| 136 | void Pass::compile() |
| 137 | { |
| 138 | if(mComputePipelineState || mGraphicsPipelineState) |
| 139 | return; // Already compiled |
| 140 | |
| 141 | // Note: It's possible (and quite likely) the pass has already been compiled on the core thread, so this will |
| 142 | // unnecessarily recompile it. However syncing them in a clean way is not trivial hard and this method is currently |
| 143 | // not being used much (at all) to warrant a complex solution. Something to keep in mind for later though. |
| 144 | createPipelineState(); |
| 145 | |
| 146 | markCoreDirty(); |
| 147 | CoreObject::syncToCore(); |
| 148 | } |
| 149 | |
| 150 | CoreSyncData Pass::syncToCore(FrameAlloc* allocator) |
| 151 | { |
| 152 | UINT32 size = coreSyncGetElemSize(*this); |
| 153 | |
| 154 | UINT8* data = allocator->alloc(size); |
| 155 | |
| 156 | char* dataPtr = (char*)data; |
| 157 | dataPtr = coreSyncWriteElem(*this, dataPtr); |
| 158 | |
| 159 | return CoreSyncData(data, size); |
| 160 | } |
| 161 | |
| 162 | SPtr<Pass> Pass::create(const PASS_DESC& desc) |
| 163 | { |
| 164 | Pass* newPass = new (bs_alloc<Pass>()) Pass(desc); |
| 165 | SPtr<Pass> newPassPtr = bs_core_ptr<Pass>(newPass); |
| 166 | newPassPtr->_setThisPtr(newPassPtr); |
| 167 | newPassPtr->initialize(); |
| 168 | |
| 169 | return newPassPtr; |
| 170 | } |
| 171 | |
| 172 | SPtr<Pass> Pass::createEmpty() |
| 173 | { |
| 174 | Pass* newPass = new (bs_alloc<Pass>()) Pass(); |
| 175 | SPtr<Pass> newPassPtr = bs_core_ptr<Pass>(newPass); |
| 176 | newPassPtr->_setThisPtr(newPassPtr); |
| 177 | |
| 178 | return newPassPtr; |
| 179 | } |
| 180 | |
| 181 | RTTITypeBase* Pass::getRTTIStatic() |
| 182 | { |
| 183 | return PassRTTI::instance(); |
| 184 | } |
| 185 | |
| 186 | RTTITypeBase* Pass::getRTTI() const |
| 187 | { |
| 188 | return Pass::getRTTIStatic(); |
| 189 | } |
| 190 | |
| 191 | namespace ct |
| 192 | { |
| 193 | Pass::Pass(const PASS_DESC& desc) |
| 194 | :TPass(desc) |
| 195 | { } |
| 196 | |
| 197 | void Pass::compile() |
| 198 | { |
| 199 | if(mComputePipelineState || mGraphicsPipelineState) |
| 200 | return; // Already compiled |
| 201 | |
| 202 | createPipelineState(); |
| 203 | } |
| 204 | |
| 205 | void Pass::syncToCore(const CoreSyncData& data) |
| 206 | { |
| 207 | char* dataPtr = (char*)data.getBuffer(); |
| 208 | dataPtr = coreSyncReadElem(*this, dataPtr); |
| 209 | } |
| 210 | |
| 211 | SPtr<Pass> Pass::create(const PASS_DESC& desc) |
| 212 | { |
| 213 | Pass* newPass = new (bs_alloc<Pass>()) Pass(desc); |
| 214 | SPtr<Pass> newPassPtr = bs_shared_ptr<Pass>(newPass); |
| 215 | newPassPtr->_setThisPtr(newPassPtr); |
| 216 | newPassPtr->initialize(); |
| 217 | |
| 218 | return newPassPtr; |
| 219 | } |
| 220 | } |
| 221 | } |
| 222 |