Merge remote-tracking branch 'origin/gi' into large-worlds

# Conflicts:
#	Source/Engine/Core/Math/Vector3.h
This commit is contained in:
Wojtek Figat
2022-05-21 19:45:13 +02:00
280 changed files with 7660 additions and 2355 deletions

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#include "DynamicBuffer.h"
#include "PixelFormatExtensions.h"
#include "GPUDevice.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Utilities.h"
@@ -87,3 +88,24 @@ void DynamicBuffer::Dispose()
SAFE_DELETE_GPU_RESOURCE(_buffer);
Data.Resize(0);
}
void DynamicStructuredBuffer::InitDesc(GPUBufferDescription& desc, int32 numElements)
{
desc = GPUBufferDescription::Structured(numElements, _stride, _isUnorderedAccess);
desc.Usage = GPUResourceUsage::Dynamic;
}
DynamicTypedBuffer::DynamicTypedBuffer(uint32 initialCapacity, PixelFormat format, bool isUnorderedAccess, const String& name)
: DynamicBuffer(initialCapacity, PixelFormatExtensions::SizeInBytes(format), name)
, _format(format)
, _isUnorderedAccess(isUnorderedAccess)
{
}
void DynamicTypedBuffer::InitDesc(GPUBufferDescription& desc, int32 numElements)
{
auto bufferFlags = GPUBufferFlags::ShaderResource;
if (_isUnorderedAccess)
bufferFlags |= GPUBufferFlags::UnorderedAccess;
desc = GPUBufferDescription::Buffer(numElements * _stride, bufferFlags, _format, nullptr, _stride, GPUResourceUsage::Dynamic);
}

View File

@@ -170,3 +170,58 @@ protected:
desc = GPUBufferDescription::Index(_stride, numElements, GPUResourceUsage::Dynamic);
}
};
/// <summary>
/// Dynamic structured buffer that allows to upload data to the GPU from CPU (supports dynamic resizing).
/// </summary>
class FLAXENGINE_API DynamicStructuredBuffer : public DynamicBuffer
{
private:
bool _isUnorderedAccess;
public:
/// <summary>
/// Init
/// </summary>
/// <param name="initialCapacity">Initial capacity of the buffer (in bytes).</param>
/// <param name="stride">Stride in bytes.</param>
/// <param name="isUnorderedAccess">True if unordered access usage.</param>
/// <param name="name">Buffer name.</param>
DynamicStructuredBuffer(uint32 initialCapacity, uint32 stride, bool isUnorderedAccess = false, const String& name = String::Empty)
: DynamicBuffer(initialCapacity, stride, name)
, _isUnorderedAccess(isUnorderedAccess)
{
}
protected:
// [DynamicBuffer]
void InitDesc(GPUBufferDescription& desc, int32 numElements) override;
};
/// <summary>
/// Dynamic Typed buffer that allows to upload data to the GPU from CPU (supports dynamic resizing).
/// </summary>
class FLAXENGINE_API DynamicTypedBuffer : public DynamicBuffer
{
private:
PixelFormat _format;
bool _isUnorderedAccess;
public:
/// <summary>
/// Init
/// </summary>
/// <param name="initialCapacity">Initial capacity of the buffer (in bytes).</param>
/// <param name="format">Format of the data.</param>
/// <param name="isUnorderedAccess">True if unordered access usage.</param>
/// <param name="name">Buffer name.</param>
DynamicTypedBuffer(uint32 initialCapacity, PixelFormat format, bool isUnorderedAccess = false, const String& name = String::Empty);
protected:
// [DynamicBuffer]
void InitDesc(GPUBufferDescription& desc, int32 numElements) override;
};

View File

@@ -702,6 +702,16 @@ API_ENUM(Attributes="Flags") enum class DrawPass : int32
/// </summary>
MotionVectors = 1 << 4,
/// <summary>
/// The Global Sign Distance Field (SDF) rendering pass. Used for software raytracing though the scene on a GPU.
/// </summary>
GlobalSDF = 1 << 5,
/// <summary>
/// The Global Surface Atlas rendering pass. Used for software raytracing though the scene on a GPU to evaluate the object surface material properties.
/// </summary>
GlobalSurfaceAtlas = 1 << 6,
/// <summary>
/// The debug quad overdraw rendering (editor-only).
/// </summary>
@@ -712,13 +722,13 @@ API_ENUM(Attributes="Flags") enum class DrawPass : int32
/// The default set of draw passes for the scene objects.
/// </summary>
API_ENUM(Attributes="HideInEditor")
Default = Depth | GBuffer | Forward | Distortion | MotionVectors,
Default = Depth | GBuffer | Forward | Distortion | MotionVectors | GlobalSDF | GlobalSurfaceAtlas,
/// <summary>
/// The all draw passes combined into a single mask.
/// </summary>
API_ENUM(Attributes="HideInEditor")
All = Depth | GBuffer | Forward | Distortion | MotionVectors,
All = Depth | GBuffer | Forward | Distortion | MotionVectors | GlobalSDF | GlobalSurfaceAtlas,
};
DECLARE_ENUM_OPERATORS(DrawPass);
@@ -847,6 +857,16 @@ API_ENUM() enum class ViewMode
/// Draw geometry overdraw to visualize performance of pixels rendering.
/// </summary>
QuadOverdraw = 23,
/// <summary>
/// Draw Global Sign Distant Field (SDF) preview.
/// </summary>
GlobalSDF = 24,
/// <summary>
/// Draw Global Surface Atlas preview.
/// </summary>
GlobalSurfaceAtlas = 25,
};
/// <summary>
@@ -997,7 +1017,7 @@ API_ENUM(Attributes="Flags") enum class ViewFlags : int64
/// <summary>
/// Default flags for materials/models previews generating.
/// </summary>
DefaultAssetPreview = Reflections | Decals | GI | DirectionalLights | PointLights | SpotLights | SkyLights | SpecularLight | AntiAliasing | Bloom | ToneMapping | EyeAdaptation | CameraArtifacts | LensFlares | ContactShadows,
DefaultAssetPreview = Reflections | Decals | DirectionalLights | PointLights | SpotLights | SkyLights | SpecularLight | AntiAliasing | Bloom | ToneMapping | EyeAdaptation | CameraArtifacts | LensFlares | ContactShadows,
};
DECLARE_ENUM_OPERATORS(ViewFlags);

View File

@@ -553,7 +553,7 @@ public:
/// <summary>
/// Sets the rendering viewport and scissor rectangle.
/// </summary>
/// <param name="viewport">The viewport.</param>
/// <param name="viewport">The viewport (in pixels).</param>
API_FUNCTION() FORCE_INLINE void SetViewportAndScissors(const Viewport& viewport)
{
SetViewport(viewport);
@@ -575,13 +575,13 @@ public:
/// <summary>
/// Sets the rendering viewport.
/// </summary>
/// <param name="viewport">The viewport.</param>
/// <param name="viewport">The viewport (in pixels).</param>
API_FUNCTION() virtual void SetViewport(API_PARAM(Ref) const Viewport& viewport) = 0;
/// <summary>
/// Sets the scissor rectangle.
/// </summary>
/// <param name="scissorRect">The scissor rectangle.</param>
/// <param name="scissorRect">The scissor rectangle (in pixels).</param>
API_FUNCTION() virtual void SetScissor(API_PARAM(Ref) const Rectangle& scissorRect) = 0;
public:

View File

@@ -48,7 +48,7 @@ void DecalMaterialShader::Bind(BindParameters& params)
bindMeta.Context = context;
bindMeta.Constants = cb;
bindMeta.Input = nullptr;
bindMeta.Buffers = nullptr;
bindMeta.Buffers = params.RenderContext.Buffers;
bindMeta.CanSampleDepth = true;
bindMeta.CanSampleGBuffer = false;
MaterialParams::Bind(params.ParamsLink, bindMeta);

View File

@@ -74,7 +74,7 @@ void DeferredMaterialShader::Bind(BindParameters& params)
bindMeta.Context = context;
bindMeta.Constants = cb;
bindMeta.Input = nullptr;
bindMeta.Buffers = nullptr;
bindMeta.Buffers = params.RenderContext.Buffers;
bindMeta.CanSampleDepth = false;
bindMeta.CanSampleGBuffer = false;
MaterialParams::Bind(params.ParamsLink, bindMeta);

View File

@@ -62,7 +62,7 @@ void DeformableMaterialShader::Bind(BindParameters& params)
bindMeta.Context = context;
bindMeta.Constants = cb;
bindMeta.Input = nullptr;
bindMeta.Buffers = nullptr;
bindMeta.Buffers = params.RenderContext.Buffers;
bindMeta.CanSampleDepth = false;
bindMeta.CanSampleGBuffer = false;
MaterialParams::Bind(params.ParamsLink, bindMeta);

View File

@@ -5,6 +5,7 @@
#include "MaterialInfo.h"
struct MaterialParamsLink;
class GPUShader;
class GPUContext;
class GPUTextureView;
class RenderBuffers;
@@ -26,6 +27,12 @@ public:
/// <returns>The constant reference to the material descriptor.</returns>
virtual const MaterialInfo& GetInfo() const = 0;
/// <summary>
/// Gets the shader resource.
/// </summary>
/// <returns>The material shader resource.</returns>
virtual GPUShader* GetShader() const = 0;
/// <summary>
/// Determines whether material is a surface shader.
/// </summary>

View File

@@ -11,6 +11,8 @@
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/GPULimits.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Renderer/GlobalSignDistanceFieldPass.h"
#include "Engine/Streaming/Streaming.h"
bool MaterialInfo8::operator==(const MaterialInfo8& other) const
@@ -157,6 +159,9 @@ const Char* ToString(MaterialParameterType value)
case MaterialParameterType::TextureGroupSampler:
result = TEXT("TextureGroupSampler");
break;
case MaterialParameterType::GlobalSDF:
result = TEXT("GlobalSDF");
break;
default:
result = TEXT("");
break;
@@ -198,7 +203,6 @@ Variant MaterialParameter::GetValue() const
case MaterialParameterType::GPUTexture:
return _asGPUTexture.Get();
default:
CRASH;
return Variant::Zero;
}
}
@@ -303,6 +307,8 @@ void MaterialParameter::SetValue(const Variant& value)
invalidType = true;
}
break;
case MaterialParameterType::GlobalSDF:
break;
default:
invalidType = true;
}
@@ -477,6 +483,16 @@ void MaterialParameter::Bind(BindMeta& meta) const
case MaterialParameterType::TextureGroupSampler:
meta.Context->BindSampler(_registerIndex, Streaming::GetTextureGroupSampler(_asInteger));
break;
case MaterialParameterType::GlobalSDF:
{
GlobalSignDistanceFieldPass::BindingData bindingData;
if (GlobalSignDistanceFieldPass::Instance()->Get(meta.Buffers, bindingData))
Platform::MemoryClear(&bindingData, sizeof(bindingData));
for (int32 i = 0; i < 4; i++)
meta.Context->BindSR(_registerIndex + i, bindingData.Cascades[i] ? bindingData.Cascades[i]->ViewVolume() : nullptr);
*((GlobalSignDistanceFieldPass::ConstantsData*)(meta.Constants.Get() + _offset)) = bindingData.Constants;
break;
}
default:
break;
}

View File

@@ -128,6 +128,11 @@ enum class MaterialParameterType : byte
/// The texture sampler derived from texture group settings.
/// </summary>
TextureGroupSampler = 19,
/// <summary>
/// The Global SDF (textures and constants).
/// </summary>
GlobalSDF = 20,
};
const Char* ToString(MaterialParameterType value);

View File

@@ -98,8 +98,6 @@ public:
/// <returns>The created and loaded material or null if failed.</returns>
static MaterialShader* CreateDummy(MemoryReadStream& shaderCacheStream, const MaterialInfo& info);
GPUShader* GetShader() const;
/// <summary>
/// Clears the loaded data.
/// </summary>
@@ -114,5 +112,6 @@ public:
// [IMaterial]
const MaterialInfo& GetInfo() const override;
GPUShader* GetShader() const override;
bool IsReady() const override;
};

View File

@@ -22,6 +22,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
const int32 envProbeShaderRegisterIndex = srv + 0;
const int32 skyLightShaderRegisterIndex = srv + 1;
const int32 dirLightShaderRegisterIndex = srv + 2;
const bool canUseShadow = view.Pass != DrawPass::Depth;
// Set fog input
if (cache->Fog)
@@ -39,7 +40,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
{
const auto& dirLight = cache->DirectionalLights.First();
const auto shadowPass = ShadowsPass::Instance();
const bool useShadow = shadowPass->LastDirLightIndex == 0;
const bool useShadow = shadowPass->LastDirLightIndex == 0 && canUseShadow;
if (useShadow)
{
data.DirectionalLightShadow = shadowPass->LastDirLight;
@@ -49,7 +50,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
{
context->UnBindSR(dirLightShaderRegisterIndex);
}
dirLight.SetupLightData(&data.DirectionalLight, view, useShadow);
dirLight.SetupLightData(&data.DirectionalLight, useShadow);
}
else
{
@@ -62,7 +63,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
if (cache->SkyLights.HasItems())
{
auto& skyLight = cache->SkyLights.First();
skyLight.SetupLightData(&data.SkyLight, view, false);
skyLight.SetupLightData(&data.SkyLight, false);
const auto texture = skyLight.Image ? skyLight.Image->GetTexture() : nullptr;
context->BindSR(skyLightShaderRegisterIndex, GET_TEXTURE_VIEW_SAFE(texture));
}
@@ -103,7 +104,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
const auto& light = cache->PointLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
light.SetupLightData(&data.LocalLights[data.LocalLightsCount], view, false);
light.SetupLightData(&data.LocalLights[data.LocalLightsCount], false);
data.LocalLightsCount++;
}
}
@@ -112,7 +113,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
const auto& light = cache->SpotLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
light.SetupLightData(&data.LocalLights[data.LocalLightsCount], view, false);
light.SetupLightData(&data.LocalLights[data.LocalLightsCount], false);
data.LocalLightsCount++;
}
}

View File

@@ -67,7 +67,7 @@ void TerrainMaterialShader::Bind(BindParameters& params)
bindMeta.Context = context;
bindMeta.Constants = cb;
bindMeta.Input = nullptr;
bindMeta.Buffers = nullptr;
bindMeta.Buffers = params.RenderContext.Buffers;
bindMeta.CanSampleDepth = false;
bindMeta.CanSampleGBuffer = false;
MaterialParams::Bind(params.ParamsLink, bindMeta);

View File

@@ -89,12 +89,12 @@ namespace
}
else
{
auto v = Half2(0, 0);
auto v = Half2::Zero;
for (uint32 i = 0; i < vertexCount; i++)
vb1[i].TexCoord = v;
}
{
auto v = Half2(0, 0);
auto v = Half2::Zero;
for (uint32 i = 0; i < vertexCount; i++)
vb1[i].LightmapUVs = v;
}

View File

@@ -531,6 +531,17 @@ void MeshData::TransformBuffer(const Matrix& matrix)
}
}
void MeshData::NormalizeBlendWeights()
{
ASSERT(Positions.Count() == BlendWeights.Count());
for (int32 i = 0; i < Positions.Count(); i++)
{
const float sum = BlendWeights[i].SumValues();
const float invSum = sum > ZeroTolerance ? 1.0f / sum : 0.0f;
BlendWeights[i] *= invSum;
}
}
void MeshData::Merge(MeshData& other)
{
// Merge index buffer (and remap indices)
@@ -600,6 +611,21 @@ bool MaterialSlotEntry::UsesProperties() const
Normals.TextureIndex != -1;
}
BoundingBox ModelLodData::GetBox() const
{
if (Meshes.IsEmpty())
return BoundingBox::Empty;
BoundingBox bounds;
Meshes[0]->CalculateBox(bounds);
for (int32 i = 1; i < Meshes.Count(); i++)
{
BoundingBox b;
Meshes[i]->CalculateBox(b);
BoundingBox::Merge(bounds, b, bounds);
}
return bounds;
}
void ModelData::CalculateLODsScreenSizes()
{
const float autoComputeLodPowerBase = 0.5f;

View File

@@ -2,7 +2,6 @@
#pragma once
#include "Engine/Core/Common.h"
#include "Engine/Core/Math/BoundingSphere.h"
#include "Engine/Core/Math/BoundingBox.h"
#include "Engine/Core/Math/Int4.h"
@@ -281,16 +280,7 @@ public:
/// <summary>
/// Normalizes the blend weights. Requires to have vertices with positions and blend weights setup.
/// </summary>
void NormalizeBlendWeights()
{
ASSERT(Positions.Count() == BlendWeights.Count());
for (int32 i = 0; i < Positions.Count(); i++)
{
const float sum = BlendWeights[i].SumValues();
const float invSum = sum > ZeroTolerance ? 1.0f / sum : 0.0f;
BlendWeights[i] *= invSum;
}
}
void NormalizeBlendWeights();
/// <summary>
/// Merges this mesh data with the specified other mesh.
@@ -409,6 +399,11 @@ public:
{
Meshes.ClearDelete();
}
/// <summary>
/// Gets the bounding box combined for all meshes in this model LOD.
/// </summary>
BoundingBox GetBox() const;
};
/// <summary>

View File

@@ -404,7 +404,7 @@ bool UpdateMesh(SkinnedMesh* mesh, MonoArray* verticesObj, MonoArray* trianglesO
}
else
{
auto v = Half2(0, 0);
auto v = Half2::Zero;
for (uint32 i = 0; i < vertexCount; i++)
vb[i].TexCoord = v;
}

View File

@@ -25,6 +25,11 @@ RenderBuffers::RenderBuffers(const SpawnParams& params)
#undef CREATE_TEXTURE
}
String RenderBuffers::CustomBuffer::ToString() const
{
return Name;
}
RenderBuffers::~RenderBuffers()
{
Release();
@@ -61,6 +66,15 @@ void RenderBuffers::Prepare()
UPDATE_LAZY_KEEP_RT(HalfResDepth);
UPDATE_LAZY_KEEP_RT(LuminanceMap);
#undef UPDATE_LAZY_KEEP_RT
for (int32 i = CustomBuffers.Count() - 1; i >= 0; i--)
{
CustomBuffer* e = CustomBuffers[i];
if (frameIndex - e->LastFrameUsed >= LAZY_FRAMES_COUNT)
{
Delete(e);
CustomBuffers.RemoveAt(i);
}
}
}
GPUTexture* RenderBuffers::RequestHalfResDepth(GPUContext* context)
@@ -184,4 +198,5 @@ void RenderBuffers::Release()
UPDATE_LAZY_KEEP_RT(HalfResDepth);
UPDATE_LAZY_KEEP_RT(LuminanceMap);
#undef UPDATE_LAZY_KEEP_RT
CustomBuffers.ClearDelete();
}

View File

@@ -16,23 +16,36 @@
#define GBUFFER2_FORMAT PixelFormat::R8G8B8A8_UNorm
#define GBUFFER3_FORMAT PixelFormat::R8G8B8A8_UNorm
// Light accumulation buffer format (direct+indirect light, materials emissive)
#define LIGHT_BUFFER_FORMAT PixelFormat::R11G11B10_Float
/// <summary>
/// The scene rendering buffers container.
/// </summary>
API_CLASS() class FLAXENGINE_API RenderBuffers : public ScriptingObject
{
DECLARE_SCRIPTING_TYPE(RenderBuffers);
protected:
DECLARE_SCRIPTING_TYPE(RenderBuffers);
/// <summary>
/// The custom rendering state.
/// </summary>
class CustomBuffer : public Object
{
public:
String Name;
uint64 LastFrameUsed = 0;
String ToString() const override;
};
protected:
int32 _width = 0;
int32 _height = 0;
float _aspectRatio = 0.0f;
Viewport _viewport;
Array<GPUTexture*, FixedAllocation<32>> _resources;
public:
union
{
struct
@@ -80,15 +93,16 @@ public:
GPUTexture* TemporalAA = nullptr;
uint64 LastFrameTemporalAA = 0;
public:
// Maps the custom buffer type into the object that holds the state.
Array<CustomBuffer*, HeapAllocation> CustomBuffers;
public:
/// <summary>
/// Finalizes an instance of the <see cref="RenderBuffers"/> class.
/// </summary>
~RenderBuffers();
public:
/// <summary>
/// Prepares buffers for rendering a scene. Called before rendering so other parts can reuse calculated value.
/// </summary>
@@ -102,7 +116,6 @@ public:
GPUTexture* RequestHalfResDepth(GPUContext* context);
public:
/// <summary>
/// Gets the buffers width (in pixels).
/// </summary>
@@ -143,6 +156,31 @@ public:
return _viewport;
}
template<class T>
const T* FindCustomBuffer(const StringView& name) const
{
for (CustomBuffer* e : CustomBuffers)
{
if (e->Name == name)
return (const T*)e;
}
return nullptr;
}
template<class T>
T* GetCustomBuffer(const StringView& name)
{
for (CustomBuffer* e : CustomBuffers)
{
if (e->Name == name)
return (T*)e;
}
CustomBuffer* result = New<T>();
result->Name = name;
CustomBuffers.Add(result);
return (T*)result;
}
/// <summary>
/// Gets the current GPU memory usage by all the buffers (in bytes).
/// </summary>
@@ -162,7 +200,6 @@ public:
API_FIELD(ReadOnly) GPUTexture* MotionVectors;
public:
/// <summary>
/// Allocates the buffers.
/// </summary>

View File

@@ -229,6 +229,8 @@ SceneRenderTask::~SceneRenderTask()
{
if (Buffers)
Buffers->DeleteObjectNow();
if (_customActorsScene)
Delete(_customActorsScene);
}
void SceneRenderTask::CameraCut()
@@ -270,18 +272,29 @@ void SceneRenderTask::CollectPostFxVolumes(RenderContext& renderContext)
}
}
void AddActorToSceneRendering(SceneRendering* s, Actor* a)
{
if (a && a->IsActiveInHierarchy())
{
int32 key = -1;
s->AddActor(a, key);
for (Actor* child : a->Children)
AddActorToSceneRendering(s, child);
}
}
void SceneRenderTask::OnCollectDrawCalls(RenderContext& renderContext)
{
// Draw actors (collect draw calls)
if ((ActorsSource & ActorsSources::CustomActors) != 0)
{
for (auto a : CustomActors)
{
if (a && a->GetIsActive())
{
a->DrawHierarchy(renderContext);
}
}
if (_customActorsScene == nullptr)
_customActorsScene = New<SceneRendering>();
else
_customActorsScene->Clear();
for (Actor* a : CustomActors)
AddActorToSceneRendering(_customActorsScene, a);
_customActorsScene->Draw(renderContext);
}
if ((ActorsSource & ActorsSources::Scenes) != 0)
{
@@ -403,7 +416,7 @@ void SceneRenderTask::OnEnd(GPUContext* context)
// Swap matrices
View.PrevView = View.View;
View.PrevProjection = View.Projection;
Matrix::Multiply(View.PrevView, View.PrevProjection, View.PrevViewProjection);
View.PrevViewProjection = View.ViewProjection();
}
bool SceneRenderTask::Resize(int32 width, int32 height)

View File

@@ -220,6 +220,10 @@ public:
API_CLASS() class FLAXENGINE_API SceneRenderTask : public RenderTask
{
DECLARE_SCRIPTING_TYPE(SceneRenderTask);
protected:
class SceneRendering* _customActorsScene = nullptr;
public:
/// <summary>
/// Finalizes an instance of the <see cref="SceneRenderTask"/> class.

View File

@@ -97,6 +97,16 @@ public:
/// </summary>
API_FIELD() bool IsOfflinePass = false;
/// <summary>
/// Flag used by single-frame rendering passes (eg. thumbnail rendering, model view caching) to reject LOD transitions animations and other temporal draw effects.
/// </summary>
API_FIELD() bool IsSingleFrame = false;
/// <summary>
/// Flag used by custom passes to skip any object culling when drawing.
/// </summary>
API_FIELD() bool IsCullingDisabled = false;
/// <summary>
/// The static flags mask used to hide objects that don't have a given static flags. Eg. use StaticFlags::Lightmap to render only objects that can use lightmap.
/// </summary>

View File

@@ -282,16 +282,18 @@ bool ShaderAssetBase::LoadShaderCache(ShaderCacheResult& result)
editorDefine.Definition = "1";
#endif
InitCompilationOptions(options);
if (ShadersCompilation::Compile(options))
const bool failed = ShadersCompilation::Compile(options);
// Encrypt source code
Encryption::EncryptBytes(reinterpret_cast<byte*>(source), sourceLength);
if (failed)
{
LOG(Error, "Failed to compile shader '{0}'", parent->ToString());
return true;
}
LOG(Info, "Shader '{0}' compiled! Cache size: {1} bytes", parent->ToString(), cacheStream.GetPosition());
// Encrypt source code
Encryption::EncryptBytes(reinterpret_cast<byte*>(source), sourceLength);
// Save compilation result (based on current caching policy)
if (cachingMode == ShaderStorage::CachingMode::AssetInternal)
{
@@ -345,7 +347,7 @@ bool ShaderAssetBase::LoadShaderCache(ShaderCacheResult& result)
result.Data.Link(cacheChunk->Data);
}
#if COMPILE_WITH_SHADER_CACHE_MANAGER
// Check if has cached shader
// Check if has cached shader
else if (cachedEntry.IsValid() || ShaderCacheManager::TryGetEntry(shaderProfile, parent->GetID(), cachedEntry))
{
// Load results from cache

View File

@@ -12,7 +12,7 @@ class GPUShaderProgram;
/// <summary>
/// The runtime version of the shaders cache supported by the all graphics back-ends. The same for all the shader cache formats (easier to sync and validate).
/// </summary>
#define GPU_SHADER_CACHE_VERSION 8
#define GPU_SHADER_CACHE_VERSION 9
/// <summary>
/// Represents collection of shader programs with permutations and custom names.

View File

@@ -431,11 +431,6 @@ bool GPUTexture::Init(const GPUTextureDescription& desc)
LOG(Warning, "Cannot create texture. Only 2D Texture can be used as a Depth Stencil. Description: {0}", desc.ToString());
return true;
}
if (desc.MipLevels != 1)
{
LOG(Warning, "Cannot create texture. Volume texture cannot have more than 1 mip level. Description: {0}", desc.ToString());
return true;
}
if (desc.ArraySize != 1)
{
LOG(Warning, "Cannot create texture. Volume texture cannot create array of volume textures. Description: {0}", desc.ToString());
@@ -607,7 +602,25 @@ GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipInde
ASSERT(IsAllocated());
ASSERT(mipIndex < MipLevels() && data.IsValid());
ASSERT(data.Length() >= slicePitch);
// TODO: support texture data upload to the GPU on a main thread during rendering without this async task (faster direct upload)
// Optimize texture upload invoked during rendering
if (IsInMainThread() && GPUDevice::Instance->IsRendering())
{
// Update all array slices
const byte* dataSource = data.Get();
for (int32 arrayIndex = 0; arrayIndex < _desc.ArraySize; arrayIndex++)
{
GPUDevice::Instance->GetMainContext()->UpdateTexture(this, arrayIndex, mipIndex, dataSource, rowPitch, slicePitch);
dataSource += slicePitch;
}
if (mipIndex == HighestResidentMipIndex() - 1)
{
// Mark as mip loaded
SetResidentMipLevels(ResidentMipLevels() + 1);
}
return nullptr;
}
auto task = ::New<GPUUploadTextureMipTask>(this, mipIndex, data, rowPitch, slicePitch, copyData);
ASSERT_LOW_LAYER(task && task->HasReference(this));
return task;
@@ -800,5 +813,6 @@ void GPUTexture::SetResidentMipLevels(int32 count)
if (_residentMipLevels == count || !IsRegularTexture())
return;
_residentMipLevels = count;
onResidentMipsChanged();
OnResidentMipsChanged();
ResidentMipsChanged(this);
}

View File

@@ -568,12 +568,17 @@ public:
/// Sets the number of resident mipmap levels in the texture (already uploaded to the GPU).
/// </summary>
API_PROPERTY() void SetResidentMipLevels(int32 count);
/// <summary>
/// Event called when texture residency gets changed. Texture Mip gets loaded into GPU memory and is ready to use.
/// </summary>
Delegate<GPUTexture*> ResidentMipsChanged;
protected:
virtual bool OnInit() = 0;
uint64 calculateMemoryUsage() const;
virtual void onResidentMipsChanged() = 0;
virtual void OnResidentMipsChanged() = 0;
public:

View File

@@ -233,6 +233,7 @@ protected:
{
Swap(_streamingTexture->_texture, _newTexture);
_streamingTexture->GetTexture()->SetResidentMipLevels(_uploadedMipCount);
_streamingTexture->ResidencyChanged();
SAFE_DELETE_GPU_RESOURCE(_newTexture);
// Base
@@ -447,6 +448,7 @@ Task* StreamingTexture::CreateStreamingTask(int32 residency)
{
// Do the quick data release
_texture->ReleaseGPU();
ResidencyChanged();
}
else
{