#include "BsMaterial.h" #include "BsException.h" #include "BsShader.h" #include "BsTechnique.h" #include "BsPass.h" #include "BsRenderAPI.h" #include "BsHardwareBufferManager.h" #include "BsGpuProgram.h" #include "BsGpuParamBlockBuffer.h" #include "BsGpuParamDesc.h" #include "BsMaterialRTTI.h" #include "BsMaterialManager.h" #include "BsDebug.h" #include "BsResources.h" #include "BsFrameAlloc.h" namespace BansheeEngine { struct ShaderBlockDesc { String name; GpuParamBlockUsage usage; int size; bool create; }; SPtr convertParamsToCore(const SPtr& passParams) { SPtr passParameters = bs_shared_ptr(); if (passParams->mVertParams != nullptr) passParameters->mVertParams = passParams->mVertParams->getCore(); else passParameters->mVertParams = nullptr; if (passParams->mFragParams != nullptr) passParameters->mFragParams = passParams->mFragParams->getCore(); else passParameters->mFragParams = nullptr; if (passParams->mGeomParams != nullptr) passParameters->mGeomParams = passParams->mGeomParams->getCore(); else passParameters->mGeomParams = nullptr; if (passParams->mHullParams != nullptr) passParameters->mHullParams = passParams->mHullParams->getCore(); else passParameters->mHullParams = nullptr; if (passParams->mDomainParams != nullptr) passParameters->mDomainParams = passParams->mDomainParams->getCore(); else passParameters->mDomainParams = nullptr; if (passParams->mComputeParams != nullptr) passParameters->mComputeParams = passParams->mComputeParams->getCore(); else passParameters->mComputeParams = nullptr; return passParameters; } bool areParamsEqual(const GpuParamDataDesc& paramA, const GpuParamDataDesc& paramB, bool ignoreBufferOffsets) { bool equal = paramA.arraySize == paramB.arraySize && paramA.elementSize == paramB.elementSize && paramA.type == paramB.type && paramA.arrayElementStride == paramB.arrayElementStride; if (!ignoreBufferOffsets) equal &= paramA.cpuMemOffset == paramB.cpuMemOffset && paramA.gpuMemOffset == paramB.gpuMemOffset; return equal; } Map determineValidDataParameters(const Vector& paramDescs) { Map foundDataParams; Map validParams; for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter) { const GpuParamDesc& curDesc = **iter; // Check regular data params for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2) { bool isParameterValid = true; const GpuParamDataDesc& curParam = iter2->second; auto dataFindIter = validParams.find(iter2->first); if (dataFindIter == validParams.end()) { validParams[iter2->first] = true; foundDataParams[iter2->first] = &curParam; } else { if (validParams[iter2->first]) { auto dataFindIter2 = foundDataParams.find(iter2->first); const GpuParamDataDesc* otherParam = dataFindIter2->second; if (!areParamsEqual(curParam, *otherParam, true)) { validParams[iter2->first] = false; foundDataParams.erase(dataFindIter2); } } } } } return foundDataParams; } Vector determineValidObjectParameters(const Vector& paramDescs) { Vector validParams; for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter) { const GpuParamDesc& curDesc = **iter; // Check sampler params for (auto iter2 = curDesc.samplers.begin(); iter2 != curDesc.samplers.end(); ++iter2) { validParams.push_back(&iter2->second); } // Check texture params for (auto iter2 = curDesc.textures.begin(); iter2 != curDesc.textures.end(); ++iter2) { validParams.push_back(&iter2->second); } // Check buffer params for (auto iter2 = curDesc.buffers.begin(); iter2 != curDesc.buffers.end(); ++iter2) { validParams.push_back(&iter2->second); } } return validParams; } Set determineValidShareableParamBlocks(const Vector& paramDescs) { // Make sure param blocks with the same name actually are the same Map> uniqueParamBlocks; Map validParamBlocks; for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter) { const GpuParamDesc& curDesc = **iter; for (auto blockIter = curDesc.paramBlocks.begin(); blockIter != curDesc.paramBlocks.end(); ++blockIter) { bool isBlockValid = true; const GpuParamBlockDesc& curBlock = blockIter->second; if (!curBlock.isShareable) // Non-shareable buffers are handled differently, they're allowed same names continue; auto iterFind = uniqueParamBlocks.find(blockIter->first); if (iterFind == uniqueParamBlocks.end()) { uniqueParamBlocks[blockIter->first] = std::make_pair(blockIter->first, *iter); validParamBlocks[blockIter->first] = true; continue; } String otherBlockName = iterFind->second.first; GpuParamDescPtr otherDesc = iterFind->second.second; for (auto myParamIter = curDesc.params.begin(); myParamIter != curDesc.params.end(); ++myParamIter) { const GpuParamDataDesc& myParam = myParamIter->second; if (myParam.paramBlockSlot != curBlock.slot) continue; // Param is in another block, so we will check it when its time for that block auto otherParamFind = otherDesc->params.find(myParamIter->first); // Cannot find other param, blocks aren't equal if (otherParamFind == otherDesc->params.end()) { isBlockValid = false; break; } const GpuParamDataDesc& otherParam = otherParamFind->second; if (!areParamsEqual(myParam, otherParam, false) || curBlock.name != otherBlockName) { isBlockValid = false; break; } } if (!isBlockValid) { if (validParamBlocks[blockIter->first]) { LOGWRN("Found two param blocks with the same name but different contents: " + blockIter->first); validParamBlocks[blockIter->first] = false; } } } } Set validParamBlocksReturn; for (auto iter = validParamBlocks.begin(); iter != validParamBlocks.end(); ++iter) { if (iter->second) validParamBlocksReturn.insert(iter->first); } return validParamBlocksReturn; } Map determineParameterToBlockMapping(const Vector& paramDescs) { Map paramToParamBlock; for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter) { const GpuParamDesc& curDesc = **iter; for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2) { const GpuParamDataDesc& curParam = iter2->second; auto iterFind = paramToParamBlock.find(curParam.name); if (iterFind != paramToParamBlock.end()) continue; for (auto iterBlock = curDesc.paramBlocks.begin(); iterBlock != curDesc.paramBlocks.end(); ++iterBlock) { if (iterBlock->second.slot == curParam.paramBlockSlot) { paramToParamBlock[curParam.name] = iterBlock->second.name; break; } } } } return paramToParamBlock; } Map determineParamMappings(const Vector& paramDescs, const Map& dataParams, const Map& objectParam) { Map validParams; Map validDataParameters = determineValidDataParameters(paramDescs); Vector validObjectParameters = determineValidObjectParameters(paramDescs); Map paramToParamBlockMap = determineParameterToBlockMapping(paramDescs); // Create data param mappings for (auto iter = dataParams.begin(); iter != dataParams.end(); ++iter) { auto findIter = validDataParameters.find(iter->second.gpuVariableName); // Not valid so we skip it if (findIter == validDataParameters.end()) continue; if (findIter->second->type != iter->second.type) { LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Type doesn't match the one defined in the gpu program. " + "Shader defined type: " + toString(iter->second.type) + " - Gpu program defined type: " + toString(findIter->second->type)); continue; } if (findIter->second->arraySize != iter->second.arraySize) { LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Array size doesn't match the one defined in the gpu program." + "Shader defined array size: " + toString(iter->second.arraySize) + " - Gpu program defined array size: " + toString(findIter->second->arraySize)); continue; } auto findBlockIter = paramToParamBlockMap.find(iter->second.gpuVariableName); if (findBlockIter == paramToParamBlockMap.end()) BS_EXCEPT(InternalErrorException, "Parameter doesn't exist in param to param block map but exists in valid param map."); String& paramBlockName = findBlockIter->second; validParams[iter->first] = iter->second.gpuVariableName; } // Create object param mappings for (auto iter = objectParam.begin(); iter != objectParam.end(); ++iter) { const Vector& gpuVariableNames = iter->second.gpuVariableNames; for (auto iter2 = gpuVariableNames.begin(); iter2 != gpuVariableNames.end(); ++iter2) { for (auto iter3 = validObjectParameters.begin(); iter3 != validObjectParameters.end(); ++iter3) { if ((*iter3)->name == (*iter2) && (*iter3)->type == iter->second.type) { validParams[iter->first] = *iter2; break; } } } } return validParams; } Vector determineShaderBlockData(const Set& paramBlocks, const Vector& paramDescs, const Map& shaderDesc) { Vector output; for (auto iter = paramBlocks.begin(); iter != paramBlocks.end(); ++iter) { ShaderBlockDesc shaderBlockDesc; shaderBlockDesc.create = true; shaderBlockDesc.usage = GPBU_STATIC; shaderBlockDesc.size = 0; shaderBlockDesc.name = *iter; auto iterFind = shaderDesc.find(*iter); if (iterFind != shaderDesc.end()) { shaderBlockDesc.create = !iterFind->second.shared && iterFind->second.rendererSemantic == 0; shaderBlockDesc.usage = iterFind->second.usage; } for (auto iter2 = paramDescs.begin(); iter2 != paramDescs.end(); ++iter2) { auto findParamBlockDesc = (*iter2)->paramBlocks.find(*iter); if (findParamBlockDesc != (*iter2)->paramBlocks.end()) { shaderBlockDesc.size = findParamBlockDesc->second.blockSize * sizeof(UINT32); break; } } output.push_back(shaderBlockDesc); } return output; } Vector MaterialBase::getAllParamDescs(const SPtr& technique) { Vector allParamDescs; // Make sure all gpu programs are fully loaded for (UINT32 i = 0; i < technique->getNumPasses(); i++) { PassPtr curPass = technique->getPass(i); HGpuProgram vertProgram = curPass->getVertexProgram(); if (vertProgram) { vertProgram.blockUntilLoaded(); vertProgram->blockUntilCoreInitialized(); allParamDescs.push_back(vertProgram->getParamDesc()); } HGpuProgram fragProgram = curPass->getFragmentProgram(); if (fragProgram) { fragProgram.blockUntilLoaded(); fragProgram->blockUntilCoreInitialized(); allParamDescs.push_back(fragProgram->getParamDesc()); } HGpuProgram geomProgram = curPass->getGeometryProgram(); if (geomProgram) { geomProgram.blockUntilLoaded(); geomProgram->blockUntilCoreInitialized(); allParamDescs.push_back(geomProgram->getParamDesc()); } HGpuProgram hullProgram = curPass->getHullProgram(); if (hullProgram) { hullProgram.blockUntilLoaded(); hullProgram->blockUntilCoreInitialized(); allParamDescs.push_back(hullProgram->getParamDesc()); } HGpuProgram domainProgram = curPass->getDomainProgram(); if (domainProgram) { domainProgram.blockUntilLoaded(); domainProgram->blockUntilCoreInitialized(); allParamDescs.push_back(domainProgram->getParamDesc()); } HGpuProgram computeProgram = curPass->getComputeProgram(); if (computeProgram) { computeProgram.blockUntilLoaded(); computeProgram->blockUntilCoreInitialized(); allParamDescs.push_back(computeProgram->getParamDesc()); } } return allParamDescs; } Vector MaterialBase::getAllParamDescs(const SPtr& technique) { Vector allParamDescs; // Make sure all gpu programs are fully loaded for (UINT32 i = 0; i < technique->getNumPasses(); i++) { SPtr curPass = technique->getPass(i); SPtr vertProgram = curPass->getVertexProgram(); if (vertProgram) allParamDescs.push_back(vertProgram->getParamDesc()); SPtr fragProgram = curPass->getFragmentProgram(); if (fragProgram) allParamDescs.push_back(fragProgram->getParamDesc()); SPtr geomProgram = curPass->getGeometryProgram(); if (geomProgram) allParamDescs.push_back(geomProgram->getParamDesc()); SPtr hullProgram = curPass->getHullProgram(); if (hullProgram) allParamDescs.push_back(hullProgram->getParamDesc()); SPtr domainProgram = curPass->getDomainProgram(); if (domainProgram) allParamDescs.push_back(domainProgram->getParamDesc()); SPtr computeProgram = curPass->getComputeProgram(); if (computeProgram) allParamDescs.push_back(computeProgram->getParamDesc()); } return allParamDescs; } template void TMaterial::setShader(ShaderType shader) { mShader = shader; initBestTechnique(); _markCoreDirty(); } template UINT32 TMaterial::getNumPasses() const { throwIfNotInitialized(); return mShader->getBestTechnique()->getNumPasses(); } template typename TMaterial::PassType TMaterial::getPass(UINT32 passIdx) const { if (passIdx < 0 || passIdx >= mShader->getBestTechnique()->getNumPasses()) BS_EXCEPT(InvalidParametersException, "Invalid pass index."); return mShader->getBestTechnique()->getPass(passIdx); } template TMaterialParamStruct TMaterial::getParamStruct(const String& name) const { throwIfNotInitialized(); auto iterFind = mValidParams.find(name); if (iterFind == mValidParams.end()) { LOGWRN("Material doesn't have a parameter named " + name); return TMaterialParamStruct(); } const String& gpuVarName = iterFind->second; Vector> gpuParams; for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter) { SPtr> params = *iter; for (UINT32 i = 0; i < params->getNumParams(); i++) { GpuParamsType& paramPtr = params->getParamByIdx(i); if (paramPtr) { if (paramPtr->hasParam(gpuVarName)) { gpuParams.push_back(TGpuParamStruct()); paramPtr->getStructParam(gpuVarName, gpuParams.back()); } } } } return TMaterialParamStruct(gpuParams); } template TMaterialParamTexture TMaterial::getParamTexture(const String& name) const { throwIfNotInitialized(); auto iterFind = mValidParams.find(name); if (iterFind == mValidParams.end()) { LOGWRN("Material doesn't have a parameter named " + name); return TMaterialParamTexture(); } const String& gpuVarName = iterFind->second; Vector> gpuParams; for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter) { SPtr> params = *iter; for (UINT32 i = 0; i < params->getNumParams(); i++) { GpuParamsType& paramPtr = params->getParamByIdx(i); if (paramPtr) { if (paramPtr->hasTexture(gpuVarName)) { gpuParams.push_back(TGpuParamTexture()); paramPtr->getTextureParam(gpuVarName, gpuParams.back()); } } } } return TMaterialParamTexture(gpuParams); } template TMaterialParamLoadStoreTexture TMaterial::getParamLoadStoreTexture(const String& name) const { throwIfNotInitialized(); auto iterFind = mValidParams.find(name); if (iterFind == mValidParams.end()) { LOGWRN("Material doesn't have a parameter named " + name); return TMaterialParamLoadStoreTexture(); } const String& gpuVarName = iterFind->second; Vector> gpuParams; for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter) { SPtr> params = *iter; for (UINT32 i = 0; i < params->getNumParams(); i++) { GpuParamsType& paramPtr = params->getParamByIdx(i); if (paramPtr) { if (paramPtr->hasTexture(gpuVarName)) { gpuParams.push_back(TGpuParamLoadStoreTexture()); paramPtr->getLoadStoreTextureParam(gpuVarName, gpuParams.back()); } } } } return TMaterialParamLoadStoreTexture(gpuParams); } template TMaterialParamSampState TMaterial::getParamSamplerState(const String& name) const { throwIfNotInitialized(); auto iterFind = mValidParams.find(name); if (iterFind == mValidParams.end()) { LOGWRN("Material doesn't have a parameter named " + name); return TMaterialParamSampState(); } const String& gpuVarName = iterFind->second; Vector> gpuParams; for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter) { SPtr> params = *iter; for (UINT32 i = 0; i < params->getNumParams(); i++) { GpuParamsType& paramPtr = params->getParamByIdx(i); if (paramPtr) { if (paramPtr->hasSamplerState(gpuVarName)) { gpuParams.push_back(TGpuParamSampState()); paramPtr->getSamplerStateParam(gpuVarName, gpuParams.back()); } } } } return TMaterialParamSampState(gpuParams); } template void TMaterial::setParamBlockBuffer(const String& name, const ParamBlockPtrType& paramBlock) { auto iterFind = mValidShareableParamBlocks.find(name); if (iterFind == mValidShareableParamBlocks.end()) { LOGWRN("Material doesn't have a parameter block named " + name); return; } for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter) { SPtr> params = *iter; for (UINT32 i = 0; i < params->getNumParams(); i++) { GpuParamsType& paramPtr = params->getParamByIdx(i); if (paramPtr) { if (paramPtr->hasParamBlock(name)) paramPtr->setParamBlockBuffer(name, paramBlock); } } } } template void TMaterial::initBestTechnique() { mBestTechnique = nullptr; mParametersPerPass.clear(); if (mShader) { mBestTechnique = mShader->getBestTechnique(); if (mBestTechnique == nullptr) return; mValidShareableParamBlocks.clear(); Vector allParamDescs = getAllParamDescs(mBestTechnique); mValidParams = determineParamMappings(allParamDescs, mShader->getDataParams(), mShader->getObjectParams()); // Fill out various helper structures Set validShareableParamBlocks = determineValidShareableParamBlocks(allParamDescs); Vector paramBlockData = determineShaderBlockData(validShareableParamBlocks, allParamDescs, mShader->getParamBlocks()); Map paramBlockBuffers; // Create param blocks for (auto& paramBlock : paramBlockData) { ParamBlockPtrType newParamBlockBuffer; if (paramBlock.create) { newParamBlockBuffer = ParamBlockType::create(paramBlock.size, paramBlock.usage); } paramBlockBuffers[paramBlock.name] = newParamBlockBuffer; mValidShareableParamBlocks.insert(paramBlock.name); } for (UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++) { PassType curPass = mBestTechnique->getPass(i); SPtr> params = SPtr>(new TPassParameters()); GpuProgramType vertProgram = curPass->getVertexProgram(); if (vertProgram) params->mVertParams = vertProgram->createParameters(); GpuProgramType fragProgram = curPass->getFragmentProgram(); if (fragProgram) params->mFragParams = fragProgram->createParameters(); GpuProgramType geomProgram = curPass->getGeometryProgram(); if (geomProgram) params->mGeomParams = geomProgram->createParameters(); GpuProgramType hullProgram = curPass->getHullProgram(); if (hullProgram) params->mHullParams = hullProgram->createParameters(); GpuProgramType domainProgram = curPass->getDomainProgram(); if (domainProgram) params->mDomainParams = domainProgram->createParameters(); GpuProgramType computeProgram = curPass->getComputeProgram(); if (computeProgram) params->mComputeParams = computeProgram->createParameters(); mParametersPerPass.push_back(params); } // Assign param block buffers for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter) { SPtr> params = *iter; for (UINT32 i = 0; i < params->getNumParams(); i++) { GpuParamsType& paramPtr = params->getParamByIdx(i); if (paramPtr) { // Assign shareable buffers for (auto iterBlock = mValidShareableParamBlocks.begin(); iterBlock != mValidShareableParamBlocks.end(); ++iterBlock) { const String& paramBlockName = *iterBlock; if (paramPtr->hasParamBlock(paramBlockName)) { ParamBlockPtrType blockBuffer = paramBlockBuffers[paramBlockName]; paramPtr->setParamBlockBuffer(paramBlockName, blockBuffer); } } // Create non-shareable ones const GpuParamDesc& desc = paramPtr->getParamDesc(); for (auto iterBlockDesc = desc.paramBlocks.begin(); iterBlockDesc != desc.paramBlocks.end(); ++iterBlockDesc) { if (!iterBlockDesc->second.isShareable) { ParamBlockPtrType newParamBlockBuffer = ParamBlockType::create(iterBlockDesc->second.blockSize * sizeof(UINT32)); paramPtr->setParamBlockBuffer(iterBlockDesc->first, newParamBlockBuffer); } } } } } } } template template void TMaterial::getParam(const String& name, TMaterialDataParam& output) const { throwIfNotInitialized(); auto iterFind = mValidParams.find(name); if (iterFind == mValidParams.end()) { LOGWRN("Material doesn't have a parameter named " + name); return; } const String& gpuVarName = iterFind->second; Vector> gpuParams; for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter) { SPtr> params = *iter; for (UINT32 i = 0; i < params->getNumParams(); i++) { GpuParamsType& paramPtr = params->getParamByIdx(i); if (paramPtr) { if (paramPtr->hasParam(gpuVarName)) { gpuParams.push_back(TGpuDataParam()); paramPtr->getParam(gpuVarName, gpuParams.back()); } } } } output = TMaterialDataParam(gpuParams); } template void TMaterial::throwIfNotInitialized() const { if (mShader == nullptr) { BS_EXCEPT(InternalErrorException, "Material does not have shader set."); } if (mBestTechnique == nullptr) { BS_EXCEPT(InternalErrorException, "Shader does not contain a supported technique."); } } template class TMaterial < false > ; template class TMaterial < true > ; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; template BS_CORE_EXPORT void TMaterial::getParam(const String&, TMaterialDataParam&) const; MaterialCore::MaterialCore(const SPtr& shader) { setShader(shader); } MaterialCore::MaterialCore(const SPtr& shader, const SPtr& bestTechnique, const Set& validShareableParamBlocks, const Map& validParams, const Vector>& passParams) { mShader = shader; mBestTechnique = bestTechnique; mValidShareableParamBlocks = validShareableParamBlocks; mValidParams = validParams; mParametersPerPass = passParams; } void MaterialCore::syncToCore(const CoreSyncData& data) { char* dataPtr = (char*)data.getBuffer(); mValidShareableParamBlocks.clear(); mValidParams.clear(); mParametersPerPass.clear(); UINT32 numPasses = 0; dataPtr = rttiReadElem(mValidShareableParamBlocks, dataPtr); dataPtr = rttiReadElem(mValidParams, dataPtr); dataPtr = rttiReadElem(numPasses, dataPtr); for (UINT32 i = 0; i < numPasses; i++) { SPtr* passParameters = (SPtr*)dataPtr; mParametersPerPass.push_back(*passParameters); passParameters->~SPtr(); dataPtr += sizeof(SPtr); } SPtr* shader = (SPtr*)dataPtr; mShader = *shader; shader->~SPtr(); dataPtr += sizeof(SPtr); SPtr* technique = (SPtr*)dataPtr; mBestTechnique = *technique; technique->~SPtr(); dataPtr += sizeof(SPtr); } SPtr MaterialCore::create(const SPtr& shader) { MaterialCore* material = new (bs_alloc()) MaterialCore(shader); SPtr materialPtr = bs_shared_ptr(material); materialPtr->_setThisPtr(materialPtr); materialPtr->initialize(); return materialPtr; } Material::Material(const ShaderPtr& shader) { setShader(shader); } void Material::_markCoreDirty() { markCoreDirty(); } SPtr Material::getCore() const { return std::static_pointer_cast(mCoreSpecific); } SPtr Material::createCore() const { MaterialCore* material = nullptr; SPtr shader; if (mShader != nullptr) { shader = mShader->getCore(); if (mBestTechnique != nullptr) { SPtr technique = mBestTechnique->getCore(); Vector> passParams; for (auto& passParam : mParametersPerPass) passParams.push_back(convertParamsToCore(passParam)); material = new (bs_alloc()) MaterialCore(shader, technique, mValidShareableParamBlocks, mValidParams, passParams); } } if (material == nullptr) material = new (bs_alloc()) MaterialCore(shader); SPtr materialPtr = bs_shared_ptr(material); materialPtr->_setThisPtr(materialPtr); return materialPtr; } CoreSyncData Material::syncToCore(FrameAlloc* allocator) { UINT32 numPasses = (UINT32)mParametersPerPass.size(); UINT32 size = sizeof(UINT32) + numPasses * sizeof(SPtr) + sizeof(SPtr) + sizeof(SPtr) + rttiGetElemSize(mValidShareableParamBlocks) + rttiGetElemSize(mValidParams); UINT8* buffer = allocator->alloc(size); char* dataPtr = (char*)buffer; dataPtr = rttiWriteElem(mValidShareableParamBlocks, dataPtr); dataPtr = rttiWriteElem(mValidParams, dataPtr); dataPtr = rttiWriteElem(numPasses, dataPtr); for (UINT32 i = 0; i < numPasses; i++) { SPtr* passParameters = new (dataPtr) SPtr(); *passParameters = convertParamsToCore(mParametersPerPass[i]); dataPtr += sizeof(SPtr); } SPtr* shader = new (dataPtr)SPtr(); if (mShader != nullptr) *shader = mShader->getCore(); else *shader = nullptr; dataPtr += sizeof(SPtr); SPtr* technique = new (dataPtr)SPtr(); if (mBestTechnique != nullptr) *technique = mBestTechnique->getCore(); else *technique = nullptr; dataPtr += sizeof(SPtr); return CoreSyncData(buffer, size); } HMaterial Material::create() { MaterialPtr materialPtr = MaterialManager::instance().create(); return static_resource_cast(gResources()._createResourceHandle(materialPtr)); } HMaterial Material::create(ShaderPtr shader) { MaterialPtr materialPtr = MaterialManager::instance().create(shader); return static_resource_cast(gResources()._createResourceHandle(materialPtr)); } RTTITypeBase* Material::getRTTIStatic() { return MaterialRTTI::instance(); } RTTITypeBase* Material::getRTTI() const { return Material::getRTTIStatic(); } }