BsBansheeLitTexRenderableHandler.cpp 13 KB

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