Wire camera-config post-process requests
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <XCEngine/Core/Asset/ResourceHandle.h>
|
||||
#include <XCEngine/Core/Math/Color.h>
|
||||
#include <XCEngine/Core/Math/Rect.h>
|
||||
#include <XCEngine/Core/Math/Vector4.h>
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
|
||||
#include <string>
|
||||
@@ -89,6 +90,12 @@ public:
|
||||
const Math::Color& GetSkyboxBottomColor() const { return m_skyboxBottomColor; }
|
||||
void SetSkyboxBottomColor(const Math::Color& value) { m_skyboxBottomColor = value; }
|
||||
|
||||
bool IsColorScalePostProcessEnabled() const { return m_colorScalePostProcessEnabled; }
|
||||
void SetColorScalePostProcessEnabled(bool value) { m_colorScalePostProcessEnabled = value; }
|
||||
|
||||
const Math::Vector4& GetColorScalePostProcessScale() const { return m_colorScalePostProcessScale; }
|
||||
void SetColorScalePostProcessScale(const Math::Vector4& value) { m_colorScalePostProcessScale = value; }
|
||||
|
||||
void Serialize(std::ostream& os) const override;
|
||||
void Deserialize(std::istream& is) override;
|
||||
|
||||
@@ -112,6 +119,8 @@ private:
|
||||
Math::Color m_skyboxTopColor = Math::Color(0.18f, 0.36f, 0.74f, 1.0f);
|
||||
Math::Color m_skyboxHorizonColor = Math::Color(0.78f, 0.84f, 0.92f, 1.0f);
|
||||
Math::Color m_skyboxBottomColor = Math::Color(0.92f, 0.93f, 0.95f, 1.0f);
|
||||
bool m_colorScalePostProcessEnabled = false;
|
||||
Math::Vector4 m_colorScalePostProcessScale = Math::Vector4::One();
|
||||
};
|
||||
|
||||
} // namespace Components
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <XCEngine/Rendering/Planning/CameraRenderRequest.h>
|
||||
#include <XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -15,13 +16,14 @@ class Scene;
|
||||
namespace Rendering {
|
||||
|
||||
class RenderPipelineAsset;
|
||||
class FullscreenPassSurfaceCache;
|
||||
|
||||
class SceneRenderer {
|
||||
public:
|
||||
SceneRenderer();
|
||||
explicit SceneRenderer(std::unique_ptr<RenderPipeline> pipeline);
|
||||
explicit SceneRenderer(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
|
||||
~SceneRenderer() = default;
|
||||
~SceneRenderer();
|
||||
|
||||
void SetPipeline(std::unique_ptr<RenderPipeline> pipeline);
|
||||
void SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
|
||||
@@ -32,7 +34,7 @@ public:
|
||||
const Components::Scene& scene,
|
||||
Components::CameraComponent* overrideCamera,
|
||||
const RenderContext& context,
|
||||
const RenderSurface& surface) const;
|
||||
const RenderSurface& surface);
|
||||
|
||||
bool Render(const CameraRenderRequest& request);
|
||||
bool Render(const std::vector<CameraRenderRequest>& requests);
|
||||
@@ -43,8 +45,15 @@ public:
|
||||
const RenderSurface& surface);
|
||||
|
||||
private:
|
||||
void PrepareOwnedCameraPostProcessState(size_t requestCount);
|
||||
void AttachCameraPostProcessRequests(
|
||||
const RenderContext& context,
|
||||
std::vector<CameraRenderRequest>& requests);
|
||||
|
||||
SceneRenderRequestPlanner m_requestPlanner;
|
||||
CameraRenderer m_cameraRenderer;
|
||||
std::vector<std::unique_ptr<RenderPassSequence>> m_ownedPostProcessSequences;
|
||||
std::vector<std::unique_ptr<FullscreenPassSurfaceCache>> m_ownedPostProcessSourceSurfaces;
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -149,6 +149,12 @@ void CameraComponent::Serialize(std::ostream& os) const {
|
||||
os << "skyboxTopColor=" << m_skyboxTopColor.r << "," << m_skyboxTopColor.g << "," << m_skyboxTopColor.b << "," << m_skyboxTopColor.a << ";";
|
||||
os << "skyboxHorizonColor=" << m_skyboxHorizonColor.r << "," << m_skyboxHorizonColor.g << "," << m_skyboxHorizonColor.b << "," << m_skyboxHorizonColor.a << ";";
|
||||
os << "skyboxBottomColor=" << m_skyboxBottomColor.r << "," << m_skyboxBottomColor.g << "," << m_skyboxBottomColor.b << "," << m_skyboxBottomColor.a << ";";
|
||||
os << "colorScalePostProcessEnabled=" << (m_colorScalePostProcessEnabled ? 1 : 0) << ";";
|
||||
os << "colorScalePostProcessScale="
|
||||
<< m_colorScalePostProcessScale.x << ","
|
||||
<< m_colorScalePostProcessScale.y << ","
|
||||
<< m_colorScalePostProcessScale.z << ","
|
||||
<< m_colorScalePostProcessScale.w << ";";
|
||||
}
|
||||
|
||||
void CameraComponent::Deserialize(std::istream& is) {
|
||||
@@ -220,6 +226,15 @@ void CameraComponent::Deserialize(std::istream& is) {
|
||||
std::replace(value.begin(), value.end(), ',', ' ');
|
||||
std::istringstream ss(value);
|
||||
ss >> m_skyboxBottomColor.r >> m_skyboxBottomColor.g >> m_skyboxBottomColor.b >> m_skyboxBottomColor.a;
|
||||
} else if (key == "colorScalePostProcessEnabled") {
|
||||
m_colorScalePostProcessEnabled = (std::stoi(value) != 0);
|
||||
} else if (key == "colorScalePostProcessScale") {
|
||||
std::replace(value.begin(), value.end(), ',', ' ');
|
||||
std::istringstream ss(value);
|
||||
ss >> m_colorScalePostProcessScale.x
|
||||
>> m_colorScalePostProcessScale.y
|
||||
>> m_colorScalePostProcessScale.z
|
||||
>> m_colorScalePostProcessScale.w;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,156 +1,5 @@
|
||||
#include "Rendering/Caches/FullscreenPassSurfaceCache.h"
|
||||
|
||||
#include "Rendering/RenderContext.h"
|
||||
#include "RHI/RHIDevice.h"
|
||||
#include "RHI/RHIResourceView.h"
|
||||
#include "RHI/RHITexture.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
|
||||
namespace {
|
||||
|
||||
void DestroySurfaceEntry(FullscreenPassSurfaceCache::SurfaceEntry& entry) {
|
||||
if (entry.renderTargetView != nullptr) {
|
||||
entry.renderTargetView->Shutdown();
|
||||
delete entry.renderTargetView;
|
||||
entry.renderTargetView = nullptr;
|
||||
}
|
||||
|
||||
if (entry.shaderResourceView != nullptr) {
|
||||
entry.shaderResourceView->Shutdown();
|
||||
delete entry.shaderResourceView;
|
||||
entry.shaderResourceView = nullptr;
|
||||
}
|
||||
|
||||
if (entry.texture != nullptr) {
|
||||
entry.texture->Shutdown();
|
||||
delete entry.texture;
|
||||
entry.texture = nullptr;
|
||||
}
|
||||
|
||||
entry.surface = RenderSurface();
|
||||
entry.currentColorState = RHI::ResourceStates::Common;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
FullscreenPassSurfaceCache::~FullscreenPassSurfaceCache() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
bool FullscreenPassSurfaceCache::EnsureSurfaces(
|
||||
const RenderContext& context,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
RHI::Format format,
|
||||
size_t surfaceCount) {
|
||||
if (!context.IsValid() ||
|
||||
width == 0 ||
|
||||
height == 0 ||
|
||||
format == RHI::Format::Unknown ||
|
||||
surfaceCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Matches(context, width, height, format, surfaceCount)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<SurfaceEntry> newEntries(surfaceCount);
|
||||
for (size_t index = 0; index < surfaceCount; ++index) {
|
||||
SurfaceEntry& entry = newEntries[index];
|
||||
|
||||
RHI::TextureDesc textureDesc = {};
|
||||
textureDesc.width = width;
|
||||
textureDesc.height = height;
|
||||
textureDesc.depth = 1;
|
||||
textureDesc.mipLevels = 1;
|
||||
textureDesc.arraySize = 1;
|
||||
textureDesc.format = static_cast<uint32_t>(format);
|
||||
textureDesc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
|
||||
textureDesc.sampleCount = 1;
|
||||
textureDesc.sampleQuality = 0;
|
||||
textureDesc.flags = 0;
|
||||
|
||||
entry.texture = context.device->CreateTexture(textureDesc);
|
||||
if (entry.texture == nullptr) {
|
||||
for (SurfaceEntry& createdEntry : newEntries) {
|
||||
DestroySurfaceEntry(createdEntry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::ResourceViewDesc viewDesc = {};
|
||||
viewDesc.format = static_cast<uint32_t>(format);
|
||||
viewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
|
||||
viewDesc.mipLevel = 0;
|
||||
|
||||
entry.renderTargetView = context.device->CreateRenderTargetView(entry.texture, viewDesc);
|
||||
if (entry.renderTargetView == nullptr) {
|
||||
for (SurfaceEntry& createdEntry : newEntries) {
|
||||
DestroySurfaceEntry(createdEntry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
entry.shaderResourceView = context.device->CreateShaderResourceView(entry.texture, viewDesc);
|
||||
if (entry.shaderResourceView == nullptr) {
|
||||
for (SurfaceEntry& createdEntry : newEntries) {
|
||||
DestroySurfaceEntry(createdEntry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
entry.surface = RenderSurface(width, height);
|
||||
entry.surface.SetColorAttachment(entry.renderTargetView);
|
||||
entry.surface.SetAutoTransitionEnabled(true);
|
||||
entry.surface.SetColorStateBefore(RHI::ResourceStates::Common);
|
||||
entry.surface.SetColorStateAfter(RHI::ResourceStates::PixelShaderResource);
|
||||
entry.currentColorState = RHI::ResourceStates::Common;
|
||||
}
|
||||
|
||||
Reset();
|
||||
m_device = context.device;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_format = format;
|
||||
m_entries = std::move(newEntries);
|
||||
return true;
|
||||
}
|
||||
|
||||
FullscreenPassSurfaceCache::SurfaceEntry* FullscreenPassSurfaceCache::GetSurfaceEntry(size_t index) {
|
||||
return index < m_entries.size() ? &m_entries[index] : nullptr;
|
||||
}
|
||||
|
||||
const FullscreenPassSurfaceCache::SurfaceEntry* FullscreenPassSurfaceCache::GetSurfaceEntry(size_t index) const {
|
||||
return index < m_entries.size() ? &m_entries[index] : nullptr;
|
||||
}
|
||||
|
||||
bool FullscreenPassSurfaceCache::Matches(
|
||||
const RenderContext& context,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
RHI::Format format,
|
||||
size_t surfaceCount) const {
|
||||
return m_device == context.device &&
|
||||
m_width == width &&
|
||||
m_height == height &&
|
||||
m_format == format &&
|
||||
m_entries.size() == surfaceCount;
|
||||
}
|
||||
|
||||
void FullscreenPassSurfaceCache::Reset() {
|
||||
for (SurfaceEntry& entry : m_entries) {
|
||||
DestroySurfaceEntry(entry);
|
||||
}
|
||||
|
||||
m_entries.clear();
|
||||
m_device = nullptr;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_format = RHI::Format::Unknown;
|
||||
}
|
||||
|
||||
} // namespace Rendering
|
||||
} // namespace XCEngine
|
||||
// This translation unit remains intentionally light. The cache is implemented
|
||||
// inline in the header so existing generated build files do not require a
|
||||
// CMake regeneration just to pick up method definitions.
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Rendering/RenderSurface.h"
|
||||
#include "Rendering/RenderContext.h"
|
||||
#include "RHI/RHIDevice.h"
|
||||
#include "RHI/RHIEnums.h"
|
||||
#include "RHI/RHIResourceView.h"
|
||||
#include "RHI/RHITexture.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
@@ -30,27 +34,146 @@ public:
|
||||
FullscreenPassSurfaceCache() = default;
|
||||
FullscreenPassSurfaceCache(const FullscreenPassSurfaceCache&) = delete;
|
||||
FullscreenPassSurfaceCache& operator=(const FullscreenPassSurfaceCache&) = delete;
|
||||
~FullscreenPassSurfaceCache();
|
||||
~FullscreenPassSurfaceCache() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
bool EnsureSurfaces(
|
||||
const RenderContext& context,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
RHI::Format format,
|
||||
size_t surfaceCount);
|
||||
size_t surfaceCount) {
|
||||
if (!context.IsValid() ||
|
||||
width == 0 ||
|
||||
height == 0 ||
|
||||
format == RHI::Format::Unknown ||
|
||||
surfaceCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Matches(context, width, height, format, surfaceCount)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<SurfaceEntry> newEntries(surfaceCount);
|
||||
for (size_t index = 0; index < surfaceCount; ++index) {
|
||||
SurfaceEntry& entry = newEntries[index];
|
||||
|
||||
RHI::TextureDesc textureDesc = {};
|
||||
textureDesc.width = width;
|
||||
textureDesc.height = height;
|
||||
textureDesc.depth = 1;
|
||||
textureDesc.mipLevels = 1;
|
||||
textureDesc.arraySize = 1;
|
||||
textureDesc.format = static_cast<uint32_t>(format);
|
||||
textureDesc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
|
||||
textureDesc.sampleCount = 1;
|
||||
textureDesc.sampleQuality = 0;
|
||||
textureDesc.flags = 0;
|
||||
|
||||
entry.texture = context.device->CreateTexture(textureDesc);
|
||||
if (entry.texture == nullptr) {
|
||||
for (SurfaceEntry& createdEntry : newEntries) {
|
||||
DestroySurfaceEntry(createdEntry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::ResourceViewDesc viewDesc = {};
|
||||
viewDesc.format = static_cast<uint32_t>(format);
|
||||
viewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
|
||||
viewDesc.mipLevel = 0;
|
||||
|
||||
entry.renderTargetView = context.device->CreateRenderTargetView(entry.texture, viewDesc);
|
||||
if (entry.renderTargetView == nullptr) {
|
||||
for (SurfaceEntry& createdEntry : newEntries) {
|
||||
DestroySurfaceEntry(createdEntry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
entry.shaderResourceView = context.device->CreateShaderResourceView(entry.texture, viewDesc);
|
||||
if (entry.shaderResourceView == nullptr) {
|
||||
for (SurfaceEntry& createdEntry : newEntries) {
|
||||
DestroySurfaceEntry(createdEntry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
entry.surface = RenderSurface(width, height);
|
||||
entry.surface.SetColorAttachment(entry.renderTargetView);
|
||||
entry.surface.SetAutoTransitionEnabled(true);
|
||||
entry.surface.SetColorStateBefore(RHI::ResourceStates::Common);
|
||||
entry.surface.SetColorStateAfter(RHI::ResourceStates::PixelShaderResource);
|
||||
entry.currentColorState = RHI::ResourceStates::Common;
|
||||
}
|
||||
|
||||
Reset();
|
||||
m_device = context.device;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_format = format;
|
||||
m_entries = std::move(newEntries);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t GetSurfaceCount() const { return m_entries.size(); }
|
||||
SurfaceEntry* GetSurfaceEntry(size_t index);
|
||||
const SurfaceEntry* GetSurfaceEntry(size_t index) const;
|
||||
SurfaceEntry* GetSurfaceEntry(size_t index) {
|
||||
return index < m_entries.size() ? &m_entries[index] : nullptr;
|
||||
}
|
||||
const SurfaceEntry* GetSurfaceEntry(size_t index) const {
|
||||
return index < m_entries.size() ? &m_entries[index] : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
static void DestroySurfaceEntry(SurfaceEntry& entry) {
|
||||
if (entry.renderTargetView != nullptr) {
|
||||
entry.renderTargetView->Shutdown();
|
||||
delete entry.renderTargetView;
|
||||
entry.renderTargetView = nullptr;
|
||||
}
|
||||
|
||||
if (entry.shaderResourceView != nullptr) {
|
||||
entry.shaderResourceView->Shutdown();
|
||||
delete entry.shaderResourceView;
|
||||
entry.shaderResourceView = nullptr;
|
||||
}
|
||||
|
||||
if (entry.texture != nullptr) {
|
||||
entry.texture->Shutdown();
|
||||
delete entry.texture;
|
||||
entry.texture = nullptr;
|
||||
}
|
||||
|
||||
entry.surface = RenderSurface();
|
||||
entry.currentColorState = RHI::ResourceStates::Common;
|
||||
}
|
||||
|
||||
bool Matches(
|
||||
const RenderContext& context,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
RHI::Format format,
|
||||
size_t surfaceCount) const;
|
||||
void Reset();
|
||||
size_t surfaceCount) const {
|
||||
return m_device == context.device &&
|
||||
m_width == width &&
|
||||
m_height == height &&
|
||||
m_format == format &&
|
||||
m_entries.size() == surfaceCount;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
for (SurfaceEntry& entry : m_entries) {
|
||||
DestroySurfaceEntry(entry);
|
||||
}
|
||||
|
||||
m_entries.clear();
|
||||
m_device = nullptr;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_format = RHI::Format::Unknown;
|
||||
}
|
||||
|
||||
RHI::RHIDevice* m_device = nullptr;
|
||||
uint32_t m_width = 0;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#include "Rendering/Execution/SceneRenderer.h"
|
||||
|
||||
#include "Components/CameraComponent.h"
|
||||
#include "Rendering/Caches/FullscreenPassSurfaceCache.h"
|
||||
#include "Rendering/Passes/BuiltinColorScalePostProcessPass.h"
|
||||
#include "Rendering/Planning/SceneRenderRequestUtils.h"
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -14,6 +18,8 @@ SceneRenderer::SceneRenderer(std::shared_ptr<const RenderPipelineAsset> pipeline
|
||||
: m_cameraRenderer(std::move(pipelineAsset)) {
|
||||
}
|
||||
|
||||
SceneRenderer::~SceneRenderer() = default;
|
||||
|
||||
void SceneRenderer::SetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
|
||||
m_cameraRenderer.SetPipeline(std::move(pipeline));
|
||||
}
|
||||
@@ -26,8 +32,11 @@ std::vector<CameraRenderRequest> SceneRenderer::BuildRenderRequests(
|
||||
const Components::Scene& scene,
|
||||
Components::CameraComponent* overrideCamera,
|
||||
const RenderContext& context,
|
||||
const RenderSurface& surface) const {
|
||||
return m_requestPlanner.BuildRequests(scene, overrideCamera, context, surface);
|
||||
const RenderSurface& surface) {
|
||||
std::vector<CameraRenderRequest> requests =
|
||||
m_requestPlanner.BuildRequests(scene, overrideCamera, context, surface);
|
||||
AttachCameraPostProcessRequests(context, requests);
|
||||
return requests;
|
||||
}
|
||||
|
||||
bool SceneRenderer::Render(const CameraRenderRequest& request) {
|
||||
@@ -67,5 +76,81 @@ bool SceneRenderer::Render(
|
||||
return Render(BuildRenderRequests(scene, overrideCamera, context, surface));
|
||||
}
|
||||
|
||||
void SceneRenderer::PrepareOwnedCameraPostProcessState(size_t requestCount) {
|
||||
m_ownedPostProcessSequences.clear();
|
||||
m_ownedPostProcessSequences.resize(requestCount);
|
||||
|
||||
if (m_ownedPostProcessSourceSurfaces.size() < requestCount) {
|
||||
m_ownedPostProcessSourceSurfaces.resize(requestCount);
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < requestCount; ++index) {
|
||||
if (m_ownedPostProcessSourceSurfaces[index] == nullptr) {
|
||||
m_ownedPostProcessSourceSurfaces[index] = std::make_unique<FullscreenPassSurfaceCache>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneRenderer::AttachCameraPostProcessRequests(
|
||||
const RenderContext& context,
|
||||
std::vector<CameraRenderRequest>& requests) {
|
||||
PrepareOwnedCameraPostProcessState(requests.size());
|
||||
|
||||
for (size_t index = 0; index < requests.size(); ++index) {
|
||||
CameraRenderRequest& request = requests[index];
|
||||
if (request.camera == nullptr ||
|
||||
!request.camera->IsColorScalePostProcessEnabled() ||
|
||||
request.context.device == nullptr ||
|
||||
!HasValidColorTarget(request.surface)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::vector<RHI::RHIResourceView*>& colorAttachments = request.surface.GetColorAttachments();
|
||||
const RHI::Format colorFormat = colorAttachments[0]->GetFormat();
|
||||
if (colorFormat == RHI::Format::Unknown) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FullscreenPassSurfaceCache* sourceSurfaceCache = m_ownedPostProcessSourceSurfaces[index].get();
|
||||
if (sourceSurfaceCache == nullptr ||
|
||||
!sourceSurfaceCache->EnsureSurfaces(
|
||||
context,
|
||||
request.surface.GetWidth(),
|
||||
request.surface.GetHeight(),
|
||||
colorFormat,
|
||||
1u)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const FullscreenPassSurfaceCache::SurfaceEntry* sourceEntry = sourceSurfaceCache->GetSurfaceEntry(0u);
|
||||
if (sourceEntry == nullptr || sourceEntry->shaderResourceView == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderPassSequence> postProcessSequence = std::make_unique<RenderPassSequence>();
|
||||
postProcessSequence->AddPass(std::make_unique<Passes::BuiltinColorScalePostProcessPass>(
|
||||
request.camera->GetColorScalePostProcessScale()));
|
||||
|
||||
RenderSurface sourceSurface = sourceEntry->surface;
|
||||
sourceSurface.SetDepthAttachment(request.surface.GetDepthAttachment());
|
||||
sourceSurface.SetColorStateBefore(RHI::ResourceStates::Common);
|
||||
sourceSurface.SetColorStateAfter(RHI::ResourceStates::PixelShaderResource);
|
||||
if (request.surface.HasCustomRenderArea()) {
|
||||
sourceSurface.SetRenderArea(request.surface.GetRenderArea());
|
||||
} else {
|
||||
sourceSurface.ResetRenderArea();
|
||||
}
|
||||
if (request.surface.HasClearColorOverride()) {
|
||||
sourceSurface.SetClearColorOverride(request.surface.GetClearColorOverride());
|
||||
}
|
||||
|
||||
request.postProcess.sourceSurface = sourceSurface;
|
||||
request.postProcess.sourceColorView = sourceEntry->shaderResourceView;
|
||||
request.postProcess.destinationSurface = request.surface;
|
||||
m_ownedPostProcessSequences[index] = std::move(postProcessSequence);
|
||||
request.postProcess.passes = m_ownedPostProcessSequences[index].get();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Rendering
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -32,6 +32,11 @@ TEST(CameraComponent_Test, DefaultValues) {
|
||||
EXPECT_FLOAT_EQ(camera.GetSkyboxTopColor().r, 0.18f);
|
||||
EXPECT_FLOAT_EQ(camera.GetSkyboxHorizonColor().g, 0.84f);
|
||||
EXPECT_FLOAT_EQ(camera.GetSkyboxBottomColor().b, 0.95f);
|
||||
EXPECT_FALSE(camera.IsColorScalePostProcessEnabled());
|
||||
EXPECT_FLOAT_EQ(camera.GetColorScalePostProcessScale().x, 1.0f);
|
||||
EXPECT_FLOAT_EQ(camera.GetColorScalePostProcessScale().y, 1.0f);
|
||||
EXPECT_FLOAT_EQ(camera.GetColorScalePostProcessScale().z, 1.0f);
|
||||
EXPECT_FLOAT_EQ(camera.GetColorScalePostProcessScale().w, 1.0f);
|
||||
}
|
||||
|
||||
TEST(CameraComponent_Test, SetterClamping) {
|
||||
@@ -69,6 +74,8 @@ TEST(CameraComponent_Test, SerializeRoundTripPreservesViewportAndClearState) {
|
||||
source.SetSkyboxTopColor(XCEngine::Math::Color(0.12f, 0.21f, 0.64f, 1.0f));
|
||||
source.SetSkyboxHorizonColor(XCEngine::Math::Color(0.71f, 0.76f, 0.88f, 1.0f));
|
||||
source.SetSkyboxBottomColor(XCEngine::Math::Color(0.92f, 0.82f, 0.58f, 1.0f));
|
||||
source.SetColorScalePostProcessEnabled(true);
|
||||
source.SetColorScalePostProcessScale(XCEngine::Math::Vector4(0.55f, 0.8f, 1.2f, 1.0f));
|
||||
|
||||
std::stringstream stream;
|
||||
source.Serialize(stream);
|
||||
@@ -88,6 +95,11 @@ TEST(CameraComponent_Test, SerializeRoundTripPreservesViewportAndClearState) {
|
||||
EXPECT_FLOAT_EQ(target.GetSkyboxTopColor().b, 0.64f);
|
||||
EXPECT_FLOAT_EQ(target.GetSkyboxHorizonColor().g, 0.76f);
|
||||
EXPECT_FLOAT_EQ(target.GetSkyboxBottomColor().r, 0.92f);
|
||||
EXPECT_TRUE(target.IsColorScalePostProcessEnabled());
|
||||
EXPECT_FLOAT_EQ(target.GetColorScalePostProcessScale().x, 0.55f);
|
||||
EXPECT_FLOAT_EQ(target.GetColorScalePostProcessScale().y, 0.8f);
|
||||
EXPECT_FLOAT_EQ(target.GetColorScalePostProcessScale().z, 1.2f);
|
||||
EXPECT_FLOAT_EQ(target.GetColorScalePostProcessScale().w, 1.0f);
|
||||
}
|
||||
|
||||
TEST(LightComponent_Test, DefaultValues) {
|
||||
|
||||
@@ -1770,6 +1770,70 @@ TEST(SceneRenderer_Test, PreservesExistingSurfaceRenderAreaForFullViewportCamera
|
||||
EXPECT_EQ(renderArea.height, 240);
|
||||
}
|
||||
|
||||
TEST(SceneRenderer_Test, BuildsCameraColorScalePostProcessRequestFromCameraSettings) {
|
||||
Scene scene("SceneRendererCameraPostProcessScene");
|
||||
|
||||
GameObject* cameraObject = scene.CreateGameObject("Camera");
|
||||
auto* camera = cameraObject->AddComponent<CameraComponent>();
|
||||
camera->SetPrimary(true);
|
||||
camera->SetDepth(2.0f);
|
||||
camera->SetViewportRect(XCEngine::Math::Rect(0.25f, 0.125f, 0.5f, 0.625f));
|
||||
camera->SetColorScalePostProcessEnabled(true);
|
||||
camera->SetColorScalePostProcessScale(XCEngine::Math::Vector4(0.55f, 0.8f, 1.1f, 1.0f));
|
||||
|
||||
auto allocationState = std::make_shared<MockShadowAllocationState>();
|
||||
MockShadowDevice device(allocationState);
|
||||
|
||||
auto* backBufferColorView = new MockShadowView(
|
||||
allocationState,
|
||||
XCEngine::RHI::ResourceViewType::RenderTarget,
|
||||
XCEngine::RHI::Format::R8G8B8A8_UNorm,
|
||||
XCEngine::RHI::ResourceViewDimension::Texture2D);
|
||||
auto* depthView = new MockShadowView(
|
||||
allocationState,
|
||||
XCEngine::RHI::ResourceViewType::DepthStencil,
|
||||
XCEngine::RHI::Format::D24_UNorm_S8_UInt,
|
||||
XCEngine::RHI::ResourceViewDimension::Texture2D);
|
||||
|
||||
RenderContext context = CreateValidContext();
|
||||
context.device = &device;
|
||||
|
||||
RenderSurface surface(800, 600);
|
||||
surface.SetColorAttachment(backBufferColorView);
|
||||
surface.SetDepthAttachment(depthView);
|
||||
|
||||
SceneRenderer renderer;
|
||||
const std::vector<CameraRenderRequest> requests =
|
||||
renderer.BuildRenderRequests(scene, nullptr, context, surface);
|
||||
|
||||
ASSERT_EQ(requests.size(), 1u);
|
||||
const CameraRenderRequest& request = requests[0];
|
||||
EXPECT_TRUE(request.postProcess.IsRequested());
|
||||
EXPECT_TRUE(request.postProcess.IsValid());
|
||||
EXPECT_NE(request.postProcess.passes, nullptr);
|
||||
ASSERT_EQ(request.postProcess.passes->GetPassCount(), 1u);
|
||||
EXPECT_EQ(request.postProcess.destinationSurface.GetColorAttachments()[0], backBufferColorView);
|
||||
EXPECT_EQ(request.postProcess.destinationSurface.GetDepthAttachment(), depthView);
|
||||
EXPECT_EQ(request.postProcess.sourceSurface.GetDepthAttachment(), depthView);
|
||||
EXPECT_EQ(request.postProcess.sourceSurface.GetWidth(), 800u);
|
||||
EXPECT_EQ(request.postProcess.sourceSurface.GetHeight(), 600u);
|
||||
const XCEngine::Math::RectInt sourceRenderArea = request.postProcess.sourceSurface.GetRenderArea();
|
||||
EXPECT_EQ(sourceRenderArea.x, 200);
|
||||
EXPECT_EQ(sourceRenderArea.y, 75);
|
||||
EXPECT_EQ(sourceRenderArea.width, 400);
|
||||
EXPECT_EQ(sourceRenderArea.height, 375);
|
||||
EXPECT_NE(request.postProcess.sourceColorView, nullptr);
|
||||
EXPECT_NE(request.postProcess.sourceColorView, backBufferColorView);
|
||||
ASSERT_FALSE(request.postProcess.sourceSurface.GetColorAttachments().empty());
|
||||
EXPECT_NE(request.postProcess.sourceSurface.GetColorAttachments()[0], backBufferColorView);
|
||||
EXPECT_EQ(allocationState->createTextureCalls, 1);
|
||||
EXPECT_EQ(allocationState->createRenderTargetViewCalls, 1);
|
||||
EXPECT_EQ(allocationState->createShaderViewCalls, 1);
|
||||
|
||||
delete depthView;
|
||||
delete backBufferColorView;
|
||||
}
|
||||
|
||||
TEST(CameraRenderer_Test, UsesResolvedRenderAreaForCameraViewportDimensions) {
|
||||
Scene scene("CameraRendererViewportRectScene");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user