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
14namespace 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