| 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 "BsSamplerOverrides.h" | 
| 4 | #include "BsRenderBeastOptions.h" | 
| 5 | #include "Material/BsMaterial.h" | 
| 6 | #include "RenderAPI/BsGpuParams.h" | 
| 7 | #include "Material/BsGpuParamsSet.h" | 
| 8 | #include "RenderAPI/BsGpuParamDesc.h" | 
| 9 | #include "Material/BsMaterialParams.h" | 
| 10 | #include "RenderAPI/BsSamplerState.h" | 
| 11 | #include "Managers/BsRenderStateManager.h" | 
| 12 |  | 
| 13 | namespace bs { namespace ct | 
| 14 | { | 
| 15 | 	MaterialSamplerOverrides* SamplerOverrideUtility::generateSamplerOverrides(const SPtr<Shader>& shader,  | 
| 16 | 		const SPtr<MaterialParams>& params, const SPtr<GpuParamsSet>& paramsSet,  | 
| 17 | 		const SPtr<RenderBeastOptions>& options) | 
| 18 | 	{ | 
| 19 | 		MaterialSamplerOverrides* output = nullptr; | 
| 20 |  | 
| 21 | 		if (shader == nullptr) | 
| 22 | 			return nullptr; | 
| 23 |  | 
| 24 | 		bs_frame_mark(); | 
| 25 | 		{ | 
| 26 | 			// Generate a list of all sampler state overrides | 
| 27 | 			FrameUnorderedMap<String, UINT32> overrideLookup; | 
| 28 | 			Vector<SamplerOverride> overrides; | 
| 29 |  | 
| 30 | 			auto& samplerParams = shader->getSamplerParams(); | 
| 31 | 			for(auto& samplerParam : samplerParams) | 
| 32 | 			{ | 
| 33 | 				UINT32 paramIdx; | 
| 34 | 				auto result = params->getParamIndex(samplerParam.first, MaterialParams::ParamType::Sampler, GPDT_UNKNOWN,  | 
| 35 | 					0, paramIdx); | 
| 36 |  | 
| 37 | 				// Parameter shouldn't be in the valid parameter list if it cannot be found | 
| 38 | 				assert(result == MaterialParams::GetParamResult::Success); | 
| 39 | 				const MaterialParamsBase::ParamData* materialParamData = params->getParamData(paramIdx); | 
| 40 |  | 
| 41 | 				UINT32 overrideIdx = (UINT32)overrides.size(); | 
| 42 | 				overrides.push_back(SamplerOverride()); | 
| 43 | 				SamplerOverride& override = overrides.back(); | 
| 44 |  | 
| 45 | 				SPtr<SamplerState> samplerState; | 
| 46 | 				params->getSamplerState(*materialParamData, samplerState); | 
| 47 |  | 
| 48 | 				if (samplerState == nullptr) | 
| 49 | 					samplerState = SamplerState::getDefault(); | 
| 50 |  | 
| 51 | 				override.paramIdx = paramIdx; | 
| 52 | 				 | 
| 53 | 				if (checkNeedsOverride(samplerState, options)) | 
| 54 | 					override.state = generateSamplerOverride(samplerState, options); | 
| 55 | 				else | 
| 56 | 					override.state = samplerState; | 
| 57 |  | 
| 58 | 				override.originalStateHash = override.state->getProperties().getHash(); | 
| 59 |  | 
| 60 | 				for (auto& entry : samplerParam.second.gpuVariableNames) | 
| 61 | 					overrideLookup[entry] = overrideIdx; | 
| 62 | 			} | 
| 63 |  | 
| 64 | 			UINT32 numPasses = paramsSet->getNumPasses(); | 
| 65 |  | 
| 66 | 			// First pass just determine if we even need to override and count the number of sampler states | 
| 67 | 			UINT32* numSetsPerPass = (UINT32*)bs_stack_alloc<UINT32>(numPasses); | 
| 68 | 			memset(numSetsPerPass, 0, sizeof(UINT32) * numPasses); | 
| 69 |  | 
| 70 | 			UINT32 totalNumSets = 0; | 
| 71 | 			for (UINT32 i = 0; i < numPasses; i++) | 
| 72 | 			{ | 
| 73 | 				UINT32 maxSamplerSet = 0; | 
| 74 |  | 
| 75 | 				SPtr<GpuParams> paramsPtr = paramsSet->getGpuParams(i); | 
| 76 | 				for (UINT32 j = 0; j < GpuParamsSet::NUM_STAGES; j++) | 
| 77 | 				{ | 
| 78 | 					GpuProgramType progType = (GpuProgramType)j; | 
| 79 | 					SPtr<GpuParamDesc> paramDesc = paramsPtr->getParamDesc(progType); | 
| 80 | 					if (paramDesc == nullptr) | 
| 81 | 						continue; | 
| 82 |  | 
| 83 | 					for (auto iter = paramDesc->samplers.begin(); iter != paramDesc->samplers.end(); ++iter) | 
| 84 | 					{ | 
| 85 | 						UINT32 set = iter->second.set; | 
| 86 | 						maxSamplerSet = std::max(maxSamplerSet, set + 1); | 
| 87 | 					} | 
| 88 | 				} | 
| 89 |  | 
| 90 | 				numSetsPerPass[i] = maxSamplerSet; | 
| 91 | 				totalNumSets += maxSamplerSet; | 
| 92 | 			} | 
| 93 | 			 | 
| 94 | 			UINT32 totalNumSamplerStates = 0; | 
| 95 | 			UINT32* slotsPerSet = (UINT32*)bs_stack_alloc<UINT32>(totalNumSets); | 
| 96 | 			memset(slotsPerSet, 0, sizeof(UINT32) * totalNumSets); | 
| 97 |  | 
| 98 | 			UINT32* slotsPerSetIter = slotsPerSet; | 
| 99 | 			for (UINT32 i = 0; i < numPasses; i++) | 
| 100 | 			{ | 
| 101 | 				SPtr<GpuParams> paramsPtr = paramsSet->getGpuParams(i); | 
| 102 | 				for (UINT32 j = 0; j < GpuParamsSet::NUM_STAGES; j++) | 
| 103 | 				{ | 
| 104 | 					GpuProgramType progType = (GpuProgramType)j; | 
| 105 | 					SPtr<GpuParamDesc> paramDesc = paramsPtr->getParamDesc(progType); | 
| 106 | 					if (paramDesc == nullptr) | 
| 107 | 						continue; | 
| 108 |  | 
| 109 | 					for (auto iter = paramDesc->samplers.begin(); iter != paramDesc->samplers.end(); ++iter) | 
| 110 | 					{ | 
| 111 | 						UINT32 set = iter->second.set; | 
| 112 | 						UINT32 slot = iter->second.slot; | 
| 113 | 						slotsPerSetIter[set] = std::max(slotsPerSetIter[set], slot + 1); | 
| 114 | 					} | 
| 115 | 				} | 
| 116 |  | 
| 117 | 				for(UINT32 j = 0; j < numSetsPerPass[i]; j++) | 
| 118 | 					totalNumSamplerStates += slotsPerSetIter[j]; | 
| 119 |  | 
| 120 | 				slotsPerSetIter += numSetsPerPass[i]; | 
| 121 | 			} | 
| 122 |  | 
| 123 | 			UINT32 outputSize = sizeof(MaterialSamplerOverrides) + | 
| 124 | 				numPasses * sizeof(PassSamplerOverrides) + | 
| 125 | 				totalNumSets * sizeof(UINT32*) + | 
| 126 | 				totalNumSamplerStates * sizeof(UINT32) + | 
| 127 | 				(UINT32)overrides.size() * sizeof(SamplerOverride); | 
| 128 |  | 
| 129 | 			UINT8* outputData = (UINT8*)bs_alloc(outputSize); | 
| 130 | 			output = (MaterialSamplerOverrides*)outputData; | 
| 131 | 			outputData += sizeof(MaterialSamplerOverrides); | 
| 132 |  | 
| 133 | 			output->refCount = 0; | 
| 134 | 			output->numPasses = numPasses; | 
| 135 | 			output->passes = (PassSamplerOverrides*)outputData; | 
| 136 | 			output->isDirty = true; | 
| 137 | 			outputData += sizeof(PassSamplerOverrides) * numPasses; | 
| 138 |  | 
| 139 | 			slotsPerSetIter = slotsPerSet; | 
| 140 | 			for (UINT32 i = 0; i < numPasses; i++) | 
| 141 | 			{ | 
| 142 | 				SPtr<GpuParams> paramsPtr = paramsSet->getGpuParams(i); | 
| 143 |  | 
| 144 | 				PassSamplerOverrides& passOverrides = output->passes[i]; | 
| 145 | 				passOverrides.numSets = numSetsPerPass[i]; | 
| 146 | 				passOverrides.stateOverrides = (UINT32**)outputData; | 
| 147 | 				outputData += sizeof(UINT32*) * passOverrides.numSets; | 
| 148 |  | 
| 149 | 				for (UINT32 j = 0; j < passOverrides.numSets; j++) | 
| 150 | 				{ | 
| 151 | 					passOverrides.stateOverrides[j] = (UINT32*)outputData; | 
| 152 | 					outputData += sizeof(UINT32) * slotsPerSetIter[j]; | 
| 153 | 				} | 
| 154 |  | 
| 155 | 				for (UINT32 j = 0; j < GpuParamsSet::NUM_STAGES; j++) | 
| 156 | 				{ | 
| 157 | 					GpuProgramType progType = (GpuProgramType)j; | 
| 158 | 					SPtr<GpuParamDesc> paramDesc = paramsPtr->getParamDesc(progType); | 
| 159 | 					if (paramDesc == nullptr) | 
| 160 | 						continue; | 
| 161 |  | 
| 162 | 					UINT32 numStates = 0; | 
| 163 | 					for (auto iter = paramDesc->samplers.begin(); iter != paramDesc->samplers.end(); ++iter) | 
| 164 | 					{ | 
| 165 | 						UINT32 set = iter->second.set; | 
| 166 | 						UINT32 slot = iter->second.slot; | 
| 167 | 						while (slot > numStates) | 
| 168 | 						{ | 
| 169 | 							passOverrides.stateOverrides[set][numStates] = (UINT32)-1; | 
| 170 | 							numStates++; | 
| 171 | 						} | 
| 172 |  | 
| 173 | 						numStates = std::max(numStates, slot + 1); | 
| 174 |  | 
| 175 | 						auto iterFind = overrideLookup.find(iter->first); | 
| 176 | 						if (iterFind != overrideLookup.end()) | 
| 177 | 							passOverrides.stateOverrides[set][slot] = iterFind->second; | 
| 178 | 						else | 
| 179 | 							passOverrides.stateOverrides[set][slot] = (UINT32)-1; | 
| 180 | 					} | 
| 181 | 				} | 
| 182 |  | 
| 183 | 				slotsPerSetIter += passOverrides.numSets; | 
| 184 | 			} | 
| 185 |  | 
| 186 | 			output->numOverrides = (UINT32)overrides.size(); | 
| 187 | 			output->overrides = (SamplerOverride*)outputData; | 
| 188 |  | 
| 189 | 			for(UINT32 i = 0; i < output->numOverrides; i++) | 
| 190 | 			{ | 
| 191 | 				new (&output->overrides[i].state) SPtr<SamplerState>(); | 
| 192 | 				output->overrides[i] = overrides[i]; | 
| 193 | 			} | 
| 194 |  | 
| 195 | 			bs_stack_free(slotsPerSet); | 
| 196 | 			bs_stack_free(numSetsPerPass); | 
| 197 | 		} | 
| 198 | 		bs_frame_clear(); | 
| 199 |  | 
| 200 | 		return output; | 
| 201 | 	} | 
| 202 |  | 
| 203 | 	void SamplerOverrideUtility::destroySamplerOverrides(MaterialSamplerOverrides* overrides) | 
| 204 | 	{ | 
| 205 | 		if (overrides != nullptr) | 
| 206 | 		{ | 
| 207 | 			for (UINT32 i = 0; i < overrides->numOverrides; i++) | 
| 208 | 				overrides->overrides[i].state.~SPtr<SamplerState>(); | 
| 209 |  | 
| 210 | 			bs_free(overrides); | 
| 211 | 			overrides = nullptr; | 
| 212 | 		} | 
| 213 | 	} | 
| 214 |  | 
| 215 | 	bool SamplerOverrideUtility::checkNeedsOverride(const SPtr<SamplerState>& samplerState, const SPtr<RenderBeastOptions>& options) | 
| 216 | 	{ | 
| 217 | 		const SamplerProperties& props = samplerState->getProperties(); | 
| 218 |  | 
| 219 | 		switch (options->filtering) | 
| 220 | 		{ | 
| 221 | 		case RenderBeastFiltering::Bilinear: | 
| 222 | 		{ | 
| 223 | 			if (props.getTextureFiltering(FT_MIN) != FO_LINEAR) | 
| 224 | 				return true; | 
| 225 |  | 
| 226 | 			if (props.getTextureFiltering(FT_MAG) != FO_LINEAR) | 
| 227 | 				return true; | 
| 228 |  | 
| 229 | 			if (props.getTextureFiltering(FT_MIP) != FO_POINT) | 
| 230 | 				return true; | 
| 231 | 		} | 
| 232 | 			break; | 
| 233 | 		case RenderBeastFiltering::Trilinear: | 
| 234 | 		{ | 
| 235 | 			if (props.getTextureFiltering(FT_MIN) != FO_LINEAR) | 
| 236 | 				return true; | 
| 237 |  | 
| 238 | 			if (props.getTextureFiltering(FT_MAG) != FO_LINEAR) | 
| 239 | 				return true; | 
| 240 |  | 
| 241 | 			if (props.getTextureFiltering(FT_MIP) != FO_LINEAR) | 
| 242 | 				return true; | 
| 243 | 		} | 
| 244 | 			break; | 
| 245 | 		case RenderBeastFiltering::Anisotropic: | 
| 246 | 		{ | 
| 247 | 			if (props.getTextureFiltering(FT_MIN) != FO_ANISOTROPIC) | 
| 248 | 				return true; | 
| 249 |  | 
| 250 | 			if (props.getTextureFiltering(FT_MAG) != FO_ANISOTROPIC) | 
| 251 | 				return true; | 
| 252 |  | 
| 253 | 			if (props.getTextureFiltering(FT_MIP) != FO_ANISOTROPIC) | 
| 254 | 				return true; | 
| 255 |  | 
| 256 | 			if (props.getTextureAnisotropy() != options->anisotropyMax) | 
| 257 | 				return true; | 
| 258 | 		} | 
| 259 | 			break; | 
| 260 | 		} | 
| 261 |  | 
| 262 | 		return false; | 
| 263 | 	} | 
| 264 |  | 
| 265 | 	SPtr<SamplerState> SamplerOverrideUtility::generateSamplerOverride(const SPtr<SamplerState>& samplerState, const SPtr<RenderBeastOptions>& options) | 
| 266 | 	{ | 
| 267 | 		const SamplerProperties& props = samplerState->getProperties(); | 
| 268 | 		SAMPLER_STATE_DESC desc = props.getDesc(); | 
| 269 |  | 
| 270 | 		switch (options->filtering) | 
| 271 | 		{ | 
| 272 | 		case RenderBeastFiltering::Bilinear: | 
| 273 | 			desc.minFilter = FO_LINEAR; | 
| 274 | 			desc.magFilter = FO_LINEAR; | 
| 275 | 			desc.mipFilter = FO_POINT; | 
| 276 | 			break; | 
| 277 | 		case RenderBeastFiltering::Trilinear: | 
| 278 | 			desc.minFilter = FO_LINEAR; | 
| 279 | 			desc.magFilter = FO_LINEAR; | 
| 280 | 			desc.mipFilter = FO_LINEAR; | 
| 281 | 			break; | 
| 282 | 		case RenderBeastFiltering::Anisotropic: | 
| 283 | 			desc.minFilter = FO_ANISOTROPIC; | 
| 284 | 			desc.magFilter = FO_ANISOTROPIC; | 
| 285 | 			desc.mipFilter = FO_ANISOTROPIC; | 
| 286 | 			break; | 
| 287 | 		} | 
| 288 |  | 
| 289 | 		desc.maxAniso = options->anisotropyMax; | 
| 290 |  | 
| 291 | 		return RenderStateManager::instance().createSamplerState(desc); | 
| 292 | 	} | 
| 293 | }} |