BsBansheeLitTexRenderableHandler.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. #include "BsBansheeLitTexRenderableHandler.h"
  2. #include "BsRenderableProxy.h"
  3. #include "BsShader.h"
  4. #include "BsShaderProxy.h"
  5. #include "BsGpuParams.h"
  6. #include "BsBansheeRenderer.h"
  7. #include "BsHardwareBufferManager.h"
  8. #include "BsGpuParamBlockBuffer.h"
  9. #include "BsTechnique.h"
  10. #include "BsPass.h"
  11. #include "BsRenderSystem.h"
  12. namespace BansheeEngine
  13. {
  14. LitTexRenderableHandler::LitTexRenderableHandler()
  15. {
  16. defaultShader = createDefaultShader();
  17. TechniquePtr defaultTechnique = defaultShader->getBestTechnique();
  18. PassPtr defaultPass = defaultTechnique->getPass(0);
  19. bool matrixTranspose = defaultPass->getVertexProgram()->requiresMatrixTranspose(); // Only need this from first vertex program as this is a static setting across all GPU programs
  20. GpuParamDescPtr vertParamDesc = defaultPass->getVertexProgram()->getParamDesc();
  21. GpuParamDescPtr fragParamDesc = defaultPass->getFragmentProgram()->getParamDesc();
  22. GpuParamDescPtr staticParamsDesc = bs_shared_ptr<GpuParamDesc>();
  23. GpuParamDescPtr perFrameParamsDesc = bs_shared_ptr<GpuParamDesc>();
  24. GpuParamDescPtr perObjectParamsDesc = bs_shared_ptr<GpuParamDesc>();
  25. bool foundLightDir = false;
  26. bool foundTime = false;
  27. bool foundWVP = false;
  28. bool foundStatic = false;
  29. bool foundPerFrame = false;
  30. bool foundPerObject = false;
  31. const Map<String, SHADER_DATA_PARAM_DESC>& dataParams = defaultShader->_getDataParams();
  32. for (auto& param : dataParams)
  33. {
  34. if (!foundLightDir && param.second.rendererSemantic == RPS_LightDir)
  35. {
  36. auto iterFind = fragParamDesc->params.find(param.second.gpuVariableName);
  37. if (iterFind == fragParamDesc->params.end())
  38. continue;
  39. lightDirParamDesc = iterFind->second;
  40. staticParamsDesc->params[iterFind->first] = iterFind->second;
  41. foundLightDir = true;
  42. }
  43. else if (!foundTime && param.second.rendererSemantic == RPS_Time)
  44. {
  45. auto iterFind = vertParamDesc->params.find(param.second.gpuVariableName);
  46. if (iterFind == vertParamDesc->params.end())
  47. continue;
  48. timeParamDesc = iterFind->second;
  49. perFrameParamsDesc->params[iterFind->first] = iterFind->second;
  50. foundTime = true;
  51. }
  52. else if (!foundWVP && param.second.rendererSemantic == RPS_WorldViewProjTfrm)
  53. {
  54. auto iterFind = vertParamDesc->params.find(param.second.gpuVariableName);
  55. if (iterFind == vertParamDesc->params.end())
  56. continue;
  57. wvpParamDesc = iterFind->second;
  58. perObjectParamsDesc->params[iterFind->first] = iterFind->second;
  59. foundWVP = true;
  60. }
  61. }
  62. const Map<String, SHADER_PARAM_BLOCK_DESC>& paramBlocks = defaultShader->_getParamBlocks();
  63. for (auto& block : paramBlocks)
  64. {
  65. if (!foundStatic && block.second.rendererSemantic == RBS_Static)
  66. {
  67. auto iterFind = fragParamDesc->paramBlocks.find(block.second.name);
  68. if (iterFind == fragParamDesc->paramBlocks.end())
  69. continue;
  70. staticParamBlockDesc = iterFind->second;
  71. staticParamsDesc->paramBlocks[iterFind->first] = iterFind->second;
  72. foundStatic = true;
  73. }
  74. else if (!foundPerFrame && block.second.rendererSemantic == RBS_PerFrame)
  75. {
  76. auto iterFind = vertParamDesc->paramBlocks.find(block.second.name);
  77. if (iterFind == vertParamDesc->paramBlocks.end())
  78. continue;
  79. perFrameParamBlockDesc = iterFind->second;
  80. perFrameParamsDesc->paramBlocks[iterFind->first] = iterFind->second;
  81. foundPerFrame = true;
  82. }
  83. else if (!foundPerObject && block.second.rendererSemantic == RBS_PerObject)
  84. {
  85. auto iterFind = vertParamDesc->paramBlocks.find(block.second.name);
  86. if (iterFind == vertParamDesc->paramBlocks.end())
  87. continue;
  88. perObjectParamBlockDesc = iterFind->second;
  89. perObjectParamsDesc->paramBlocks[iterFind->first] = iterFind->second;
  90. foundPerObject = true;
  91. }
  92. }
  93. if (!foundLightDir || !foundTime || !foundWVP || !foundStatic || !foundPerFrame || !foundPerObject)
  94. BS_EXCEPT(InternalErrorException, "Invalid default shader.");
  95. // Create global GPU param buffers and get parameter handles
  96. staticParams = bs_shared_ptr<GpuParams>(staticParamsDesc, matrixTranspose);
  97. perFrameParams = bs_shared_ptr<GpuParams>(perFrameParamsDesc, matrixTranspose);
  98. staticParamBuffer = HardwareBufferManager::instance().createGpuParamBlockBuffer(staticParamBlockDesc.blockSize * sizeof(UINT32));
  99. perFrameParamBuffer = HardwareBufferManager::instance().createGpuParamBlockBuffer(perFrameParamBlockDesc.blockSize * sizeof(UINT32));
  100. staticParams->setParamBlockBuffer(staticParamBlockDesc.slot, staticParamBuffer);
  101. perFrameParams->setParamBlockBuffer(perFrameParamBlockDesc.slot, perFrameParamBuffer);
  102. staticParams->getParam(lightDirParamDesc.name, lightDirParam);
  103. perFrameParams->getParam(timeParamDesc.name, timeParam);
  104. lightDirParam.set(Vector4(0.707f, 0.707f, 0.707f, 0.0f));
  105. }
  106. void LitTexRenderableHandler::initializeProxy(const RenderableProxyPtr& proxy)
  107. {
  108. static auto paramsMatch = [](const GpuParamDataDesc& a, const GpuParamDataDesc& b)
  109. {
  110. return a.gpuMemOffset == b.gpuMemOffset && a.elementSize == b.elementSize &&
  111. a.arraySize == b.arraySize && a.arrayElementStride == b.arrayElementStride;
  112. };
  113. for (auto& element : proxy->renderableElements)
  114. {
  115. element->rendererData = PerObjectData();
  116. PerObjectData* rendererData = any_cast_unsafe<PerObjectData>(&element->rendererData);
  117. ShaderProxyPtr shader = element->material->shader;
  118. const Map<String, SHADER_PARAM_BLOCK_DESC>& paramBlockDescs = shader->paramBlocks;
  119. const Map<String, SHADER_DATA_PARAM_DESC>& dataParamDescs = shader->dataParams;
  120. String staticBlockName;
  121. String perFrameBlockName;
  122. String perObjectBlockName;
  123. String wvpParamName;
  124. for (auto& paramBlockDesc : paramBlockDescs)
  125. {
  126. switch (paramBlockDesc.second.rendererSemantic)
  127. {
  128. case RBS_Static:
  129. staticBlockName = paramBlockDesc.second.name;
  130. break;
  131. case RBS_PerFrame:
  132. perFrameBlockName = paramBlockDesc.second.name;
  133. break;
  134. case RBS_PerObject:
  135. perObjectBlockName = paramBlockDesc.second.name;
  136. break;
  137. }
  138. }
  139. for (auto& paramDesc : dataParamDescs)
  140. {
  141. if (paramDesc.second.rendererSemantic == RPS_WorldViewProjTfrm)
  142. wvpParamName = paramDesc.second.gpuVariableName;
  143. }
  144. UINT32 idx = 0;
  145. for (auto& gpuParams : element->material->params)
  146. {
  147. const GpuParamDesc& paramsDesc = gpuParams->getParamDesc();
  148. if (staticBlockName != "")
  149. {
  150. auto findIter = paramsDesc.paramBlocks.find(staticBlockName);
  151. if (findIter != paramsDesc.paramBlocks.end())
  152. {
  153. // TODO - We only compare block sizes but not actual contents. Should I check them too?
  154. // Probably shouldn't concern myself with that here, instead check that on a higher level.
  155. if (findIter->second.blockSize == staticParamBlockDesc.blockSize)
  156. {
  157. UINT32 slotIdx = findIter->second.slot;
  158. element->material->rendererBuffers.push_back(MaterialProxy::BufferBindInfo(idx, slotIdx, staticParamBuffer));
  159. }
  160. }
  161. }
  162. if (perFrameBlockName != "")
  163. {
  164. auto findIter = paramsDesc.paramBlocks.find(perFrameBlockName);
  165. if (findIter != paramsDesc.paramBlocks.end())
  166. {
  167. if (findIter->second.blockSize == perFrameParamBlockDesc.blockSize)
  168. {
  169. UINT32 slotIdx = findIter->second.slot;
  170. element->material->rendererBuffers.push_back(MaterialProxy::BufferBindInfo(idx, slotIdx, perFrameParamBuffer));
  171. }
  172. }
  173. }
  174. if (perObjectBlockName != "")
  175. {
  176. auto findIter = paramsDesc.paramBlocks.find(perObjectBlockName);
  177. if (findIter != paramsDesc.paramBlocks.end())
  178. {
  179. if (findIter->second.blockSize == perObjectParamBlockDesc.blockSize)
  180. {
  181. if (rendererData->perObjectParamBuffer == nullptr)
  182. rendererData->perObjectParamBuffer = HardwareBufferManager::instance().createGpuParamBlockBuffer(perObjectParamBlockDesc.blockSize * sizeof(UINT32));
  183. rendererData->perObjectBuffers.push_back(MaterialProxy::BufferBindInfo(idx, findIter->second.slot, rendererData->perObjectParamBuffer));
  184. if (!rendererData->hasWVPParam && wvpParamName != "")
  185. {
  186. auto findIter2 = paramsDesc.params.find(wvpParamName);
  187. if (findIter2 != paramsDesc.params.end())
  188. {
  189. if (paramsMatch(findIter2->second, wvpParamDesc))
  190. {
  191. gpuParams->getParam(wvpParamName, rendererData->wvpParam);
  192. rendererData->hasWVPParam = true;
  193. }
  194. }
  195. }
  196. }
  197. }
  198. }
  199. idx++;
  200. }
  201. bindGlobalBuffers(element);
  202. }
  203. }
  204. void LitTexRenderableHandler::bindPerObjectBuffers(const RenderableProxyPtr& renderable, const RenderableElement* element)
  205. {
  206. if (renderable->renderableType != RenType_LitTextured)
  207. return;
  208. const PerObjectData* rendererData = any_cast_unsafe<PerObjectData>(&element->rendererData);
  209. for (auto& perObjectBuffer : rendererData->perObjectBuffers)
  210. {
  211. GpuParamsPtr params = element->material->params[perObjectBuffer.paramsIdx];
  212. params->setParamBlockBuffer(perObjectBuffer.slotIdx, rendererData->perObjectParamBuffer);
  213. }
  214. }
  215. void LitTexRenderableHandler::updateGlobalBuffers(float time)
  216. {
  217. timeParam.set(time);
  218. staticParams->updateHardwareBuffers();
  219. perFrameParams->updateHardwareBuffers();
  220. }
  221. void LitTexRenderableHandler::updatePerObjectBuffers(RenderableElement* element, const Matrix4& wvpMatrix)
  222. {
  223. PerObjectData* rendererData = any_cast_unsafe<PerObjectData>(&element->rendererData);
  224. if (rendererData->hasWVPParam)
  225. rendererData->wvpParam.set(wvpMatrix);
  226. if (rendererData->perObjectParamBuffer != nullptr)
  227. {
  228. GpuParamBlockPtr paramBlock = rendererData->perObjectParamBuffer->getParamBlock();
  229. if (paramBlock->isDirty())
  230. paramBlock->uploadToBuffer(rendererData->perObjectParamBuffer);
  231. }
  232. }
  233. ShaderPtr LitTexRenderableHandler::createDefaultShader()
  234. {
  235. String rsName = RenderSystem::instance().getName();
  236. HGpuProgram vsProgram;
  237. HGpuProgram psProgram;
  238. if (rsName == RenderSystemDX11)
  239. {
  240. String vsCode = R"(
  241. cbuffer PerFrame
  242. {
  243. float time;
  244. }
  245. cbuffer PerObject
  246. {
  247. float4x4 matWorldViewProj;
  248. }
  249. void vs_main(in float3 inPos : POSITION,
  250. out float4 oPosition : SV_Position)
  251. {
  252. oPosition = mul(matWorldViewProj, float4(inPos.xyz + float3(sin(time), 0, 0), 1));
  253. })";
  254. String psCode = R"(
  255. cbuffer Static
  256. {
  257. float4 lightDir;
  258. }
  259. float4 ps_main() : SV_Target
  260. {
  261. return dot(lightDir, float4(0.5f, 0.5f, 0.5f, 0.5f));
  262. })";
  263. vsProgram = GpuProgram::create(vsCode, "vs_main", "hlsl", GPT_VERTEX_PROGRAM, GPP_VS_4_0);
  264. psProgram = GpuProgram::create(psCode, "ps_main", "hlsl", GPT_FRAGMENT_PROGRAM, GPP_PS_4_0);
  265. }
  266. else if (rsName == RenderSystemDX9)
  267. {
  268. String vsCode = R"(
  269. BS_PARAM_BLOCK PerFrame { time }
  270. BS_PARAM_BLOCK PerObject { matWorldViewProj }
  271. float time;
  272. float4x4 matWorldViewProj;
  273. void vs_main(in float3 inPos : POSITION,
  274. out float4 oPosition : POSITION)
  275. {
  276. oPosition = mul(matWorldViewProj, float4(inPos.xyz + float3(sin(time), 0, 0), 1));
  277. })";
  278. String psCode = R"(
  279. BS_PARAM_BLOCK Static { lightDir }
  280. float4 lightDir;
  281. float4 ps_main() : COLOR0
  282. {
  283. return dot(lightDir, float4(0.5f, 0.5f, 0.5f, 0.5f));
  284. })";
  285. vsProgram = GpuProgram::create(vsCode, "vs_main", "hlsl", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
  286. psProgram = GpuProgram::create(psCode, "ps_main", "hlsl", GPT_FRAGMENT_PROGRAM, GPP_PS_2_0);
  287. }
  288. else if (rsName == RenderSystemOpenGL)
  289. {
  290. String vsCode = R"(#version 400
  291. uniform PerFrame
  292. {
  293. float time;
  294. };
  295. uniform PerObject
  296. {
  297. mat4 matWorldViewProj;
  298. };
  299. in vec3 bs_position;
  300. void main()
  301. {
  302. gl_Position = matWorldViewProj * vec4(bs_position.xyz + vec3(sin(time), 0, 0), 1);
  303. })";
  304. String psCode = R"(#version 400
  305. uniform Static
  306. {
  307. vec4 lightDir;
  308. };
  309. out vec4 fragColor;
  310. void main()
  311. {
  312. fragColor = lightDir * vec4(0.5f, 0.5f, 0.5f, 0.5f);
  313. })";
  314. vsProgram = GpuProgram::create(vsCode, "main", "glsl", GPT_VERTEX_PROGRAM, GPP_VS_4_0);
  315. psProgram = GpuProgram::create(psCode, "main", "glsl", GPT_FRAGMENT_PROGRAM, GPP_PS_4_0);
  316. }
  317. vsProgram.synchronize();
  318. psProgram.synchronize();
  319. ShaderPtr defaultShader = Shader::create("LitTexDefault");
  320. defaultShader->setParamBlockAttribs("Static", true, GPBU_DYNAMIC, RBS_Static);
  321. defaultShader->setParamBlockAttribs("PerFrame", true, GPBU_DYNAMIC, RBS_PerFrame);
  322. defaultShader->setParamBlockAttribs("PerObject", true, GPBU_DYNAMIC, RBS_PerObject);
  323. defaultShader->addParameter("lightDir", "lightDir", GPDT_FLOAT4, RPS_LightDir);
  324. defaultShader->addParameter("time", "time", GPDT_FLOAT1, RPS_Time);
  325. defaultShader->addParameter("matWorldViewProj", "matWorldViewProj", GPDT_MATRIX_4X4, RPS_WorldViewProjTfrm);
  326. TechniquePtr newTechnique = defaultShader->addTechnique(rsName, RendererDefault);
  327. PassPtr newPass = newTechnique->addPass();
  328. newPass->setVertexProgram(vsProgram);
  329. newPass->setFragmentProgram(psProgram);
  330. return defaultShader;
  331. }
  332. }