1#include "RenderMaterial.h"
3#include "Rendering/IBuffers.h"
4#include "Rendering/ICapabilities.h"
5#include "Rendering/IContext.h"
6#include "Rendering/IEffects.h"
7#include "Rendering/ITextures.h"
11#include "Resources/MaterialManager.h"
12#include "Systems/Core/CameraSystem.h"
14#include "RenderStates.h"
15#include "RenderResources.h"
20#include "EffectBindings.h"
22#include "Foundation/HashSequence.h"
23#include "Foundation/Logging/Logger.h"
31 size_t calculateHash(
const size_t permutationIndex,
41 size_t instanceCode =
Cogs::hash(permutationIndex);
47 if (definition.isShared) {
48 instanceCode =
Cogs::hash(definition.defaultValue, instanceCode);
55 assert(streamsLayout);
57 LOG_ERROR(logger,
"Non-empty MeshStreamsLayout with zero hash");
60 instanceCode =
Cogs::hash(enginePermutation->getCode(), instanceCode);
62 instanceCode =
Cogs::hash(clipShape, instanceCode);
69 if (!binding.renderEffect) {
71 return ActivationResult::Postponed;
74 if (binding.renderEffect->hasFailed()) {
75 if (!renderMaterial->hasFailed()) {
77 auto * material = renderMaterial->getResource();
78 LOG_ERROR(logger,
"Could not initialize bindings for effect %s, failing activation.", material ? material->
getName().
to_string().c_str() :
"");
80 renderMaterial->setFailed();
83 return ActivationResult::Failure;
84 }
if (binding.renderEffect->isReleased()) {
85 LOG_ERROR(logger,
"Could not initialize bindings for released effect.");
87 renderMaterial->setFailed();
89 return ActivationResult::Failure;
90 }
else if (binding.renderEffect->
isDelayed()) {
91 renderMaterial->setDelayed();
93 return ActivationResult::Delayed;
94 }
else if (!binding.renderEffect->
isActive()) {
95 LOG_DEBUG(logger,
"Could not initialize render material due to uninitialized effect. Re-queuing.");
97 return ActivationResult::Postponed;
100 return ActivationResult::Success;
114 gpubuf.generation = materialBuffer.
generation;
123 if (b->renderEffect &&
HandleIsValid(b->renderEffect->effectHandle) && !b->textureBindings.size()) {
124 b->textureBindings.resize(material->textureProperties.size());
125 b->samplerBindings.resize(material->textureProperties.size());
129 for (
auto& tp : material->textureProperties) {
133 b->samplerBindings[tp.key] = device->
getEffects()->
getSamplerStateBinding(b->renderEffect->effectHandle, tp.name.substr(0, tp.name.find(
"[")) +
"Sampler", unit);
147 size_t N = material->textureProperties.size();
148 renderMaterial->texturePropertyStates.resize(N);
149 for (
size_t i = 0; i < N; i++) {
151 if (t.isPerInstance)
continue;
154 if (
size_t hash = t.texture.hash(); !
HandleIsValid(state.samplerState) || state.hash != hash) {
157 unsigned int anisotropy = 1;
159 anisotropy =
static_cast<unsigned int>(settings.anisotropicFiltering->getInt());
165 t.texture.filterMode,
166 Cogs::SamplerState::Never,
170 state.samplerState = renderStates->getSamplerState(samplerStateDesc);
171 debug_assert(state.samplerState);
184 binding.renderEffect = renderEffect;
186 auto effectResult = checkEffect(renderMaterial, binding);
188 if (effectResult != ActivationResult::Success)
return effectResult;
196 binding.bufferBindings.resize(material->constantBuffers.
buffers.size());
197 binding.buffers.resize(material->constantBuffers.
buffers.size());
199 for (
auto& buffer : material->constantBuffers.
buffers) {
200 if (!buffer.
size)
continue;
202 binding.bufferBindings[buffer.
index] = effects->getConstantBufferBinding(binding.renderEffect->effectHandle, buffer.
name);
206 deviceBuffers->annotate(binding.buffers[buffer.
index].handle, material->definition.name +
"_mat_" + std::to_string(buffer.
index));
210 auto& effectHandle = binding.renderEffect->effectHandle;
212 binding.sceneBufferBinding = effects->getConstantBufferBinding(effectHandle,
"SceneBuffer");
213 binding.viewBufferBinding = effects->getConstantBufferBinding(effectHandle,
"ViewBuffer");
214 binding.lightBufferBinding = effects->getConstantBufferBinding(effectHandle,
"LightBuffer");
215 binding.shadowBufferBinding = effects->getConstantBufferBinding(effectHandle,
"ShadowBuffer");
216 binding.animationBufferBinding = effects->getConstantBufferBinding(effectHandle,
"AnimationBuffer");
218 binding.shadowArrayBinding = effects->getTextureBinding(effectHandle,
"cascadedShadowMap", 1);
219 binding.shadowArrayBinding_1 = effects->getTextureBinding(effectHandle,
"cascadedShadowMap_1", 1);
220 binding.shadowArraySamplerBinding = effects->getSamplerStateBinding(effectHandle,
"cascadedShadowMapSampler", 1);
221 binding.shadowSamplerBinding = effects->getSamplerStateBinding(effectHandle,
"cascadedShadowSampler", 1);
223 binding.shadowCubeArrayBinding = effects->getTextureBinding(effectHandle,
"cubeShadowMap", 2);
224 binding.shadowCubeArrayBinding_1 = effects->getTextureBinding(effectHandle,
"cubeShadowMap_1", 2);
225 binding.shadowCubeArraySamplerBinding = effects->getSamplerStateBinding(effectHandle,
"cubeShadowMapSampler", 2);
227 binding.skyBinding = effects->getTextureBinding(effectHandle,
"environmentSky", 0);
228 binding.radianceBinding = effects->getTextureBinding(effectHandle,
"environmentRadiance", 0);
229 binding.irradianceBinding = effects->getTextureBinding(effectHandle,
"environmentIrradiance", 0);
230 binding.ambientIrradianceBinding = effects->getTextureBinding(effectHandle,
"ambientIrradiance", 0);
231 binding.brdfLUTBinding = effects->getTextureBinding(effectHandle,
"brdfLUT", 0);
233 binding.skySamplerBinding = effects->getSamplerStateBinding(effectHandle,
"environmentSkySampler", 0);
234 binding.radianceSamplerBinding = effects->getSamplerStateBinding(effectHandle,
"environmentRadianceSampler", 0);
235 binding.irradianceSamplerBinding = effects->getSamplerStateBinding(effectHandle,
"environmentIrradianceSampler", 0);
236 binding.ambientIrradianceSamplerBinding = effects->getSamplerStateBinding(effectHandle,
"ambientIrradianceSampler", 0);
237 binding.brdfLUTSamplerBinding = effects->getSamplerStateBinding(effectHandle,
"brdfLUTSampler", 0);
239 binding.objectBufferBinding = effects->getConstantBufferBinding(effectHandle,
"ObjectBuffer");
241 binding.blueNoise = effects->getTextureBinding(effectHandle,
"blueNoise_LDR_RGBA", 0);
242 binding.blueNoiseStable = effects->getTextureBinding(effectHandle,
"blueNoiseStable_LDR_RGBA", 0);
245 updateTextureBinding(material, device, renderStates, binding);
247 binding.effectGeneration = renderEffect->getGeneration();
248 ++binding.generation;
250 return ActivationResult::Success;
257 auto context = resources->getContext();
258 this->renderer = context->renderer;
260 std::vector<EffectBindingInstance> stillPending;
262 uint32_t results = 0;
263 for (
auto & pending : pendingBindings) {
264 auto & effect = pending.effect;
265 auto binding = pending.binding;
267 auto renderEffect = resources->getRenderEffect(effect);
270 if (renderEffect && binding->effectGeneration != renderEffect->generation) {
271 result = setupBinding(device, renderStates,
this, material, effect.resolve(), renderEffect, *binding);
273 results |=
static_cast<uint32_t
>(result);
276 updateBufferContents(device, material, *binding);
277 bindings.emplace_back(pending);
282 stillPending.emplace_back(pending);
285 for (
auto & binding : bindings) {
286 if (!
HandleIsValid(binding.binding->renderEffect->effectHandle)) {
289 updateBufferContents(device, material, *binding.binding);
293 pendingBindings = std::move(stillPending);
304 }
else if (havePostponed && !haveActive) {
306 }
else if (haveDelayed && !haveActive) {
312 auto instances = context->materialInstanceManager->getAllocatedResources();
314 if (uint32_t gen = material->
getGeneration(); updatedGeneration != gen) {
315 updatedGeneration = gen;
316 updateTextureProperties(
this, resources, renderStates, material);
324 if (materialInstance->
material == material &&
326 materialInstance->setChanged();
335void Cogs::Core::RenderMaterial::release(
Renderer * renderer)
339 for (
auto & b : bindings) {
340 auto binding = b.binding;
342 if (!binding)
continue;
344 for (
auto & buffer : binding->buffers) {
350 binding->buffers.clear();
351 binding->bufferBindings.clear();
356 for (
auto & b : pendingBindings) {
361 pendingBindings.clear();
373 const size_t code = calculateHash(permutationIndex, materialInstance, streamsLayout, enginePermutation, passOptions, clipShape);
376 if (b.code == code)
return b.binding;
380 if (b.code == code)
return b.binding;
385 EffectHandle effect = material->
getEffect(code, materialInstance, streamsLayout, enginePermutation, passOptions, clipShape);
391 material->setChanged();
Contains render resources used by the renderer.
EffectBindings & getEffectBindings() override
Get the reference to the EffectBindings structure.
IGraphicsDevice * getDevice() override
Get the graphics device used by the renderer.
const RenderSettings & getSettings() const override
Get the settings of the renderer.
Represents a graphics device used to manage graphics resources and issue drawing commands.
virtual IEffects * getEffects()=0
Get a pointer to the effect management interface.
virtual IContext * getImmediateContext()=0
Get a pointer to the immediate context used to issue commands to the graphics device.
virtual IBuffers * getBuffers()=0
Get a pointer to the buffer management interface.
Log implementation class.
std::string to_string() const
String conversion method.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
ClipShapeType
Specifices what kind of shape a clip shape has.
ActivationResult
Defines results for resource activation.
@ Success
Resource activated successfully.
@ Delayed
Delayed activation.
@ Postponed
Resource activation postponed, retry later.
@ Failure
Resource activation failed.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
@ Write
The buffer can be mapped and written to by the CPU after creation.
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
std::vector< MaterialPropertyBuffer > buffers
Constant buffer instances.
uint16_t buffersGeneration
If the constant buffer bindings need updates.
Effect resources contain data to control the shader stages of the GPU pipeline.
Material instances represent a specialized Material combined with state for all its buffers and prope...
std::vector< std::string > variantStrings
String storage for string variants.
Material * material
Material resource this MaterialInstance is created from.
ShaderVariantSelectors variantSelectors
Variant selectors.
Material property buffers contain properties for a material, such as color, reflectiveness or other v...
bool isPerInstance
If the buffer is updated per instance.
ConstantBufferKey index
Index of the buffer in the set of buffers owned by the same Material.
size_t size
Total size of the buffer in bytes.
PropertyName name
Name used to refer to the buffer in shaders.
std::vector< uint8_t > content
Default content for property buffer instances created from this buffer.
size_t generation
Generation counter.
Material resources define the how of geometry rendering (the what is defined by Mesh and Texture reso...
EffectHandle getEffect(size_t code, const MaterialInstance *materialInstance, const MeshStreamsLayout *streamsLayout, const EnginePermutation *enginePermutation, const RenderPassOptions &passOptions, const ClipShapeType clipShape)
EffectBinding * getBinding(const size_t permutationIndex, const MaterialInstance *materialInstance, const MeshStreamsLayout *streamsLayout, const EnginePermutation *enginePermutation, const RenderPassOptions &passOptions, const ClipShapeType clipShape)
Material * resource
Engine resource this render resource represents.
bool isDelayed() const
Get if the render resource is in a delayed state.
bool isActive() const
Get if the render resource is active and can be used for rendering.
Render settings variables.
uint32_t getGeneration() const
Get the generation count.
StringView getName() const
Get the name of the resource.
uint32_t referenceCount() const
Get the current reference count.
Property value for texture samplers.
Provides buffer management functionality.
virtual void releaseBuffer(BufferHandle bufferHandle)=0
Releases the buffer with the given bufferHandle.
Represents a graphics device context which can receive rendering commands.
virtual void updateBuffer(BufferHandle bufferHandle, const void *data, size_t size)=0
Replace contents of buffer with new data.
virtual SamplerStateBindingHandle getSamplerStateBinding(EffectHandle effectHandle, const StringView &name, const unsigned int slot)=0
Get a handle to a sampler state object binding, mapping how to bind the sampler state to the given ef...
virtual TextureBindingHandle getTextureBinding(EffectHandle effectHandle, const StringView &name, const unsigned int slot)=0
Get a handle to a texture object binding, mapping how to bind textures to the given effect.
Encapsulates state for texture sampling in a state object.
@ MinMagMipLinear
Linear sampling for both minification and magnification.
@ Dynamic
Buffer will be loaded and modified with some frequency.