Fix scene selection outline mask path
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
#include "Passes/SceneViewportSelectionOutlinePass.h"
|
#include "Passes/SceneViewportSelectionOutlinePass.h"
|
||||||
|
|
||||||
|
#include "Viewport/ViewportHostRenderTargets.h"
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
|
|
||||||
@@ -9,11 +11,11 @@ class SceneViewportSelectionOutlinePass final : public Rendering::RenderPass {
|
|||||||
public:
|
public:
|
||||||
SceneViewportSelectionOutlinePass(
|
SceneViewportSelectionOutlinePass(
|
||||||
SceneViewportSelectionOutlinePassRenderer& renderer,
|
SceneViewportSelectionOutlinePassRenderer& renderer,
|
||||||
RHI::RHIResourceView* objectIdTextureView,
|
ViewportRenderTargets* targets,
|
||||||
std::vector<uint64_t> selectedObjectIds,
|
std::vector<uint64_t> selectedObjectIds,
|
||||||
const SceneViewportSelectionOutlineStyle& style)
|
const SceneViewportSelectionOutlineStyle& style)
|
||||||
: m_renderer(renderer)
|
: m_renderer(renderer)
|
||||||
, m_objectIdTextureView(objectIdTextureView)
|
, m_targets(targets)
|
||||||
, m_selectedObjectIds(std::move(selectedObjectIds))
|
, m_selectedObjectIds(std::move(selectedObjectIds))
|
||||||
, m_style(style) {
|
, m_style(style) {
|
||||||
}
|
}
|
||||||
@@ -26,14 +28,15 @@ public:
|
|||||||
return m_renderer.Render(
|
return m_renderer.Render(
|
||||||
context.renderContext,
|
context.renderContext,
|
||||||
context.surface,
|
context.surface,
|
||||||
m_objectIdTextureView,
|
context.sceneData,
|
||||||
|
*m_targets,
|
||||||
m_selectedObjectIds,
|
m_selectedObjectIds,
|
||||||
m_style);
|
m_style);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SceneViewportSelectionOutlinePassRenderer& m_renderer;
|
SceneViewportSelectionOutlinePassRenderer& m_renderer;
|
||||||
RHI::RHIResourceView* m_objectIdTextureView = nullptr;
|
ViewportRenderTargets* m_targets = nullptr;
|
||||||
std::vector<uint64_t> m_selectedObjectIds = {};
|
std::vector<uint64_t> m_selectedObjectIds = {};
|
||||||
SceneViewportSelectionOutlineStyle m_style = {};
|
SceneViewportSelectionOutlineStyle m_style = {};
|
||||||
};
|
};
|
||||||
@@ -41,35 +44,51 @@ private:
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SceneViewportSelectionOutlinePassRenderer::SceneViewportSelectionOutlinePassRenderer()
|
SceneViewportSelectionOutlinePassRenderer::SceneViewportSelectionOutlinePassRenderer()
|
||||||
: m_outlinePass() {
|
: m_selectionMaskPass()
|
||||||
|
, m_outlinePass() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneViewportSelectionOutlinePassRenderer::Shutdown() {
|
void SceneViewportSelectionOutlinePassRenderer::Shutdown() {
|
||||||
|
m_selectionMaskPass.Shutdown();
|
||||||
m_outlinePass.Shutdown();
|
m_outlinePass.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SceneViewportSelectionOutlinePassRenderer::Render(
|
bool SceneViewportSelectionOutlinePassRenderer::Render(
|
||||||
const Rendering::RenderContext& renderContext,
|
const Rendering::RenderContext& renderContext,
|
||||||
const Rendering::RenderSurface& surface,
|
const Rendering::RenderSurface& surface,
|
||||||
RHI::RHIResourceView* objectIdTextureView,
|
const Rendering::RenderSceneData& sceneData,
|
||||||
|
ViewportRenderTargets& targets,
|
||||||
const std::vector<uint64_t>& selectedObjectIds,
|
const std::vector<uint64_t>& selectedObjectIds,
|
||||||
const SceneViewportSelectionOutlineStyle& style) {
|
const SceneViewportSelectionOutlineStyle& style) {
|
||||||
|
Rendering::RenderSurface selectionMaskSurface = BuildViewportSelectionMaskSurface(targets);
|
||||||
|
selectionMaskSurface.SetRenderArea(surface.GetRenderArea());
|
||||||
|
|
||||||
|
if (!m_selectionMaskPass.Render(
|
||||||
|
renderContext,
|
||||||
|
selectionMaskSurface,
|
||||||
|
sceneData,
|
||||||
|
selectedObjectIds)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.selectionMaskState = RHI::ResourceStates::PixelShaderResource;
|
||||||
|
|
||||||
return m_outlinePass.Render(
|
return m_outlinePass.Render(
|
||||||
renderContext,
|
renderContext,
|
||||||
surface,
|
surface,
|
||||||
objectIdTextureView,
|
targets.selectionMaskShaderView,
|
||||||
selectedObjectIds,
|
targets.depthShaderView,
|
||||||
ToBuiltinSceneViewportSelectionOutlineStyle(style));
|
ToBuiltinSceneViewportSelectionOutlineStyle(style));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Rendering::RenderPass> CreateSceneViewportSelectionOutlinePass(
|
std::unique_ptr<Rendering::RenderPass> CreateSceneViewportSelectionOutlinePass(
|
||||||
SceneViewportSelectionOutlinePassRenderer& renderer,
|
SceneViewportSelectionOutlinePassRenderer& renderer,
|
||||||
RHI::RHIResourceView* objectIdTextureView,
|
ViewportRenderTargets* targets,
|
||||||
const std::vector<uint64_t>& selectedObjectIds,
|
const std::vector<uint64_t>& selectedObjectIds,
|
||||||
const SceneViewportSelectionOutlineStyle& style) {
|
const SceneViewportSelectionOutlineStyle& style) {
|
||||||
return std::make_unique<SceneViewportSelectionOutlinePass>(
|
return std::make_unique<SceneViewportSelectionOutlinePass>(
|
||||||
renderer,
|
renderer,
|
||||||
objectIdTextureView,
|
targets,
|
||||||
selectedObjectIds,
|
selectedObjectIds,
|
||||||
style);
|
style);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#include "Viewport/SceneViewportPassSpecs.h"
|
#include "Viewport/SceneViewportPassSpecs.h"
|
||||||
|
|
||||||
#include <XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h>
|
#include <XCEngine/Rendering/Passes/BuiltinSelectionMaskPass.h>
|
||||||
|
#include <XCEngine/Rendering/Passes/BuiltinSelectionOutlinePass.h>
|
||||||
#include <XCEngine/Rendering/RenderContext.h>
|
#include <XCEngine/Rendering/RenderContext.h>
|
||||||
#include <XCEngine/Rendering/RenderPass.h>
|
#include <XCEngine/Rendering/RenderPass.h>
|
||||||
#include <XCEngine/Rendering/RenderSurface.h>
|
#include <XCEngine/Rendering/RenderSurface.h>
|
||||||
@@ -14,6 +15,8 @@
|
|||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
|
|
||||||
|
struct ViewportRenderTargets;
|
||||||
|
|
||||||
class SceneViewportSelectionOutlinePassRenderer {
|
class SceneViewportSelectionOutlinePassRenderer {
|
||||||
public:
|
public:
|
||||||
SceneViewportSelectionOutlinePassRenderer();
|
SceneViewportSelectionOutlinePassRenderer();
|
||||||
@@ -24,17 +27,19 @@ public:
|
|||||||
bool Render(
|
bool Render(
|
||||||
const Rendering::RenderContext& renderContext,
|
const Rendering::RenderContext& renderContext,
|
||||||
const Rendering::RenderSurface& surface,
|
const Rendering::RenderSurface& surface,
|
||||||
RHI::RHIResourceView* objectIdTextureView,
|
const Rendering::RenderSceneData& sceneData,
|
||||||
|
ViewportRenderTargets& targets,
|
||||||
const std::vector<uint64_t>& selectedObjectIds,
|
const std::vector<uint64_t>& selectedObjectIds,
|
||||||
const SceneViewportSelectionOutlineStyle& style);
|
const SceneViewportSelectionOutlineStyle& style);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Rendering::Passes::BuiltinObjectIdOutlinePass m_outlinePass;
|
Rendering::Passes::BuiltinSelectionMaskPass m_selectionMaskPass;
|
||||||
|
Rendering::Passes::BuiltinSelectionOutlinePass m_outlinePass;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Rendering::RenderPass> CreateSceneViewportSelectionOutlinePass(
|
std::unique_ptr<Rendering::RenderPass> CreateSceneViewportSelectionOutlinePass(
|
||||||
SceneViewportSelectionOutlinePassRenderer& renderer,
|
SceneViewportSelectionOutlinePassRenderer& renderer,
|
||||||
RHI::RHIResourceView* objectIdTextureView,
|
ViewportRenderTargets* targets,
|
||||||
const std::vector<uint64_t>& selectedObjectIds,
|
const std::vector<uint64_t>& selectedObjectIds,
|
||||||
const SceneViewportSelectionOutlineStyle& style);
|
const SceneViewportSelectionOutlineStyle& style);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <XCEngine/Core/Math/Color.h>
|
#include <XCEngine/Core/Math/Color.h>
|
||||||
#include <XCEngine/Core/Math/Vector3.h>
|
#include <XCEngine/Core/Math/Vector3.h>
|
||||||
#include <XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h>
|
#include <XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h>
|
||||||
#include <XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h>
|
#include <XCEngine/Rendering/Passes/BuiltinSelectionOutlinePass.h>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
@@ -41,9 +41,9 @@ struct SceneViewportSelectionOutlineStyle {
|
|||||||
bool debugSelectionMask = false;
|
bool debugSelectionMask = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Rendering::Passes::ObjectIdOutlineStyle ToBuiltinSceneViewportSelectionOutlineStyle(
|
inline Rendering::Passes::SelectionOutlineStyle ToBuiltinSceneViewportSelectionOutlineStyle(
|
||||||
const SceneViewportSelectionOutlineStyle& style) {
|
const SceneViewportSelectionOutlineStyle& style) {
|
||||||
Rendering::Passes::ObjectIdOutlineStyle builtinStyle = {};
|
Rendering::Passes::SelectionOutlineStyle builtinStyle = {};
|
||||||
builtinStyle.outlineColor = style.outlineColor;
|
builtinStyle.outlineColor = style.outlineColor;
|
||||||
builtinStyle.outlineWidthPixels = style.outlineWidthPixels;
|
builtinStyle.outlineWidthPixels = style.outlineWidthPixels;
|
||||||
builtinStyle.debugSelectionMask = style.debugSelectionMask;
|
builtinStyle.debugSelectionMask = style.debugSelectionMask;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ void SceneViewportRenderPassBundle::Shutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SceneViewportRenderPlanBuildResult SceneViewportRenderPassBundle::BuildRenderPlan(
|
SceneViewportRenderPlanBuildResult SceneViewportRenderPassBundle::BuildRenderPlan(
|
||||||
const ViewportRenderTargets& targets,
|
ViewportRenderTargets& targets,
|
||||||
const SceneViewportOverlayData& overlay,
|
const SceneViewportOverlayData& overlay,
|
||||||
const std::vector<uint64_t>& selectedObjectIds,
|
const std::vector<uint64_t>& selectedObjectIds,
|
||||||
const SceneViewportOverlayFrameData& editorOverlayFrameData,
|
const SceneViewportOverlayFrameData& editorOverlayFrameData,
|
||||||
@@ -24,12 +24,12 @@ SceneViewportRenderPlanBuildResult SceneViewportRenderPassBundle::BuildRenderPla
|
|||||||
return CreateSceneViewportGridPass(m_gridRenderer, data);
|
return CreateSceneViewportGridPass(m_gridRenderer, data);
|
||||||
},
|
},
|
||||||
[this](
|
[this](
|
||||||
RHI::RHIResourceView* objectIdTextureView,
|
ViewportRenderTargets* outlineTargets,
|
||||||
const std::vector<uint64_t>& selectionIds,
|
const std::vector<uint64_t>& selectionIds,
|
||||||
const SceneViewportSelectionOutlineStyle& style) {
|
const SceneViewportSelectionOutlineStyle& style) {
|
||||||
return CreateSceneViewportSelectionOutlinePass(
|
return CreateSceneViewportSelectionOutlinePass(
|
||||||
m_selectionOutlineRenderer,
|
m_selectionOutlineRenderer,
|
||||||
objectIdTextureView,
|
outlineTargets,
|
||||||
selectionIds,
|
selectionIds,
|
||||||
style);
|
style);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public:
|
|||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
SceneViewportRenderPlanBuildResult BuildRenderPlan(
|
SceneViewportRenderPlanBuildResult BuildRenderPlan(
|
||||||
const ViewportRenderTargets& targets,
|
ViewportRenderTargets& targets,
|
||||||
const SceneViewportOverlayData& overlay,
|
const SceneViewportOverlayData& overlay,
|
||||||
const std::vector<uint64_t>& selectedObjectIds,
|
const std::vector<uint64_t>& selectedObjectIds,
|
||||||
const SceneViewportOverlayFrameData& editorOverlayFrameData,
|
const SceneViewportOverlayFrameData& editorOverlayFrameData,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ using SceneViewportOverlayPassFactory =
|
|||||||
using SceneViewportGridPassFactory =
|
using SceneViewportGridPassFactory =
|
||||||
std::function<std::unique_ptr<Rendering::RenderPass>(const SceneViewportGridPassData&)>;
|
std::function<std::unique_ptr<Rendering::RenderPass>(const SceneViewportGridPassData&)>;
|
||||||
using SceneViewportSelectionOutlinePassFactory = std::function<std::unique_ptr<Rendering::RenderPass>(
|
using SceneViewportSelectionOutlinePassFactory = std::function<std::unique_ptr<Rendering::RenderPass>(
|
||||||
RHI::RHIResourceView*,
|
ViewportRenderTargets*,
|
||||||
const std::vector<uint64_t>&,
|
const std::vector<uint64_t>&,
|
||||||
const SceneViewportSelectionOutlineStyle&)>;
|
const SceneViewportSelectionOutlineStyle&)>;
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ struct SceneViewportRenderPlanBuildResult {
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline SceneViewportRenderPlanBuildResult BuildSceneViewportRenderPlan(
|
inline SceneViewportRenderPlanBuildResult BuildSceneViewportRenderPlan(
|
||||||
const ViewportRenderTargets& targets,
|
ViewportRenderTargets& targets,
|
||||||
const SceneViewportOverlayData& overlay,
|
const SceneViewportOverlayData& overlay,
|
||||||
const std::vector<uint64_t>& selectedObjectIds,
|
const std::vector<uint64_t>& selectedObjectIds,
|
||||||
const SceneViewportOverlayFrameData& editorOverlayFrameData,
|
const SceneViewportOverlayFrameData& editorOverlayFrameData,
|
||||||
@@ -69,18 +69,21 @@ inline SceneViewportRenderPlanBuildResult BuildSceneViewportRenderPlan(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!selectedObjectIds.empty()) {
|
if (!selectedObjectIds.empty()) {
|
||||||
if (targets.objectIdShaderView != nullptr &&
|
if (targets.selectionMaskView != nullptr &&
|
||||||
|
targets.selectionMaskShaderView != nullptr &&
|
||||||
|
targets.depthView != nullptr &&
|
||||||
|
targets.depthShaderView != nullptr &&
|
||||||
selectionOutlinePassFactory != nullptr) {
|
selectionOutlinePassFactory != nullptr) {
|
||||||
std::unique_ptr<Rendering::RenderPass> selectionOutlinePass =
|
std::unique_ptr<Rendering::RenderPass> selectionOutlinePass =
|
||||||
selectionOutlinePassFactory(
|
selectionOutlinePassFactory(
|
||||||
targets.objectIdShaderView,
|
&targets,
|
||||||
selectedObjectIds,
|
selectedObjectIds,
|
||||||
BuildSceneViewportSelectionOutlineStyle(debugSelectionMask));
|
BuildSceneViewportSelectionOutlineStyle(debugSelectionMask));
|
||||||
if (selectionOutlinePass != nullptr) {
|
if (selectionOutlinePass != nullptr) {
|
||||||
result.plan.postScenePasses.AddPass(std::move(selectionOutlinePass));
|
result.plan.postScenePasses.AddPass(std::move(selectionOutlinePass));
|
||||||
}
|
}
|
||||||
} else if (!debugSelectionMask) {
|
} else if (!debugSelectionMask) {
|
||||||
result.warningStatusText = "Scene object id shader view is unavailable";
|
result.warningStatusText = "Scene selection outline resources are unavailable";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ inline void ApplySceneViewportRenderRequestSetup(
|
|||||||
request.postScenePasses = postPasses;
|
request.postScenePasses = postPasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targets.objectIdView == nullptr) {
|
if (targets.objectIdView == nullptr || targets.objectIdDepthView == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +165,7 @@ inline void MarkSceneViewportRenderSuccess(
|
|||||||
const Rendering::CameraRenderRequest& request) {
|
const Rendering::CameraRenderRequest& request) {
|
||||||
targets.colorState = RHI::ResourceStates::PixelShaderResource;
|
targets.colorState = RHI::ResourceStates::PixelShaderResource;
|
||||||
targets.objectIdState = RHI::ResourceStates::PixelShaderResource;
|
targets.objectIdState = RHI::ResourceStates::PixelShaderResource;
|
||||||
|
targets.selectionMaskState = RHI::ResourceStates::PixelShaderResource;
|
||||||
targets.hasValidObjectIdFrame = request.objectId.IsRequested();
|
targets.hasValidObjectIdFrame = request.objectId.IsRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,14 +18,21 @@ struct ViewportRenderTargets {
|
|||||||
RHI::RHIResourceView* colorView = nullptr;
|
RHI::RHIResourceView* colorView = nullptr;
|
||||||
RHI::RHITexture* depthTexture = nullptr;
|
RHI::RHITexture* depthTexture = nullptr;
|
||||||
RHI::RHIResourceView* depthView = nullptr;
|
RHI::RHIResourceView* depthView = nullptr;
|
||||||
|
RHI::RHIResourceView* depthShaderView = nullptr;
|
||||||
RHI::RHITexture* objectIdTexture = nullptr;
|
RHI::RHITexture* objectIdTexture = nullptr;
|
||||||
|
RHI::RHITexture* objectIdDepthTexture = nullptr;
|
||||||
|
RHI::RHIResourceView* objectIdDepthView = nullptr;
|
||||||
RHI::RHIResourceView* objectIdView = nullptr;
|
RHI::RHIResourceView* objectIdView = nullptr;
|
||||||
RHI::RHIResourceView* objectIdShaderView = nullptr;
|
RHI::RHIResourceView* objectIdShaderView = nullptr;
|
||||||
|
RHI::RHITexture* selectionMaskTexture = nullptr;
|
||||||
|
RHI::RHIResourceView* selectionMaskView = nullptr;
|
||||||
|
RHI::RHIResourceView* selectionMaskShaderView = nullptr;
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE imguiCpuHandle = {};
|
D3D12_CPU_DESCRIPTOR_HANDLE imguiCpuHandle = {};
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE imguiGpuHandle = {};
|
D3D12_GPU_DESCRIPTOR_HANDLE imguiGpuHandle = {};
|
||||||
::XCEngine::UI::UITextureHandle textureHandle = {};
|
::XCEngine::UI::UITextureHandle textureHandle = {};
|
||||||
RHI::ResourceStates colorState = RHI::ResourceStates::Common;
|
RHI::ResourceStates colorState = RHI::ResourceStates::Common;
|
||||||
RHI::ResourceStates objectIdState = RHI::ResourceStates::Common;
|
RHI::ResourceStates objectIdState = RHI::ResourceStates::Common;
|
||||||
|
RHI::ResourceStates selectionMaskState = RHI::ResourceStates::Common;
|
||||||
bool hasValidObjectIdFrame = false;
|
bool hasValidObjectIdFrame = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -44,9 +51,15 @@ inline ViewportHostResourceReuseQuery BuildViewportRenderTargetsReuseQuery(
|
|||||||
query.resources.hasColorView = targets.colorView != nullptr;
|
query.resources.hasColorView = targets.colorView != nullptr;
|
||||||
query.resources.hasDepthTexture = targets.depthTexture != nullptr;
|
query.resources.hasDepthTexture = targets.depthTexture != nullptr;
|
||||||
query.resources.hasDepthView = targets.depthView != nullptr;
|
query.resources.hasDepthView = targets.depthView != nullptr;
|
||||||
|
query.resources.hasDepthShaderView = targets.depthShaderView != nullptr;
|
||||||
query.resources.hasObjectIdTexture = targets.objectIdTexture != nullptr;
|
query.resources.hasObjectIdTexture = targets.objectIdTexture != nullptr;
|
||||||
|
query.resources.hasObjectIdDepthTexture = targets.objectIdDepthTexture != nullptr;
|
||||||
|
query.resources.hasObjectIdDepthView = targets.objectIdDepthView != nullptr;
|
||||||
query.resources.hasObjectIdView = targets.objectIdView != nullptr;
|
query.resources.hasObjectIdView = targets.objectIdView != nullptr;
|
||||||
query.resources.hasObjectIdShaderView = targets.objectIdShaderView != nullptr;
|
query.resources.hasObjectIdShaderView = targets.objectIdShaderView != nullptr;
|
||||||
|
query.resources.hasSelectionMaskTexture = targets.selectionMaskTexture != nullptr;
|
||||||
|
query.resources.hasSelectionMaskView = targets.selectionMaskView != nullptr;
|
||||||
|
query.resources.hasSelectionMaskShaderView = targets.selectionMaskShaderView != nullptr;
|
||||||
query.resources.hasTextureDescriptor = targets.textureHandle.IsValid();
|
query.resources.hasTextureDescriptor = targets.textureHandle.IsValid();
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
@@ -65,10 +78,19 @@ inline Rendering::RenderSurface BuildViewportObjectIdSurface(const ViewportRende
|
|||||||
targets.width,
|
targets.width,
|
||||||
targets.height,
|
targets.height,
|
||||||
targets.objectIdView,
|
targets.objectIdView,
|
||||||
targets.depthView,
|
targets.objectIdDepthView,
|
||||||
targets.objectIdState);
|
targets.objectIdState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Rendering::RenderSurface BuildViewportSelectionMaskSurface(const ViewportRenderTargets& targets) {
|
||||||
|
return BuildViewportRenderSurface(
|
||||||
|
targets.width,
|
||||||
|
targets.height,
|
||||||
|
targets.selectionMaskView,
|
||||||
|
targets.depthView,
|
||||||
|
targets.selectionMaskState);
|
||||||
|
}
|
||||||
|
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
|
|
||||||
template <typename ResourceType>
|
template <typename ResourceType>
|
||||||
@@ -111,7 +133,17 @@ inline bool CreateViewportDepthResources(
|
|||||||
const RHI::ResourceViewDesc depthViewDesc =
|
const RHI::ResourceViewDesc depthViewDesc =
|
||||||
BuildViewportTextureViewDesc(RHI::Format::D24_UNorm_S8_UInt);
|
BuildViewportTextureViewDesc(RHI::Format::D24_UNorm_S8_UInt);
|
||||||
targets.depthView = device->CreateDepthStencilView(targets.depthTexture, depthViewDesc);
|
targets.depthView = device->CreateDepthStencilView(targets.depthTexture, depthViewDesc);
|
||||||
return targets.depthView != nullptr;
|
if (targets.depthView == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RHI::ResourceViewDesc depthShaderViewDesc = {};
|
||||||
|
depthShaderViewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
|
||||||
|
depthShaderViewDesc.mipLevel = 0;
|
||||||
|
targets.depthShaderView = device->CreateShaderResourceView(
|
||||||
|
targets.depthTexture,
|
||||||
|
depthShaderViewDesc);
|
||||||
|
return targets.depthShaderView != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool CreateViewportObjectIdResources(
|
inline bool CreateViewportObjectIdResources(
|
||||||
@@ -136,7 +168,48 @@ inline bool CreateViewportObjectIdResources(
|
|||||||
targets.objectIdShaderView = device->CreateShaderResourceView(
|
targets.objectIdShaderView = device->CreateShaderResourceView(
|
||||||
targets.objectIdTexture,
|
targets.objectIdTexture,
|
||||||
objectIdViewDesc);
|
objectIdViewDesc);
|
||||||
return targets.objectIdShaderView != nullptr;
|
if (targets.objectIdShaderView == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RHI::TextureDesc objectIdDepthDesc =
|
||||||
|
BuildViewportTextureDesc(targets.width, targets.height, RHI::Format::D24_UNorm_S8_UInt);
|
||||||
|
targets.objectIdDepthTexture = device->CreateTexture(objectIdDepthDesc);
|
||||||
|
if (targets.objectIdDepthTexture == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RHI::ResourceViewDesc objectIdDepthViewDesc =
|
||||||
|
BuildViewportTextureViewDesc(RHI::Format::D24_UNorm_S8_UInt);
|
||||||
|
targets.objectIdDepthView = device->CreateDepthStencilView(
|
||||||
|
targets.objectIdDepthTexture,
|
||||||
|
objectIdDepthViewDesc);
|
||||||
|
return targets.objectIdDepthView != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool CreateViewportSelectionMaskResources(
|
||||||
|
RHI::RHIDevice* device,
|
||||||
|
ViewportRenderTargets& targets) {
|
||||||
|
const RHI::TextureDesc selectionMaskDesc =
|
||||||
|
BuildViewportTextureDesc(targets.width, targets.height, RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
targets.selectionMaskTexture = device->CreateTexture(selectionMaskDesc);
|
||||||
|
if (targets.selectionMaskTexture == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RHI::ResourceViewDesc selectionMaskViewDesc =
|
||||||
|
BuildViewportTextureViewDesc(RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
targets.selectionMaskView = device->CreateRenderTargetView(
|
||||||
|
targets.selectionMaskTexture,
|
||||||
|
selectionMaskViewDesc);
|
||||||
|
if (targets.selectionMaskView == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.selectionMaskShaderView = device->CreateShaderResourceView(
|
||||||
|
targets.selectionMaskTexture,
|
||||||
|
selectionMaskViewDesc);
|
||||||
|
return targets.selectionMaskShaderView != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool CreateViewportTextureDescriptor(
|
inline bool CreateViewportTextureDescriptor(
|
||||||
@@ -170,7 +243,13 @@ inline void DestroyViewportRenderTargets(
|
|||||||
|
|
||||||
Detail::ShutdownAndDelete(targets.objectIdView);
|
Detail::ShutdownAndDelete(targets.objectIdView);
|
||||||
Detail::ShutdownAndDelete(targets.objectIdShaderView);
|
Detail::ShutdownAndDelete(targets.objectIdShaderView);
|
||||||
|
Detail::ShutdownAndDelete(targets.objectIdDepthView);
|
||||||
|
Detail::ShutdownAndDelete(targets.objectIdDepthTexture);
|
||||||
Detail::ShutdownAndDelete(targets.objectIdTexture);
|
Detail::ShutdownAndDelete(targets.objectIdTexture);
|
||||||
|
Detail::ShutdownAndDelete(targets.selectionMaskView);
|
||||||
|
Detail::ShutdownAndDelete(targets.selectionMaskShaderView);
|
||||||
|
Detail::ShutdownAndDelete(targets.selectionMaskTexture);
|
||||||
|
Detail::ShutdownAndDelete(targets.depthShaderView);
|
||||||
Detail::ShutdownAndDelete(targets.depthView);
|
Detail::ShutdownAndDelete(targets.depthView);
|
||||||
Detail::ShutdownAndDelete(targets.depthTexture);
|
Detail::ShutdownAndDelete(targets.depthTexture);
|
||||||
Detail::ShutdownAndDelete(targets.colorView);
|
Detail::ShutdownAndDelete(targets.colorView);
|
||||||
@@ -183,6 +262,7 @@ inline void DestroyViewportRenderTargets(
|
|||||||
targets.textureHandle = {};
|
targets.textureHandle = {};
|
||||||
targets.colorState = RHI::ResourceStates::Common;
|
targets.colorState = RHI::ResourceStates::Common;
|
||||||
targets.objectIdState = RHI::ResourceStates::Common;
|
targets.objectIdState = RHI::ResourceStates::Common;
|
||||||
|
targets.selectionMaskState = RHI::ResourceStates::Common;
|
||||||
targets.hasValidObjectIdFrame = false;
|
targets.hasValidObjectIdFrame = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +284,8 @@ inline bool CreateViewportRenderTargets(
|
|||||||
if (!Detail::CreateViewportColorResources(device, targets) ||
|
if (!Detail::CreateViewportColorResources(device, targets) ||
|
||||||
!Detail::CreateViewportDepthResources(device, targets) ||
|
!Detail::CreateViewportDepthResources(device, targets) ||
|
||||||
(ViewportRequiresObjectIdResources(kind) &&
|
(ViewportRequiresObjectIdResources(kind) &&
|
||||||
!Detail::CreateViewportObjectIdResources(device, targets)) ||
|
(!Detail::CreateViewportObjectIdResources(device, targets) ||
|
||||||
|
!Detail::CreateViewportSelectionMaskResources(device, targets))) ||
|
||||||
!Detail::CreateViewportTextureDescriptor(backend, device, targets)) {
|
!Detail::CreateViewportTextureDescriptor(backend, device, targets)) {
|
||||||
DestroyViewportRenderTargets(backend, targets);
|
DestroyViewportRenderTargets(backend, targets);
|
||||||
return false;
|
return false;
|
||||||
@@ -212,6 +293,7 @@ inline bool CreateViewportRenderTargets(
|
|||||||
|
|
||||||
targets.colorState = RHI::ResourceStates::Common;
|
targets.colorState = RHI::ResourceStates::Common;
|
||||||
targets.objectIdState = RHI::ResourceStates::Common;
|
targets.objectIdState = RHI::ResourceStates::Common;
|
||||||
|
targets.selectionMaskState = RHI::ResourceStates::Common;
|
||||||
targets.hasValidObjectIdFrame = false;
|
targets.hasValidObjectIdFrame = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,15 @@ struct ViewportHostResourcePresence {
|
|||||||
bool hasColorView = false;
|
bool hasColorView = false;
|
||||||
bool hasDepthTexture = false;
|
bool hasDepthTexture = false;
|
||||||
bool hasDepthView = false;
|
bool hasDepthView = false;
|
||||||
|
bool hasDepthShaderView = false;
|
||||||
bool hasObjectIdTexture = false;
|
bool hasObjectIdTexture = false;
|
||||||
|
bool hasObjectIdDepthTexture = false;
|
||||||
|
bool hasObjectIdDepthView = false;
|
||||||
bool hasObjectIdView = false;
|
bool hasObjectIdView = false;
|
||||||
bool hasObjectIdShaderView = false;
|
bool hasObjectIdShaderView = false;
|
||||||
|
bool hasSelectionMaskTexture = false;
|
||||||
|
bool hasSelectionMaskView = false;
|
||||||
|
bool hasSelectionMaskShaderView = false;
|
||||||
bool hasTextureDescriptor = false;
|
bool hasTextureDescriptor = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,8 +76,14 @@ inline bool CanReuseViewportResources(const ViewportHostResourceReuseQuery& quer
|
|||||||
}
|
}
|
||||||
|
|
||||||
return query.resources.hasObjectIdTexture &&
|
return query.resources.hasObjectIdTexture &&
|
||||||
|
query.resources.hasObjectIdDepthTexture &&
|
||||||
|
query.resources.hasObjectIdDepthView &&
|
||||||
query.resources.hasObjectIdView &&
|
query.resources.hasObjectIdView &&
|
||||||
query.resources.hasObjectIdShaderView;
|
query.resources.hasObjectIdShaderView &&
|
||||||
|
query.resources.hasDepthShaderView &&
|
||||||
|
query.resources.hasSelectionMaskTexture &&
|
||||||
|
query.resources.hasSelectionMaskView &&
|
||||||
|
query.resources.hasSelectionMaskShaderView;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline RHI::TextureDesc BuildViewportTextureDesc(
|
inline RHI::TextureDesc BuildViewportTextureDesc(
|
||||||
|
|||||||
@@ -484,10 +484,12 @@ add_library(XCEngine STATIC
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinDepthOnlyPass.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinDepthOnlyPass.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinShadowCasterPass.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinShadowCasterPass.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinObjectIdPass.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinObjectIdPass.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinSelectionMaskPass.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinColorScalePostProcessPass.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinColorScalePostProcessPass.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinFinalColorPass.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinFinalColorPass.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinSelectionOutlinePass.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinVolumetricPass.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinVolumetricPass.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/CameraRenderer.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/CameraRenderer.cpp
|
||||||
@@ -499,10 +501,12 @@ add_library(XCEngine STATIC
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinShadowCasterPass.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinShadowCasterPass.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdPass.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdPass.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdPassResources.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdPassResources.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinSelectionMaskPass.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinColorScalePostProcessPass.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinColorScalePostProcessPass.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinFinalColorPass.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinFinalColorPass.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdOutlinePass.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdOutlinePass.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinSelectionOutlinePass.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinVolumetricPass.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinVolumetricPass.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderSurface.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderSurface.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Extraction/RenderSceneExtractor.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Extraction/RenderSceneExtractor.cpp
|
||||||
|
|||||||
78
engine/assets/builtin/shaders/selection-mask.shader
Normal file
78
engine/assets/builtin/shaders/selection-mask.shader
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
Shader "Builtin Selection Mask"
|
||||||
|
{
|
||||||
|
Properties
|
||||||
|
{
|
||||||
|
_BaseColor ("Base Color", Color) = (1,1,1,1) [Semantic(BaseColor)]
|
||||||
|
_Cutoff ("Alpha Cutoff", Range) = 0.5 [Semantic(AlphaCutoff)]
|
||||||
|
_MainTex ("Base Map", 2D) = "white" [Semantic(BaseColorTexture)]
|
||||||
|
}
|
||||||
|
HLSLINCLUDE
|
||||||
|
// XC_BUILTIN_SELECTION_MASK_D3D12_SHARED
|
||||||
|
cbuffer PerObjectConstants
|
||||||
|
{
|
||||||
|
float4x4 gProjectionMatrix;
|
||||||
|
float4x4 gViewMatrix;
|
||||||
|
float4x4 gModelMatrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
cbuffer MaterialConstants
|
||||||
|
{
|
||||||
|
float4 gBaseColorFactor;
|
||||||
|
float4 gAlphaCutoffParams;
|
||||||
|
};
|
||||||
|
|
||||||
|
Texture2D BaseColorTexture;
|
||||||
|
SamplerState LinearClampSampler;
|
||||||
|
|
||||||
|
struct VSInput
|
||||||
|
{
|
||||||
|
float3 position : POSITION;
|
||||||
|
float3 normal : NORMAL;
|
||||||
|
float2 texcoord : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PSInput
|
||||||
|
{
|
||||||
|
float4 position : SV_POSITION;
|
||||||
|
float2 texcoord : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
PSInput MainVS(VSInput input)
|
||||||
|
{
|
||||||
|
PSInput output;
|
||||||
|
const float4 positionWS = mul(gModelMatrix, float4(input.position, 1.0f));
|
||||||
|
const float4 positionVS = mul(gViewMatrix, positionWS);
|
||||||
|
output.position = mul(gProjectionMatrix, positionVS);
|
||||||
|
output.texcoord = input.texcoord;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 MainPS(PSInput input) : SV_TARGET
|
||||||
|
{
|
||||||
|
// XC_BUILTIN_SELECTION_MASK_D3D12_PS
|
||||||
|
#ifdef XC_ALPHA_TEST
|
||||||
|
const float4 baseColor =
|
||||||
|
BaseColorTexture.Sample(LinearClampSampler, input.texcoord) * gBaseColorFactor;
|
||||||
|
clip(baseColor.a - gAlphaCutoffParams.x);
|
||||||
|
#endif
|
||||||
|
return float4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
ENDHLSL
|
||||||
|
SubShader
|
||||||
|
{
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "SelectionMask"
|
||||||
|
Tags { "LightMode" = "SelectionMask" }
|
||||||
|
Cull Back
|
||||||
|
ZWrite Off
|
||||||
|
ZTest LEqual
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
#pragma vertex MainVS
|
||||||
|
#pragma fragment MainPS
|
||||||
|
#pragma shader_feature_local _ XC_ALPHA_TEST
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
131
engine/assets/builtin/shaders/selection-outline.shader
Normal file
131
engine/assets/builtin/shaders/selection-outline.shader
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
Shader "Builtin Selection Outline"
|
||||||
|
{
|
||||||
|
HLSLINCLUDE
|
||||||
|
// XC_BUILTIN_SELECTION_OUTLINE_D3D12_SHARED
|
||||||
|
cbuffer OutlineConstants
|
||||||
|
{
|
||||||
|
float4 gViewportSizeAndTexelSize;
|
||||||
|
float4 gOutlineColor;
|
||||||
|
float4 gOutlineInfo;
|
||||||
|
float4 gDepthParams;
|
||||||
|
};
|
||||||
|
|
||||||
|
Texture2D gSelectionMaskTexture;
|
||||||
|
Texture2D gDepthTexture;
|
||||||
|
|
||||||
|
struct VSOutput
|
||||||
|
{
|
||||||
|
float4 position : SV_POSITION;
|
||||||
|
};
|
||||||
|
|
||||||
|
VSOutput MainVS(uint vertexId : SV_VertexID)
|
||||||
|
{
|
||||||
|
// XC_BUILTIN_SELECTION_OUTLINE_D3D12_VS
|
||||||
|
static const float2 positions[3] = {
|
||||||
|
float2(-1.0, -1.0),
|
||||||
|
float2(-1.0, 3.0),
|
||||||
|
float2( 3.0, -1.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
VSOutput output;
|
||||||
|
output.position = float4(positions[vertexId], 0.0, 1.0);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int2 ClampPixelCoord(int2 pixelCoord)
|
||||||
|
{
|
||||||
|
const int2 maxCoord = int2(
|
||||||
|
max((int)gViewportSizeAndTexelSize.x - 1, 0),
|
||||||
|
max((int)gViewportSizeAndTexelSize.y - 1, 0));
|
||||||
|
return clamp(pixelCoord, int2(0, 0), maxCoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
float LoadSelectionMask(int2 pixelCoord)
|
||||||
|
{
|
||||||
|
return gSelectionMaskTexture.Load(int3(ClampPixelCoord(pixelCoord), 0)).r;
|
||||||
|
}
|
||||||
|
|
||||||
|
float LoadDepth(int2 pixelCoord)
|
||||||
|
{
|
||||||
|
return gDepthTexture.Load(int3(ClampPixelCoord(pixelCoord), 0)).r;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSelectedPixel(float maskValue)
|
||||||
|
{
|
||||||
|
return maskValue > 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 MainPS(VSOutput input) : SV_TARGET
|
||||||
|
{
|
||||||
|
// XC_BUILTIN_SELECTION_OUTLINE_D3D12_PS
|
||||||
|
const int2 pixelCoord = int2(input.position.xy);
|
||||||
|
const bool debugSelectionMask = gOutlineInfo.x > 0.5;
|
||||||
|
const bool centerSelected = IsSelectedPixel(LoadSelectionMask(pixelCoord));
|
||||||
|
|
||||||
|
if (debugSelectionMask) {
|
||||||
|
return centerSelected ? float4(1.0, 1.0, 1.0, 1.0) : float4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (centerSelected) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float centerDepth = LoadDepth(pixelCoord);
|
||||||
|
const int outlineWidth = max((int)gOutlineInfo.y, 1);
|
||||||
|
const float depthThreshold = max(gDepthParams.x, 1.0e-6f);
|
||||||
|
|
||||||
|
float outline = 0.0;
|
||||||
|
[loop]
|
||||||
|
for (int y = -2; y <= 2; ++y) {
|
||||||
|
[loop]
|
||||||
|
for (int x = -2; x <= 2; ++x) {
|
||||||
|
if (x == 0 && y == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float distancePixels = length(float2((float)x, (float)y));
|
||||||
|
if (distancePixels > outlineWidth) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int2 sampleCoord = pixelCoord + int2(x, y);
|
||||||
|
if (!IsSelectedPixel(LoadSelectionMask(sampleCoord))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float selectedDepth = LoadDepth(sampleCoord);
|
||||||
|
if (!(centerDepth > selectedDepth + depthThreshold)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float weight = saturate(
|
||||||
|
1.0 - ((distancePixels - 1.0) / max((float)outlineWidth, 1.0)));
|
||||||
|
outline = max(outline, weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outline <= 0.001) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
return float4(gOutlineColor.rgb, gOutlineColor.a * outline);
|
||||||
|
}
|
||||||
|
ENDHLSL
|
||||||
|
SubShader
|
||||||
|
{
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "SelectionOutline"
|
||||||
|
Tags { "LightMode" = "SelectionOutline" }
|
||||||
|
Cull Off
|
||||||
|
ZWrite Off
|
||||||
|
ZTest Always
|
||||||
|
Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
#pragma vertex MainVS
|
||||||
|
#pragma fragment MainPS
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -226,7 +226,8 @@ inline bool TryBuildBuiltinPassDefaultResourceBindings(
|
|||||||
|
|
||||||
if (ShaderPassMatchesBuiltinPass(shaderPass, BuiltinMaterialPass::Unlit) ||
|
if (ShaderPassMatchesBuiltinPass(shaderPass, BuiltinMaterialPass::Unlit) ||
|
||||||
ShaderPassMatchesBuiltinPass(shaderPass, BuiltinMaterialPass::DepthOnly) ||
|
ShaderPassMatchesBuiltinPass(shaderPass, BuiltinMaterialPass::DepthOnly) ||
|
||||||
ShaderPassMatchesBuiltinPass(shaderPass, BuiltinMaterialPass::ShadowCaster)) {
|
ShaderPassMatchesBuiltinPass(shaderPass, BuiltinMaterialPass::ShadowCaster) ||
|
||||||
|
ShaderPassMatchesBuiltinPass(shaderPass, BuiltinMaterialPass::SelectionMask)) {
|
||||||
AppendBuiltinPassResourceBinding(
|
AppendBuiltinPassResourceBinding(
|
||||||
outBindings,
|
outBindings,
|
||||||
"PerObjectConstants",
|
"PerObjectConstants",
|
||||||
@@ -318,10 +319,17 @@ inline bool TryBuildBuiltinPassDefaultResourceBindings(
|
|||||||
"PerObject");
|
"PerObject");
|
||||||
AppendBuiltinPassResourceBinding(
|
AppendBuiltinPassResourceBinding(
|
||||||
outBindings,
|
outBindings,
|
||||||
"MaterialConstants",
|
"LightingConstants",
|
||||||
Resources::ShaderResourceType::ConstantBuffer,
|
Resources::ShaderResourceType::ConstantBuffer,
|
||||||
1u,
|
1u,
|
||||||
0u,
|
0u,
|
||||||
|
"Lighting");
|
||||||
|
AppendBuiltinPassResourceBinding(
|
||||||
|
outBindings,
|
||||||
|
"MaterialConstants",
|
||||||
|
Resources::ShaderResourceType::ConstantBuffer,
|
||||||
|
2u,
|
||||||
|
0u,
|
||||||
"Material");
|
"Material");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ inline const char* GetBuiltinPassCanonicalName(BuiltinMaterialPass pass) {
|
|||||||
return "shadowcaster";
|
return "shadowcaster";
|
||||||
case BuiltinMaterialPass::ObjectId:
|
case BuiltinMaterialPass::ObjectId:
|
||||||
return "objectid";
|
return "objectid";
|
||||||
|
case BuiltinMaterialPass::SelectionMask:
|
||||||
|
return "selectionmask";
|
||||||
case BuiltinMaterialPass::Skybox:
|
case BuiltinMaterialPass::Skybox:
|
||||||
return "skybox";
|
return "skybox";
|
||||||
case BuiltinMaterialPass::Volumetric:
|
case BuiltinMaterialPass::Volumetric:
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ enum class BuiltinMaterialPass : Core::uint32 {
|
|||||||
DepthOnly,
|
DepthOnly,
|
||||||
ShadowCaster,
|
ShadowCaster,
|
||||||
ObjectId,
|
ObjectId,
|
||||||
|
SelectionMask,
|
||||||
Skybox,
|
Skybox,
|
||||||
Volumetric,
|
Volumetric,
|
||||||
PostProcess,
|
PostProcess,
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/Rendering/Passes/BuiltinDepthStylePassBase.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace Rendering {
|
||||||
|
|
||||||
|
struct RenderSceneData;
|
||||||
|
struct VisibleRenderItem;
|
||||||
|
|
||||||
|
namespace Passes {
|
||||||
|
|
||||||
|
class BuiltinSelectionMaskPass final : public BuiltinDepthStylePassBase {
|
||||||
|
public:
|
||||||
|
BuiltinSelectionMaskPass();
|
||||||
|
~BuiltinSelectionMaskPass() override = default;
|
||||||
|
|
||||||
|
static RHI::InputLayoutDesc BuildInputLayout();
|
||||||
|
|
||||||
|
const char* GetName() const override;
|
||||||
|
|
||||||
|
bool Render(
|
||||||
|
const RenderContext& context,
|
||||||
|
const RenderSurface& surface,
|
||||||
|
const RenderSceneData& sceneData,
|
||||||
|
const std::vector<uint64_t>& selectedObjectIds);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool ShouldRenderVisibleItem(const VisibleRenderItem& visibleItem) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint64_t> m_selectedObjectIds = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Passes
|
||||||
|
} // namespace Rendering
|
||||||
|
} // namespace XCEngine
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/Core/Asset/ResourceHandle.h>
|
||||||
|
#include <XCEngine/Core/Containers/String.h>
|
||||||
|
#include <XCEngine/Core/Math/Color.h>
|
||||||
|
#include <XCEngine/Core/Math/Vector4.h>
|
||||||
|
#include <XCEngine/Rendering/RenderContext.h>
|
||||||
|
#include <XCEngine/Rendering/RenderSurface.h>
|
||||||
|
|
||||||
|
#include <XCEngine/RHI/RHIDescriptorPool.h>
|
||||||
|
#include <XCEngine/RHI/RHIDescriptorSet.h>
|
||||||
|
#include <XCEngine/RHI/RHIEnums.h>
|
||||||
|
#include <XCEngine/RHI/RHIPipelineLayout.h>
|
||||||
|
#include <XCEngine/RHI/RHIPipelineState.h>
|
||||||
|
#include <XCEngine/RHI/RHIResourceView.h>
|
||||||
|
#include <XCEngine/Resources/Shader/Shader.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace Rendering {
|
||||||
|
namespace Passes {
|
||||||
|
|
||||||
|
struct SelectionOutlineStyle {
|
||||||
|
Math::Color outlineColor = Math::Color(1.0f, 0.4f, 0.0f, 1.0f);
|
||||||
|
float outlineWidthPixels = 2.0f;
|
||||||
|
bool debugSelectionMask = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BuiltinSelectionOutlinePass {
|
||||||
|
public:
|
||||||
|
explicit BuiltinSelectionOutlinePass(Containers::String shaderPath = Containers::String());
|
||||||
|
~BuiltinSelectionOutlinePass() = default;
|
||||||
|
BuiltinSelectionOutlinePass(const BuiltinSelectionOutlinePass&) = delete;
|
||||||
|
BuiltinSelectionOutlinePass& operator=(const BuiltinSelectionOutlinePass&) = delete;
|
||||||
|
BuiltinSelectionOutlinePass(BuiltinSelectionOutlinePass&&) = delete;
|
||||||
|
BuiltinSelectionOutlinePass& operator=(BuiltinSelectionOutlinePass&&) = delete;
|
||||||
|
|
||||||
|
void SetShaderPath(const Containers::String& shaderPath);
|
||||||
|
const Containers::String& GetShaderPath() const;
|
||||||
|
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
bool Render(
|
||||||
|
const RenderContext& renderContext,
|
||||||
|
const RenderSurface& surface,
|
||||||
|
RHI::RHIResourceView* selectionMaskTextureView,
|
||||||
|
RHI::RHIResourceView* depthTextureView,
|
||||||
|
const SelectionOutlineStyle& style = {});
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct OutlineConstants {
|
||||||
|
Math::Vector4 viewportSizeAndTexelSize = Math::Vector4::Zero();
|
||||||
|
Math::Vector4 outlineColor = Math::Vector4::Zero();
|
||||||
|
Math::Vector4 outlineInfo = Math::Vector4::Zero();
|
||||||
|
Math::Vector4 depthParams = Math::Vector4::Zero();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool EnsureInitialized(const RenderContext& renderContext);
|
||||||
|
bool CreateResources(const RenderContext& renderContext);
|
||||||
|
void DestroyResources();
|
||||||
|
bool HasCreatedResources() const;
|
||||||
|
void ResetState();
|
||||||
|
|
||||||
|
RHI::RHIDevice* m_device = nullptr;
|
||||||
|
RHI::RHIType m_backendType = RHI::RHIType::D3D12;
|
||||||
|
RHI::RHIPipelineLayout* m_pipelineLayout = nullptr;
|
||||||
|
RHI::RHIPipelineState* m_pipelineState = nullptr;
|
||||||
|
RHI::RHIDescriptorPool* m_constantPool = nullptr;
|
||||||
|
RHI::RHIDescriptorSet* m_constantSet = nullptr;
|
||||||
|
RHI::RHIDescriptorPool* m_texturePool = nullptr;
|
||||||
|
RHI::RHIDescriptorSet* m_textureSet = nullptr;
|
||||||
|
Containers::String m_shaderPath;
|
||||||
|
std::optional<Resources::ResourceHandle<Resources::Shader>> m_builtinSelectionOutlineShader;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Passes
|
||||||
|
} // namespace Rendering
|
||||||
|
} // namespace XCEngine
|
||||||
@@ -35,6 +35,8 @@ Containers::String GetBuiltinDepthOnlyShaderPath();
|
|||||||
Containers::String GetBuiltinShadowCasterShaderPath();
|
Containers::String GetBuiltinShadowCasterShaderPath();
|
||||||
Containers::String GetBuiltinObjectIdShaderPath();
|
Containers::String GetBuiltinObjectIdShaderPath();
|
||||||
Containers::String GetBuiltinObjectIdOutlineShaderPath();
|
Containers::String GetBuiltinObjectIdOutlineShaderPath();
|
||||||
|
Containers::String GetBuiltinSelectionMaskShaderPath();
|
||||||
|
Containers::String GetBuiltinSelectionOutlineShaderPath();
|
||||||
Containers::String GetBuiltinSkyboxShaderPath();
|
Containers::String GetBuiltinSkyboxShaderPath();
|
||||||
Containers::String GetBuiltinVolumetricShaderPath();
|
Containers::String GetBuiltinVolumetricShaderPath();
|
||||||
Containers::String GetBuiltinColorScalePostProcessShaderPath();
|
Containers::String GetBuiltinColorScalePostProcessShaderPath();
|
||||||
|
|||||||
@@ -360,7 +360,9 @@ BuiltinDepthStylePassBase::ResolvedShaderPass BuiltinDepthStylePassBase::Resolve
|
|||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (material != nullptr && IsTransparentRenderQueue(ResolveMaterialRenderQueue(material))) {
|
if (material != nullptr &&
|
||||||
|
IsTransparentRenderQueue(ResolveMaterialRenderQueue(material)) &&
|
||||||
|
m_passType != BuiltinMaterialPass::SelectionMask) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
65
engine/src/Rendering/Passes/BuiltinSelectionMaskPass.cpp
Normal file
65
engine/src/Rendering/Passes/BuiltinSelectionMaskPass.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "Rendering/Passes/BuiltinSelectionMaskPass.h"
|
||||||
|
|
||||||
|
#include "Components/GameObject.h"
|
||||||
|
#include "Resources/BuiltinResources.h"
|
||||||
|
|
||||||
|
#include <XCEngine/Rendering/FrameData/RenderSceneData.h>
|
||||||
|
#include <XCEngine/Rendering/FrameData/VisibleRenderItem.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace Rendering {
|
||||||
|
namespace Passes {
|
||||||
|
|
||||||
|
BuiltinSelectionMaskPass::BuiltinSelectionMaskPass()
|
||||||
|
: BuiltinDepthStylePassBase(
|
||||||
|
BuiltinMaterialPass::SelectionMask,
|
||||||
|
Resources::GetBuiltinSelectionMaskShaderPath()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
RHI::InputLayoutDesc BuiltinSelectionMaskPass::BuildInputLayout() {
|
||||||
|
return BuildCommonInputLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* BuiltinSelectionMaskPass::GetName() const {
|
||||||
|
return "BuiltinSelectionMaskPass";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuiltinSelectionMaskPass::Render(
|
||||||
|
const RenderContext& context,
|
||||||
|
const RenderSurface& surface,
|
||||||
|
const RenderSceneData& sceneData,
|
||||||
|
const std::vector<uint64_t>& selectedObjectIds) {
|
||||||
|
m_selectedObjectIds = selectedObjectIds;
|
||||||
|
if (m_selectedObjectIds.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSceneData selectionMaskSceneData = sceneData;
|
||||||
|
selectionMaskSceneData.cameraData.clearFlags = RenderClearFlags::Color;
|
||||||
|
selectionMaskSceneData.cameraData.clearColor = Math::Color::Black();
|
||||||
|
|
||||||
|
const RenderPassContext passContext = {
|
||||||
|
context,
|
||||||
|
surface,
|
||||||
|
selectionMaskSceneData,
|
||||||
|
nullptr,
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
return Execute(passContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuiltinSelectionMaskPass::ShouldRenderVisibleItem(const VisibleRenderItem& visibleItem) const {
|
||||||
|
if (visibleItem.gameObject == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t objectId = visibleItem.gameObject->GetID();
|
||||||
|
return std::find(m_selectedObjectIds.begin(), m_selectedObjectIds.end(), objectId) !=
|
||||||
|
m_selectedObjectIds.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Passes
|
||||||
|
} // namespace Rendering
|
||||||
|
} // namespace XCEngine
|
||||||
429
engine/src/Rendering/Passes/BuiltinSelectionOutlinePass.cpp
Normal file
429
engine/src/Rendering/Passes/BuiltinSelectionOutlinePass.cpp
Normal file
@@ -0,0 +1,429 @@
|
|||||||
|
#include "Rendering/Passes/BuiltinSelectionOutlinePass.h"
|
||||||
|
|
||||||
|
#include "Core/Asset/ResourceManager.h"
|
||||||
|
#include "Debug/Logger.h"
|
||||||
|
#include "Rendering/Detail/ShaderVariantUtils.h"
|
||||||
|
#include "Rendering/Materials/RenderMaterialStateUtils.h"
|
||||||
|
#include "RHI/RHICommandList.h"
|
||||||
|
#include "RHI/RHIDevice.h"
|
||||||
|
|
||||||
|
#include <XCEngine/Resources/BuiltinResources.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace Rendering {
|
||||||
|
namespace Passes {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const Resources::ShaderPass* FindSelectionOutlineCompatiblePass(
|
||||||
|
const Resources::Shader& shader,
|
||||||
|
Resources::ShaderBackend backend) {
|
||||||
|
const Resources::ShaderPass* outlinePass = shader.FindPass("SelectionOutline");
|
||||||
|
if (outlinePass != nullptr &&
|
||||||
|
::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, outlinePass->name, backend)) {
|
||||||
|
return outlinePass;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Resources::ShaderPass* editorOutlinePass = shader.FindPass("EditorSelectionOutline");
|
||||||
|
if (editorOutlinePass != nullptr &&
|
||||||
|
::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(
|
||||||
|
shader,
|
||||||
|
editorOutlinePass->name,
|
||||||
|
backend)) {
|
||||||
|
return editorOutlinePass;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shader.GetPassCount() > 0 &&
|
||||||
|
::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(
|
||||||
|
shader,
|
||||||
|
shader.GetPasses()[0].name,
|
||||||
|
backend)) {
|
||||||
|
return &shader.GetPasses()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RHI::GraphicsPipelineDesc CreatePipelineDesc(
|
||||||
|
RHI::RHIType backendType,
|
||||||
|
RHI::RHIPipelineLayout* pipelineLayout,
|
||||||
|
const Resources::Shader& shader,
|
||||||
|
const Containers::String& passName) {
|
||||||
|
RHI::GraphicsPipelineDesc pipelineDesc = {};
|
||||||
|
pipelineDesc.pipelineLayout = pipelineLayout;
|
||||||
|
pipelineDesc.topologyType = static_cast<uint32_t>(RHI::PrimitiveTopologyType::Triangle);
|
||||||
|
pipelineDesc.renderTargetCount = 1;
|
||||||
|
pipelineDesc.renderTargetFormats[0] = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
pipelineDesc.depthStencilFormat = static_cast<uint32_t>(RHI::Format::Unknown);
|
||||||
|
pipelineDesc.sampleCount = 1;
|
||||||
|
|
||||||
|
const Resources::ShaderPass* shaderPass = shader.FindPass(passName);
|
||||||
|
if (shaderPass != nullptr && shaderPass->hasFixedFunctionState) {
|
||||||
|
::XCEngine::Rendering::ApplyRenderState(shaderPass->fixedFunctionState, pipelineDesc);
|
||||||
|
} else {
|
||||||
|
Resources::MaterialRenderState fallbackState = {};
|
||||||
|
fallbackState.cullMode = Resources::MaterialCullMode::None;
|
||||||
|
fallbackState.depthWriteEnable = false;
|
||||||
|
fallbackState.depthTestEnable = false;
|
||||||
|
fallbackState.depthFunc = Resources::MaterialComparisonFunc::Always;
|
||||||
|
fallbackState.blendEnable = true;
|
||||||
|
fallbackState.srcBlend = Resources::MaterialBlendFactor::SrcAlpha;
|
||||||
|
fallbackState.dstBlend = Resources::MaterialBlendFactor::InvSrcAlpha;
|
||||||
|
fallbackState.srcBlendAlpha = Resources::MaterialBlendFactor::One;
|
||||||
|
fallbackState.dstBlendAlpha = Resources::MaterialBlendFactor::InvSrcAlpha;
|
||||||
|
fallbackState.blendOp = Resources::MaterialBlendOp::Add;
|
||||||
|
fallbackState.blendOpAlpha = Resources::MaterialBlendOp::Add;
|
||||||
|
fallbackState.colorWriteMask = static_cast<uint8_t>(RHI::ColorWriteMask::All);
|
||||||
|
::XCEngine::Rendering::ApplyRenderState(fallbackState, pipelineDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Resources::ShaderBackend backend = ::XCEngine::Rendering::Detail::ToShaderBackend(backendType);
|
||||||
|
if (const Resources::ShaderStageVariant* vertexVariant =
|
||||||
|
shader.FindVariant(passName, Resources::ShaderType::Vertex, backend)) {
|
||||||
|
if (shaderPass != nullptr) {
|
||||||
|
::XCEngine::Rendering::Detail::ApplyShaderStageVariant(
|
||||||
|
shader.GetPath(),
|
||||||
|
*shaderPass,
|
||||||
|
backend,
|
||||||
|
*vertexVariant,
|
||||||
|
pipelineDesc.vertexShader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (const Resources::ShaderStageVariant* fragmentVariant =
|
||||||
|
shader.FindVariant(passName, Resources::ShaderType::Fragment, backend)) {
|
||||||
|
if (shaderPass != nullptr) {
|
||||||
|
::XCEngine::Rendering::Detail::ApplyShaderStageVariant(
|
||||||
|
shader.GetPath(),
|
||||||
|
*shaderPass,
|
||||||
|
backend,
|
||||||
|
*fragmentVariant,
|
||||||
|
pipelineDesc.fragmentShader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pipelineDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
BuiltinSelectionOutlinePass::BuiltinSelectionOutlinePass(Containers::String shaderPath)
|
||||||
|
: m_shaderPath(shaderPath.Empty() ? Resources::GetBuiltinSelectionOutlineShaderPath() : std::move(shaderPath)) {
|
||||||
|
ResetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuiltinSelectionOutlinePass::SetShaderPath(const Containers::String& shaderPath) {
|
||||||
|
if (m_shaderPath == shaderPath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DestroyResources();
|
||||||
|
m_shaderPath = shaderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Containers::String& BuiltinSelectionOutlinePass::GetShaderPath() const {
|
||||||
|
return m_shaderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuiltinSelectionOutlinePass::Shutdown() {
|
||||||
|
DestroyResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuiltinSelectionOutlinePass::Render(
|
||||||
|
const RenderContext& renderContext,
|
||||||
|
const RenderSurface& surface,
|
||||||
|
RHI::RHIResourceView* selectionMaskTextureView,
|
||||||
|
RHI::RHIResourceView* depthTextureView,
|
||||||
|
const SelectionOutlineStyle& style) {
|
||||||
|
if (!renderContext.IsValid() ||
|
||||||
|
renderContext.backendType != RHI::RHIType::D3D12 ||
|
||||||
|
selectionMaskTextureView == nullptr ||
|
||||||
|
depthTextureView == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EnsureInitialized(renderContext)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<RHI::RHIResourceView*>& colorAttachments = surface.GetColorAttachments();
|
||||||
|
if (colorAttachments.empty() || colorAttachments[0] == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutlineConstants constants = {};
|
||||||
|
constants.viewportSizeAndTexelSize = Math::Vector4(
|
||||||
|
static_cast<float>(surface.GetWidth()),
|
||||||
|
static_cast<float>(surface.GetHeight()),
|
||||||
|
surface.GetWidth() > 0 ? 1.0f / static_cast<float>(surface.GetWidth()) : 0.0f,
|
||||||
|
surface.GetHeight() > 0 ? 1.0f / static_cast<float>(surface.GetHeight()) : 0.0f);
|
||||||
|
constants.outlineColor = Math::Vector4(
|
||||||
|
style.outlineColor.r,
|
||||||
|
style.outlineColor.g,
|
||||||
|
style.outlineColor.b,
|
||||||
|
style.outlineColor.a);
|
||||||
|
constants.outlineInfo = Math::Vector4(
|
||||||
|
style.debugSelectionMask ? 1.0f : 0.0f,
|
||||||
|
style.outlineWidthPixels,
|
||||||
|
0.0f,
|
||||||
|
0.0f);
|
||||||
|
constants.depthParams = Math::Vector4(1.0e-5f, 0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
m_constantSet->WriteConstant(0, &constants, sizeof(constants));
|
||||||
|
m_textureSet->Update(0, selectionMaskTextureView);
|
||||||
|
m_textureSet->Update(1, depthTextureView);
|
||||||
|
|
||||||
|
RHI::RHICommandList* commandList = renderContext.commandList;
|
||||||
|
RHI::RHIResourceView* renderTarget = colorAttachments[0];
|
||||||
|
commandList->TransitionBarrier(
|
||||||
|
renderTarget,
|
||||||
|
surface.GetColorStateAfter(),
|
||||||
|
RHI::ResourceStates::RenderTarget);
|
||||||
|
commandList->TransitionBarrier(
|
||||||
|
depthTextureView,
|
||||||
|
RHI::ResourceStates::DepthWrite,
|
||||||
|
RHI::ResourceStates::PixelShaderResource);
|
||||||
|
commandList->SetRenderTargets(1, &renderTarget, nullptr);
|
||||||
|
|
||||||
|
const Math::RectInt renderArea = surface.GetRenderArea();
|
||||||
|
const RHI::Viewport viewport = {
|
||||||
|
static_cast<float>(renderArea.x),
|
||||||
|
static_cast<float>(renderArea.y),
|
||||||
|
static_cast<float>(renderArea.width),
|
||||||
|
static_cast<float>(renderArea.height),
|
||||||
|
0.0f,
|
||||||
|
1.0f
|
||||||
|
};
|
||||||
|
const RHI::Rect scissorRect = {
|
||||||
|
renderArea.x,
|
||||||
|
renderArea.y,
|
||||||
|
renderArea.x + renderArea.width,
|
||||||
|
renderArea.y + renderArea.height
|
||||||
|
};
|
||||||
|
|
||||||
|
commandList->SetViewport(viewport);
|
||||||
|
commandList->SetScissorRect(scissorRect);
|
||||||
|
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
|
||||||
|
commandList->SetPipelineState(m_pipelineState);
|
||||||
|
|
||||||
|
RHI::RHIDescriptorSet* descriptorSets[] = { m_constantSet, m_textureSet };
|
||||||
|
commandList->SetGraphicsDescriptorSets(0, 2, descriptorSets, m_pipelineLayout);
|
||||||
|
commandList->Draw(3, 1, 0, 0);
|
||||||
|
|
||||||
|
commandList->TransitionBarrier(
|
||||||
|
renderTarget,
|
||||||
|
RHI::ResourceStates::RenderTarget,
|
||||||
|
surface.GetColorStateAfter());
|
||||||
|
commandList->TransitionBarrier(
|
||||||
|
depthTextureView,
|
||||||
|
RHI::ResourceStates::PixelShaderResource,
|
||||||
|
RHI::ResourceStates::DepthWrite);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuiltinSelectionOutlinePass::EnsureInitialized(const RenderContext& renderContext) {
|
||||||
|
if (m_pipelineLayout != nullptr &&
|
||||||
|
m_pipelineState != nullptr &&
|
||||||
|
m_constantPool != nullptr &&
|
||||||
|
m_constantSet != nullptr &&
|
||||||
|
m_texturePool != nullptr &&
|
||||||
|
m_textureSet != nullptr &&
|
||||||
|
m_device == renderContext.device &&
|
||||||
|
m_backendType == renderContext.backendType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasCreatedResources()) {
|
||||||
|
DestroyResources();
|
||||||
|
}
|
||||||
|
return CreateResources(renderContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuiltinSelectionOutlinePass::CreateResources(const RenderContext& renderContext) {
|
||||||
|
if (!renderContext.IsValid() || renderContext.backendType != RHI::RHIType::D3D12) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_shaderPath.Empty()) {
|
||||||
|
Debug::Logger::Get().Error(
|
||||||
|
Debug::LogCategory::Rendering,
|
||||||
|
"BuiltinSelectionOutlinePass requires an injected shader path before resource creation");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::ResourceHandle<Resources::Shader> shader = Resources::ResourceManager::Get().Load<Resources::Shader>(
|
||||||
|
m_shaderPath);
|
||||||
|
if (!shader.IsValid()) {
|
||||||
|
Debug::Logger::Get().Error(
|
||||||
|
Debug::LogCategory::Rendering,
|
||||||
|
"BuiltinSelectionOutlinePass failed to load configured selection-outline shader resource");
|
||||||
|
ResetState();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = renderContext.device;
|
||||||
|
m_backendType = renderContext.backendType;
|
||||||
|
m_builtinSelectionOutlineShader.emplace(std::move(shader));
|
||||||
|
|
||||||
|
const Resources::ShaderBackend backend = ::XCEngine::Rendering::Detail::ToShaderBackend(m_backendType);
|
||||||
|
const Resources::ShaderPass* outlinePass =
|
||||||
|
FindSelectionOutlineCompatiblePass(*m_builtinSelectionOutlineShader->Get(), backend);
|
||||||
|
if (outlinePass == nullptr) {
|
||||||
|
Debug::Logger::Get().Error(
|
||||||
|
Debug::LogCategory::Rendering,
|
||||||
|
"BuiltinSelectionOutlinePass could not resolve a valid SelectionOutline shader pass");
|
||||||
|
DestroyResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RHI::DescriptorSetLayoutBinding constantBinding = {};
|
||||||
|
constantBinding.binding = 0;
|
||||||
|
constantBinding.type = static_cast<uint32_t>(RHI::DescriptorType::CBV);
|
||||||
|
constantBinding.count = 1;
|
||||||
|
|
||||||
|
RHI::DescriptorSetLayoutBinding textureBindings[2] = {};
|
||||||
|
textureBindings[0].binding = 0;
|
||||||
|
textureBindings[0].type = static_cast<uint32_t>(RHI::DescriptorType::SRV);
|
||||||
|
textureBindings[0].count = 1;
|
||||||
|
textureBindings[1].binding = 1;
|
||||||
|
textureBindings[1].type = static_cast<uint32_t>(RHI::DescriptorType::SRV);
|
||||||
|
textureBindings[1].count = 1;
|
||||||
|
|
||||||
|
RHI::DescriptorSetLayoutDesc constantLayout = {};
|
||||||
|
constantLayout.bindings = &constantBinding;
|
||||||
|
constantLayout.bindingCount = 1;
|
||||||
|
|
||||||
|
RHI::DescriptorSetLayoutDesc textureLayout = {};
|
||||||
|
textureLayout.bindings = textureBindings;
|
||||||
|
textureLayout.bindingCount = 2;
|
||||||
|
|
||||||
|
RHI::DescriptorSetLayoutDesc setLayouts[2] = {};
|
||||||
|
setLayouts[0] = constantLayout;
|
||||||
|
setLayouts[1] = textureLayout;
|
||||||
|
|
||||||
|
RHI::RHIPipelineLayoutDesc pipelineLayoutDesc = {};
|
||||||
|
pipelineLayoutDesc.setLayouts = setLayouts;
|
||||||
|
pipelineLayoutDesc.setLayoutCount = 2;
|
||||||
|
m_pipelineLayout = m_device->CreatePipelineLayout(pipelineLayoutDesc);
|
||||||
|
if (m_pipelineLayout == nullptr) {
|
||||||
|
DestroyResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RHI::DescriptorPoolDesc constantPoolDesc = {};
|
||||||
|
constantPoolDesc.type = RHI::DescriptorHeapType::CBV_SRV_UAV;
|
||||||
|
constantPoolDesc.descriptorCount = 1;
|
||||||
|
constantPoolDesc.shaderVisible = false;
|
||||||
|
m_constantPool = m_device->CreateDescriptorPool(constantPoolDesc);
|
||||||
|
if (m_constantPool == nullptr) {
|
||||||
|
DestroyResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_constantSet = m_constantPool->AllocateSet(constantLayout);
|
||||||
|
if (m_constantSet == nullptr) {
|
||||||
|
DestroyResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RHI::DescriptorPoolDesc texturePoolDesc = {};
|
||||||
|
texturePoolDesc.type = RHI::DescriptorHeapType::CBV_SRV_UAV;
|
||||||
|
texturePoolDesc.descriptorCount = 2;
|
||||||
|
texturePoolDesc.shaderVisible = true;
|
||||||
|
m_texturePool = m_device->CreateDescriptorPool(texturePoolDesc);
|
||||||
|
if (m_texturePool == nullptr) {
|
||||||
|
DestroyResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_textureSet = m_texturePool->AllocateSet(textureLayout);
|
||||||
|
if (m_textureSet == nullptr) {
|
||||||
|
DestroyResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pipelineState = m_device->CreatePipelineState(
|
||||||
|
CreatePipelineDesc(
|
||||||
|
m_backendType,
|
||||||
|
m_pipelineLayout,
|
||||||
|
*m_builtinSelectionOutlineShader->Get(),
|
||||||
|
outlinePass->name));
|
||||||
|
if (m_pipelineState == nullptr || !m_pipelineState->IsValid()) {
|
||||||
|
DestroyResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuiltinSelectionOutlinePass::HasCreatedResources() const {
|
||||||
|
return m_device != nullptr ||
|
||||||
|
m_pipelineLayout != nullptr ||
|
||||||
|
m_pipelineState != nullptr ||
|
||||||
|
m_constantPool != nullptr ||
|
||||||
|
m_constantSet != nullptr ||
|
||||||
|
m_texturePool != nullptr ||
|
||||||
|
m_textureSet != nullptr ||
|
||||||
|
m_builtinSelectionOutlineShader.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuiltinSelectionOutlinePass::DestroyResources() {
|
||||||
|
if (m_pipelineState != nullptr) {
|
||||||
|
m_pipelineState->Shutdown();
|
||||||
|
delete m_pipelineState;
|
||||||
|
m_pipelineState = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_textureSet != nullptr) {
|
||||||
|
m_textureSet->Shutdown();
|
||||||
|
delete m_textureSet;
|
||||||
|
m_textureSet = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_texturePool != nullptr) {
|
||||||
|
m_texturePool->Shutdown();
|
||||||
|
delete m_texturePool;
|
||||||
|
m_texturePool = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_constantSet != nullptr) {
|
||||||
|
m_constantSet->Shutdown();
|
||||||
|
delete m_constantSet;
|
||||||
|
m_constantSet = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_constantPool != nullptr) {
|
||||||
|
m_constantPool->Shutdown();
|
||||||
|
delete m_constantPool;
|
||||||
|
m_constantPool = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pipelineLayout != nullptr) {
|
||||||
|
m_pipelineLayout->Shutdown();
|
||||||
|
delete m_pipelineLayout;
|
||||||
|
m_pipelineLayout = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_builtinSelectionOutlineShader.has_value()) {
|
||||||
|
m_builtinSelectionOutlineShader.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuiltinSelectionOutlinePass::ResetState() {
|
||||||
|
m_device = nullptr;
|
||||||
|
m_backendType = RHI::RHIType::D3D12;
|
||||||
|
m_pipelineLayout = nullptr;
|
||||||
|
m_pipelineState = nullptr;
|
||||||
|
m_constantPool = nullptr;
|
||||||
|
m_constantSet = nullptr;
|
||||||
|
m_texturePool = nullptr;
|
||||||
|
m_textureSet = nullptr;
|
||||||
|
m_builtinSelectionOutlineShader.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Passes
|
||||||
|
} // namespace Rendering
|
||||||
|
} // namespace XCEngine
|
||||||
@@ -33,6 +33,8 @@ constexpr const char* kBuiltinDepthOnlyShaderPath = "builtin://shaders/depth-onl
|
|||||||
constexpr const char* kBuiltinShadowCasterShaderPath = "builtin://shaders/shadow-caster";
|
constexpr const char* kBuiltinShadowCasterShaderPath = "builtin://shaders/shadow-caster";
|
||||||
constexpr const char* kBuiltinObjectIdShaderPath = "builtin://shaders/object-id";
|
constexpr const char* kBuiltinObjectIdShaderPath = "builtin://shaders/object-id";
|
||||||
constexpr const char* kBuiltinObjectIdOutlineShaderPath = "builtin://shaders/object-id-outline";
|
constexpr const char* kBuiltinObjectIdOutlineShaderPath = "builtin://shaders/object-id-outline";
|
||||||
|
constexpr const char* kBuiltinSelectionMaskShaderPath = "builtin://shaders/selection-mask";
|
||||||
|
constexpr const char* kBuiltinSelectionOutlineShaderPath = "builtin://shaders/selection-outline";
|
||||||
constexpr const char* kBuiltinSkyboxShaderPath = "builtin://shaders/skybox";
|
constexpr const char* kBuiltinSkyboxShaderPath = "builtin://shaders/skybox";
|
||||||
constexpr const char* kBuiltinVolumetricShaderPath = "builtin://shaders/volumetric";
|
constexpr const char* kBuiltinVolumetricShaderPath = "builtin://shaders/volumetric";
|
||||||
constexpr const char* kBuiltinColorScalePostProcessShaderPath =
|
constexpr const char* kBuiltinColorScalePostProcessShaderPath =
|
||||||
@@ -60,6 +62,10 @@ constexpr const char* kBuiltinObjectIdShaderAssetRelativePath =
|
|||||||
"engine/assets/builtin/shaders/object-id.shader";
|
"engine/assets/builtin/shaders/object-id.shader";
|
||||||
constexpr const char* kBuiltinObjectIdOutlineShaderAssetRelativePath =
|
constexpr const char* kBuiltinObjectIdOutlineShaderAssetRelativePath =
|
||||||
"engine/assets/builtin/shaders/object-id-outline.shader";
|
"engine/assets/builtin/shaders/object-id-outline.shader";
|
||||||
|
constexpr const char* kBuiltinSelectionMaskShaderAssetRelativePath =
|
||||||
|
"engine/assets/builtin/shaders/selection-mask.shader";
|
||||||
|
constexpr const char* kBuiltinSelectionOutlineShaderAssetRelativePath =
|
||||||
|
"engine/assets/builtin/shaders/selection-outline.shader";
|
||||||
constexpr const char* kBuiltinSkyboxShaderAssetRelativePath =
|
constexpr const char* kBuiltinSkyboxShaderAssetRelativePath =
|
||||||
"engine/assets/builtin/shaders/skybox.shader";
|
"engine/assets/builtin/shaders/skybox.shader";
|
||||||
constexpr const char* kBuiltinVolumetricShaderAssetRelativePath =
|
constexpr const char* kBuiltinVolumetricShaderAssetRelativePath =
|
||||||
@@ -149,6 +155,12 @@ const char* GetBuiltinShaderAssetRelativePath(const Containers::String& builtinS
|
|||||||
if (builtinShaderPath == Containers::String(kBuiltinObjectIdOutlineShaderPath)) {
|
if (builtinShaderPath == Containers::String(kBuiltinObjectIdOutlineShaderPath)) {
|
||||||
return kBuiltinObjectIdOutlineShaderAssetRelativePath;
|
return kBuiltinObjectIdOutlineShaderAssetRelativePath;
|
||||||
}
|
}
|
||||||
|
if (builtinShaderPath == Containers::String(kBuiltinSelectionMaskShaderPath)) {
|
||||||
|
return kBuiltinSelectionMaskShaderAssetRelativePath;
|
||||||
|
}
|
||||||
|
if (builtinShaderPath == Containers::String(kBuiltinSelectionOutlineShaderPath)) {
|
||||||
|
return kBuiltinSelectionOutlineShaderAssetRelativePath;
|
||||||
|
}
|
||||||
if (builtinShaderPath == Containers::String(kBuiltinSkyboxShaderPath)) {
|
if (builtinShaderPath == Containers::String(kBuiltinSkyboxShaderPath)) {
|
||||||
return kBuiltinSkyboxShaderAssetRelativePath;
|
return kBuiltinSkyboxShaderAssetRelativePath;
|
||||||
}
|
}
|
||||||
@@ -710,6 +722,14 @@ Shader* BuildBuiltinObjectIdOutlineShader(const Containers::String& path) {
|
|||||||
return TryLoadBuiltinShaderFromAsset(path);
|
return TryLoadBuiltinShaderFromAsset(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shader* BuildBuiltinSelectionMaskShader(const Containers::String& path) {
|
||||||
|
return TryLoadBuiltinShaderFromAsset(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader* BuildBuiltinSelectionOutlineShader(const Containers::String& path) {
|
||||||
|
return TryLoadBuiltinShaderFromAsset(path);
|
||||||
|
}
|
||||||
|
|
||||||
Shader* BuildBuiltinSkyboxShader(const Containers::String& path) {
|
Shader* BuildBuiltinSkyboxShader(const Containers::String& path) {
|
||||||
return TryLoadBuiltinShaderFromAsset(path);
|
return TryLoadBuiltinShaderFromAsset(path);
|
||||||
}
|
}
|
||||||
@@ -735,9 +755,6 @@ Material* BuildDefaultPrimitiveMaterial(const Containers::String& path) {
|
|||||||
params.memorySize = 0;
|
params.memorySize = 0;
|
||||||
material->Initialize(params);
|
material->Initialize(params);
|
||||||
|
|
||||||
MaterialRenderState renderState = {};
|
|
||||||
renderState.cullMode = MaterialCullMode::Back;
|
|
||||||
material->SetRenderState(renderState);
|
|
||||||
material->SetRenderQueue(MaterialRenderQueue::Geometry);
|
material->SetRenderQueue(MaterialRenderQueue::Geometry);
|
||||||
material->SetShader(ResourceManager::Get().Load<Shader>(GetBuiltinForwardLitShaderPath()));
|
material->SetShader(ResourceManager::Get().Load<Shader>(GetBuiltinForwardLitShaderPath()));
|
||||||
material->SetTexture(
|
material->SetTexture(
|
||||||
@@ -823,6 +840,14 @@ bool TryGetBuiltinShaderPathByShaderName(
|
|||||||
outPath = GetBuiltinObjectIdOutlineShaderPath();
|
outPath = GetBuiltinObjectIdOutlineShaderPath();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (shaderName == "Builtin Selection Mask") {
|
||||||
|
outPath = GetBuiltinSelectionMaskShaderPath();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (shaderName == "Builtin Selection Outline") {
|
||||||
|
outPath = GetBuiltinSelectionOutlineShaderPath();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (shaderName == "Builtin Skybox") {
|
if (shaderName == "Builtin Skybox") {
|
||||||
outPath = GetBuiltinSkyboxShaderPath();
|
outPath = GetBuiltinSkyboxShaderPath();
|
||||||
return true;
|
return true;
|
||||||
@@ -902,6 +927,14 @@ Containers::String GetBuiltinObjectIdOutlineShaderPath() {
|
|||||||
return Containers::String(kBuiltinObjectIdOutlineShaderPath);
|
return Containers::String(kBuiltinObjectIdOutlineShaderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Containers::String GetBuiltinSelectionMaskShaderPath() {
|
||||||
|
return Containers::String(kBuiltinSelectionMaskShaderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::String GetBuiltinSelectionOutlineShaderPath() {
|
||||||
|
return Containers::String(kBuiltinSelectionOutlineShaderPath);
|
||||||
|
}
|
||||||
|
|
||||||
Containers::String GetBuiltinSkyboxShaderPath() {
|
Containers::String GetBuiltinSkyboxShaderPath() {
|
||||||
return Containers::String(kBuiltinSkyboxShaderPath);
|
return Containers::String(kBuiltinSkyboxShaderPath);
|
||||||
}
|
}
|
||||||
@@ -1018,6 +1051,10 @@ LoadResult CreateBuiltinShaderResource(const Containers::String& path) {
|
|||||||
shader = BuildBuiltinObjectIdShader(path);
|
shader = BuildBuiltinObjectIdShader(path);
|
||||||
} else if (path == GetBuiltinObjectIdOutlineShaderPath()) {
|
} else if (path == GetBuiltinObjectIdOutlineShaderPath()) {
|
||||||
shader = BuildBuiltinObjectIdOutlineShader(path);
|
shader = BuildBuiltinObjectIdOutlineShader(path);
|
||||||
|
} else if (path == GetBuiltinSelectionMaskShaderPath()) {
|
||||||
|
shader = BuildBuiltinSelectionMaskShader(path);
|
||||||
|
} else if (path == GetBuiltinSelectionOutlineShaderPath()) {
|
||||||
|
shader = BuildBuiltinSelectionOutlineShader(path);
|
||||||
} else if (path == GetBuiltinSkyboxShaderPath()) {
|
} else if (path == GetBuiltinSkyboxShaderPath()) {
|
||||||
shader = BuildBuiltinSkyboxShader(path);
|
shader = BuildBuiltinSkyboxShader(path);
|
||||||
} else if (path == GetBuiltinVolumetricShaderPath()) {
|
} else if (path == GetBuiltinVolumetricShaderPath()) {
|
||||||
|
|||||||
@@ -180,6 +180,19 @@ TEST(MaterialLoader, ResourceManagerRegistersMaterialAndShaderLoaders) {
|
|||||||
manager.Shutdown();
|
manager.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(MaterialLoader, BuiltinDefaultPrimitiveMaterialLeavesRenderStateOverrideDisabled) {
|
||||||
|
ResourceManager& manager = ResourceManager::Get();
|
||||||
|
manager.Initialize();
|
||||||
|
|
||||||
|
const auto materialHandle = manager.Load<Material>(GetBuiltinDefaultPrimitiveMaterialPath());
|
||||||
|
ASSERT_TRUE(materialHandle.IsValid());
|
||||||
|
ASSERT_NE(materialHandle->GetShader(), nullptr);
|
||||||
|
EXPECT_EQ(materialHandle->GetShader()->GetPath(), GetBuiltinForwardLitShaderPath());
|
||||||
|
EXPECT_FALSE(materialHandle->HasRenderStateOverride());
|
||||||
|
|
||||||
|
manager.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
TEST(MaterialLoader, LoadValidMaterialParsesRenderMetadata) {
|
TEST(MaterialLoader, LoadValidMaterialParsesRenderMetadata) {
|
||||||
ResourceManager& manager = ResourceManager::Get();
|
ResourceManager& manager = ResourceManager::Get();
|
||||||
manager.Initialize();
|
manager.Initialize();
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ TEST(ShaderLoader, CanLoad) {
|
|||||||
EXPECT_TRUE(loader.CanLoad(GetBuiltinUnlitShaderPath()));
|
EXPECT_TRUE(loader.CanLoad(GetBuiltinUnlitShaderPath()));
|
||||||
EXPECT_TRUE(loader.CanLoad(GetBuiltinObjectIdShaderPath()));
|
EXPECT_TRUE(loader.CanLoad(GetBuiltinObjectIdShaderPath()));
|
||||||
EXPECT_TRUE(loader.CanLoad(GetBuiltinObjectIdOutlineShaderPath()));
|
EXPECT_TRUE(loader.CanLoad(GetBuiltinObjectIdOutlineShaderPath()));
|
||||||
|
EXPECT_TRUE(loader.CanLoad(GetBuiltinSelectionMaskShaderPath()));
|
||||||
|
EXPECT_TRUE(loader.CanLoad(GetBuiltinSelectionOutlineShaderPath()));
|
||||||
EXPECT_FALSE(loader.CanLoad("test.vert"));
|
EXPECT_FALSE(loader.CanLoad("test.vert"));
|
||||||
EXPECT_FALSE(loader.CanLoad("test.frag"));
|
EXPECT_FALSE(loader.CanLoad("test.frag"));
|
||||||
EXPECT_FALSE(loader.CanLoad("test.glsl"));
|
EXPECT_FALSE(loader.CanLoad("test.glsl"));
|
||||||
@@ -2516,6 +2518,27 @@ TEST(ShaderLoader, LoadBuiltinObjectIdShaderBuildsAuthoringVariants) {
|
|||||||
delete shader;
|
delete shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ShaderLoader, LoadBuiltinSelectionMaskShaderBuildsAuthoringVariants) {
|
||||||
|
ShaderLoader loader;
|
||||||
|
LoadResult result = loader.Load(GetBuiltinSelectionMaskShaderPath());
|
||||||
|
ASSERT_TRUE(result);
|
||||||
|
ASSERT_NE(result.resource, nullptr);
|
||||||
|
|
||||||
|
Shader* shader = static_cast<Shader*>(result.resource);
|
||||||
|
ASSERT_NE(shader, nullptr);
|
||||||
|
ASSERT_TRUE(shader->IsValid());
|
||||||
|
|
||||||
|
const ShaderPass* alphaTestPass = shader->FindPass("SelectionMask");
|
||||||
|
ASSERT_NE(alphaTestPass, nullptr);
|
||||||
|
EXPECT_EQ(alphaTestPass->resources.Size(), 4u);
|
||||||
|
ASSERT_EQ(alphaTestPass->keywordDeclarations.Size(), 1u);
|
||||||
|
EXPECT_EQ(alphaTestPass->keywordDeclarations[0].type, ShaderKeywordDeclarationType::ShaderFeatureLocal);
|
||||||
|
ASSERT_EQ(alphaTestPass->keywordDeclarations[0].options.Size(), 2u);
|
||||||
|
EXPECT_EQ(alphaTestPass->keywordDeclarations[0].options[1], "XC_ALPHA_TEST");
|
||||||
|
|
||||||
|
delete shader;
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ShaderLoader, LoadBuiltinDepthOnlyShaderBuildsAuthoringVariants) {
|
TEST(ShaderLoader, LoadBuiltinDepthOnlyShaderBuildsAuthoringVariants) {
|
||||||
ShaderLoader loader;
|
ShaderLoader loader;
|
||||||
LoadResult result = loader.Load(GetBuiltinDepthOnlyShaderPath());
|
LoadResult result = loader.Load(GetBuiltinDepthOnlyShaderPath());
|
||||||
|
|||||||
@@ -78,10 +78,16 @@ SceneViewportOverlayFrameData CreateOverlayFrameDataWithLine(const SceneViewport
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(SceneViewportRenderPassBundleTest, BuildRenderPlanCreatesGridOutlineAndOverlayPasses) {
|
TEST(SceneViewportRenderPassBundleTest, BuildRenderPlanCreatesGridOutlineAndOverlayPasses) {
|
||||||
DummyResourceView objectIdShaderView(ResourceViewType::ShaderResource);
|
DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
|
DummyResourceView depthShaderView(ResourceViewType::ShaderResource, Format::D24_UNorm_S8_UInt);
|
||||||
|
DummyResourceView selectionMaskView(ResourceViewType::RenderTarget);
|
||||||
|
DummyResourceView selectionMaskShaderView(ResourceViewType::ShaderResource);
|
||||||
|
|
||||||
ViewportRenderTargets targets = {};
|
ViewportRenderTargets targets = {};
|
||||||
targets.objectIdShaderView = &objectIdShaderView;
|
targets.depthView = &depthView;
|
||||||
|
targets.depthShaderView = &depthShaderView;
|
||||||
|
targets.selectionMaskView = &selectionMaskView;
|
||||||
|
targets.selectionMaskShaderView = &selectionMaskShaderView;
|
||||||
|
|
||||||
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
||||||
const SceneViewportOverlayFrameData editorOverlayFrameData =
|
const SceneViewportOverlayFrameData editorOverlayFrameData =
|
||||||
@@ -100,12 +106,13 @@ TEST(SceneViewportRenderPassBundleTest, BuildRenderPlanCreatesGridOutlineAndOver
|
|||||||
EXPECT_EQ(result.warningStatusText, nullptr);
|
EXPECT_EQ(result.warningStatusText, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SceneViewportRenderPassBundleTest, BuildRenderPlanReportsMissingObjectIdShaderView) {
|
TEST(SceneViewportRenderPassBundleTest, BuildRenderPlanReportsMissingSelectionOutlineResources) {
|
||||||
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
||||||
|
ViewportRenderTargets targets = {};
|
||||||
|
|
||||||
SceneViewportRenderPassBundle bundle;
|
SceneViewportRenderPassBundle bundle;
|
||||||
const auto result = bundle.BuildRenderPlan(
|
const auto result = bundle.BuildRenderPlan(
|
||||||
{},
|
targets,
|
||||||
overlay,
|
overlay,
|
||||||
{ 42u },
|
{ 42u },
|
||||||
{},
|
{},
|
||||||
@@ -113,7 +120,7 @@ TEST(SceneViewportRenderPassBundleTest, BuildRenderPlanReportsMissingObjectIdSha
|
|||||||
|
|
||||||
EXPECT_EQ(result.plan.postScenePasses.GetPassCount(), 1u);
|
EXPECT_EQ(result.plan.postScenePasses.GetPassCount(), 1u);
|
||||||
EXPECT_EQ(result.plan.overlayPasses.GetPassCount(), 0u);
|
EXPECT_EQ(result.plan.overlayPasses.GetPassCount(), 0u);
|
||||||
EXPECT_STREQ(result.warningStatusText, "Scene object id shader view is unavailable");
|
EXPECT_STREQ(result.warningStatusText, "Scene selection outline resources are unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -18,11 +18,15 @@ using XCEngine::Editor::GetSceneViewportInfiniteGridShaderPath;
|
|||||||
using XCEngine::Editor::GetSceneViewportPointLightGizmoIconPath;
|
using XCEngine::Editor::GetSceneViewportPointLightGizmoIconPath;
|
||||||
using XCEngine::Editor::GetSceneViewportSpotLightGizmoIconPath;
|
using XCEngine::Editor::GetSceneViewportSpotLightGizmoIconPath;
|
||||||
using XCEngine::Resources::GetBuiltinObjectIdOutlineShaderPath;
|
using XCEngine::Resources::GetBuiltinObjectIdOutlineShaderPath;
|
||||||
|
using XCEngine::Resources::GetBuiltinSelectionMaskShaderPath;
|
||||||
|
using XCEngine::Resources::GetBuiltinSelectionOutlineShaderPath;
|
||||||
using XCEngine::Resources::LoadResult;
|
using XCEngine::Resources::LoadResult;
|
||||||
using XCEngine::Resources::ResourceHandle;
|
using XCEngine::Resources::ResourceHandle;
|
||||||
using XCEngine::Resources::ResourceManager;
|
using XCEngine::Resources::ResourceManager;
|
||||||
using XCEngine::Resources::Shader;
|
using XCEngine::Resources::Shader;
|
||||||
using XCEngine::Resources::ShaderBackend;
|
using XCEngine::Resources::ShaderBackend;
|
||||||
|
using XCEngine::Resources::ShaderKeywordDeclarationType;
|
||||||
|
using XCEngine::Resources::ShaderKeywordSet;
|
||||||
using XCEngine::Resources::ShaderLoader;
|
using XCEngine::Resources::ShaderLoader;
|
||||||
using XCEngine::Resources::ShaderPass;
|
using XCEngine::Resources::ShaderPass;
|
||||||
using XCEngine::Resources::ShaderStageVariant;
|
using XCEngine::Resources::ShaderStageVariant;
|
||||||
@@ -110,4 +114,61 @@ TEST(SceneViewportShaderPathsTest, ResourceManagerLoadsSceneViewportOutlineShade
|
|||||||
manager.Shutdown();
|
manager.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SceneViewportShaderPathsTest, ResourceManagerLoadsSelectionOutlineShadersByResolvedPath) {
|
||||||
|
ResourceManager& manager = ResourceManager::Get();
|
||||||
|
manager.Shutdown();
|
||||||
|
|
||||||
|
const ResourceHandle<Shader> maskShaderHandle = manager.Load<Shader>(GetBuiltinSelectionMaskShaderPath());
|
||||||
|
ASSERT_TRUE(maskShaderHandle.IsValid());
|
||||||
|
|
||||||
|
const ShaderPass* maskPass = maskShaderHandle->FindPass("SelectionMask");
|
||||||
|
ASSERT_NE(maskPass, nullptr);
|
||||||
|
ASSERT_EQ(maskPass->variants.Size(), 4u);
|
||||||
|
ASSERT_EQ(maskPass->keywordDeclarations.Size(), 1u);
|
||||||
|
EXPECT_EQ(maskPass->keywordDeclarations[0].type, ShaderKeywordDeclarationType::ShaderFeatureLocal);
|
||||||
|
ASSERT_EQ(maskPass->keywordDeclarations[0].options.Size(), 2u);
|
||||||
|
EXPECT_EQ(maskPass->keywordDeclarations[0].options[0], "_");
|
||||||
|
EXPECT_EQ(maskPass->keywordDeclarations[0].options[1], "XC_ALPHA_TEST");
|
||||||
|
EXPECT_TRUE(maskShaderHandle->PassDeclaresKeyword("SelectionMask", "XC_ALPHA_TEST"));
|
||||||
|
|
||||||
|
const ShaderStageVariant* maskFragment = maskShaderHandle->FindVariant(
|
||||||
|
"SelectionMask",
|
||||||
|
ShaderType::Fragment,
|
||||||
|
ShaderBackend::D3D12);
|
||||||
|
ASSERT_NE(maskFragment, nullptr);
|
||||||
|
EXPECT_NE(
|
||||||
|
std::string(maskFragment->sourceCode.CStr()).find("XC_BUILTIN_SELECTION_MASK_D3D12_PS"),
|
||||||
|
std::string::npos);
|
||||||
|
|
||||||
|
ShaderKeywordSet alphaKeywords = {};
|
||||||
|
alphaKeywords.enabledKeywords.PushBack("XC_ALPHA_TEST");
|
||||||
|
const ShaderStageVariant* alphaMaskFragment = maskShaderHandle->FindVariant(
|
||||||
|
"SelectionMask",
|
||||||
|
ShaderType::Fragment,
|
||||||
|
ShaderBackend::D3D12,
|
||||||
|
alphaKeywords);
|
||||||
|
ASSERT_NE(alphaMaskFragment, nullptr);
|
||||||
|
EXPECT_NE(
|
||||||
|
std::string(alphaMaskFragment->sourceCode.CStr()).find("#define XC_ALPHA_TEST 1"),
|
||||||
|
std::string::npos);
|
||||||
|
|
||||||
|
const ResourceHandle<Shader> outlineShaderHandle = manager.Load<Shader>(GetBuiltinSelectionOutlineShaderPath());
|
||||||
|
ASSERT_TRUE(outlineShaderHandle.IsValid());
|
||||||
|
|
||||||
|
const ShaderPass* outlinePass = outlineShaderHandle->FindPass("SelectionOutline");
|
||||||
|
ASSERT_NE(outlinePass, nullptr);
|
||||||
|
ASSERT_EQ(outlinePass->variants.Size(), 2u);
|
||||||
|
|
||||||
|
const ShaderStageVariant* outlineFragment = outlineShaderHandle->FindVariant(
|
||||||
|
"SelectionOutline",
|
||||||
|
ShaderType::Fragment,
|
||||||
|
ShaderBackend::D3D12);
|
||||||
|
ASSERT_NE(outlineFragment, nullptr);
|
||||||
|
EXPECT_NE(
|
||||||
|
std::string(outlineFragment->sourceCode.CStr()).find("XC_BUILTIN_SELECTION_OUTLINE_D3D12_PS"),
|
||||||
|
std::string::npos);
|
||||||
|
|
||||||
|
manager.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -73,9 +73,15 @@ TEST(ViewportHostSurfaceUtilsTest, ViewportReuseRequiresObjectIdOnlyForSceneView
|
|||||||
EXPECT_TRUE(ViewportRequiresObjectIdResources(EditorViewportKind::Scene));
|
EXPECT_TRUE(ViewportRequiresObjectIdResources(EditorViewportKind::Scene));
|
||||||
EXPECT_FALSE(CanReuseViewportResources(sceneQuery));
|
EXPECT_FALSE(CanReuseViewportResources(sceneQuery));
|
||||||
|
|
||||||
|
sceneQuery.resources.hasDepthShaderView = true;
|
||||||
sceneQuery.resources.hasObjectIdTexture = true;
|
sceneQuery.resources.hasObjectIdTexture = true;
|
||||||
|
sceneQuery.resources.hasObjectIdDepthTexture = true;
|
||||||
|
sceneQuery.resources.hasObjectIdDepthView = true;
|
||||||
sceneQuery.resources.hasObjectIdView = true;
|
sceneQuery.resources.hasObjectIdView = true;
|
||||||
sceneQuery.resources.hasObjectIdShaderView = true;
|
sceneQuery.resources.hasObjectIdShaderView = true;
|
||||||
|
sceneQuery.resources.hasSelectionMaskTexture = true;
|
||||||
|
sceneQuery.resources.hasSelectionMaskView = true;
|
||||||
|
sceneQuery.resources.hasSelectionMaskShaderView = true;
|
||||||
EXPECT_TRUE(CanReuseViewportResources(sceneQuery));
|
EXPECT_TRUE(CanReuseViewportResources(sceneQuery));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,9 +96,15 @@ TEST(ViewportHostSurfaceUtilsTest, ViewportReuseRejectsMismatchedOrMissingResour
|
|||||||
query.resources.hasColorView = true;
|
query.resources.hasColorView = true;
|
||||||
query.resources.hasDepthTexture = true;
|
query.resources.hasDepthTexture = true;
|
||||||
query.resources.hasDepthView = true;
|
query.resources.hasDepthView = true;
|
||||||
|
query.resources.hasDepthShaderView = true;
|
||||||
query.resources.hasObjectIdTexture = true;
|
query.resources.hasObjectIdTexture = true;
|
||||||
|
query.resources.hasObjectIdDepthTexture = true;
|
||||||
|
query.resources.hasObjectIdDepthView = true;
|
||||||
query.resources.hasObjectIdView = true;
|
query.resources.hasObjectIdView = true;
|
||||||
query.resources.hasObjectIdShaderView = true;
|
query.resources.hasObjectIdShaderView = true;
|
||||||
|
query.resources.hasSelectionMaskTexture = true;
|
||||||
|
query.resources.hasSelectionMaskView = true;
|
||||||
|
query.resources.hasSelectionMaskShaderView = true;
|
||||||
query.resources.hasTextureDescriptor = true;
|
query.resources.hasTextureDescriptor = true;
|
||||||
|
|
||||||
EXPECT_TRUE(CanReuseViewportResources(query));
|
EXPECT_TRUE(CanReuseViewportResources(query));
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportSelectionOutlineStyleApplies
|
|||||||
|
|
||||||
TEST(ViewportRenderFlowUtilsTest, ApplySceneRenderRequestSetupAttachesOptionalPassesAndObjectIdSurface) {
|
TEST(ViewportRenderFlowUtilsTest, ApplySceneRenderRequestSetupAttachesOptionalPassesAndObjectIdSurface) {
|
||||||
DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
|
DummyResourceView objectIdDepthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
DummyResourceView objectIdView(ResourceViewType::RenderTarget);
|
DummyResourceView objectIdView(ResourceViewType::RenderTarget);
|
||||||
DummyResourceView objectIdShaderView(ResourceViewType::ShaderResource);
|
DummyResourceView objectIdShaderView(ResourceViewType::ShaderResource);
|
||||||
|
|
||||||
@@ -197,6 +198,7 @@ TEST(ViewportRenderFlowUtilsTest, ApplySceneRenderRequestSetupAttachesOptionalPa
|
|||||||
targets.width = 800;
|
targets.width = 800;
|
||||||
targets.height = 600;
|
targets.height = 600;
|
||||||
targets.depthView = &depthView;
|
targets.depthView = &depthView;
|
||||||
|
targets.objectIdDepthView = &objectIdDepthView;
|
||||||
targets.objectIdView = &objectIdView;
|
targets.objectIdView = &objectIdView;
|
||||||
targets.objectIdShaderView = &objectIdShaderView;
|
targets.objectIdShaderView = &objectIdShaderView;
|
||||||
targets.objectIdState = ResourceStates::Common;
|
targets.objectIdState = ResourceStates::Common;
|
||||||
@@ -217,7 +219,7 @@ TEST(ViewportRenderFlowUtilsTest, ApplySceneRenderRequestSetupAttachesOptionalPa
|
|||||||
EXPECT_TRUE(request.objectId.IsRequested());
|
EXPECT_TRUE(request.objectId.IsRequested());
|
||||||
ASSERT_EQ(request.objectId.surface.GetColorAttachments().size(), 1u);
|
ASSERT_EQ(request.objectId.surface.GetColorAttachments().size(), 1u);
|
||||||
EXPECT_EQ(request.objectId.surface.GetColorAttachments()[0], &objectIdView);
|
EXPECT_EQ(request.objectId.surface.GetColorAttachments()[0], &objectIdView);
|
||||||
EXPECT_EQ(request.objectId.surface.GetDepthAttachment(), &depthView);
|
EXPECT_EQ(request.objectId.surface.GetDepthAttachment(), &objectIdDepthView);
|
||||||
|
|
||||||
const auto requestArea = request.surface.GetRenderArea();
|
const auto requestArea = request.surface.GetRenderArea();
|
||||||
const auto objectIdArea = request.objectId.surface.GetRenderArea();
|
const auto objectIdArea = request.objectId.surface.GetRenderArea();
|
||||||
@@ -247,9 +249,18 @@ TEST(ViewportRenderFlowUtilsTest, ApplySceneRenderRequestSetupSkipsUnavailableOp
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanCollectsPostSceneAndOverlayPasses) {
|
TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanCollectsPostSceneAndOverlayPasses) {
|
||||||
|
DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
|
DummyResourceView depthShaderView(ResourceViewType::ShaderResource, Format::D24_UNorm_S8_UInt);
|
||||||
|
DummyResourceView selectionMaskView(ResourceViewType::RenderTarget);
|
||||||
|
DummyResourceView selectionMaskShaderView(ResourceViewType::ShaderResource);
|
||||||
|
|
||||||
DummyResourceView objectIdShaderView(ResourceViewType::ShaderResource);
|
DummyResourceView objectIdShaderView(ResourceViewType::ShaderResource);
|
||||||
|
|
||||||
ViewportRenderTargets targets = {};
|
ViewportRenderTargets targets = {};
|
||||||
|
targets.depthView = &depthView;
|
||||||
|
targets.depthShaderView = &depthShaderView;
|
||||||
|
targets.selectionMaskView = &selectionMaskView;
|
||||||
|
targets.selectionMaskShaderView = &selectionMaskShaderView;
|
||||||
targets.objectIdShaderView = &objectIdShaderView;
|
targets.objectIdShaderView = &objectIdShaderView;
|
||||||
|
|
||||||
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
||||||
@@ -274,11 +285,16 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanCollectsPostSceneA
|
|||||||
return std::make_unique<NoopRenderPass>();
|
return std::make_unique<NoopRenderPass>();
|
||||||
},
|
},
|
||||||
[&selectionOutlinePassFactoryCallCount](
|
[&selectionOutlinePassFactoryCallCount](
|
||||||
RHIResourceView* objectIdTextureView,
|
ViewportRenderTargets* outlineTargets,
|
||||||
const std::vector<uint64_t>& selectedObjectIds,
|
const std::vector<uint64_t>& selectedObjectIds,
|
||||||
const SceneViewportSelectionOutlineStyle& style) {
|
const SceneViewportSelectionOutlineStyle& style) {
|
||||||
++selectionOutlinePassFactoryCallCount;
|
++selectionOutlinePassFactoryCallCount;
|
||||||
EXPECT_NE(objectIdTextureView, nullptr);
|
EXPECT_NE(outlineTargets, nullptr);
|
||||||
|
if (outlineTargets == nullptr) {
|
||||||
|
return std::unique_ptr<NoopRenderPass>();
|
||||||
|
}
|
||||||
|
EXPECT_NE(outlineTargets->selectionMaskShaderView, nullptr);
|
||||||
|
EXPECT_NE(outlineTargets->depthShaderView, nullptr);
|
||||||
EXPECT_EQ(selectedObjectIds.size(), 2u);
|
EXPECT_EQ(selectedObjectIds.size(), 2u);
|
||||||
EXPECT_FLOAT_EQ(style.outlineWidthPixels, 2.0f);
|
EXPECT_FLOAT_EQ(style.outlineWidthPixels, 2.0f);
|
||||||
return std::make_unique<NoopRenderPass>();
|
return std::make_unique<NoopRenderPass>();
|
||||||
@@ -301,6 +317,7 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanCollectsPostSceneA
|
|||||||
|
|
||||||
TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanSkipsRhiOverlayPassWhenFrameContainsOnlySceneIcons) {
|
TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanSkipsRhiOverlayPassWhenFrameContainsOnlySceneIcons) {
|
||||||
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
||||||
|
ViewportRenderTargets targets = {};
|
||||||
|
|
||||||
SceneViewportOverlayFrameData editorOverlayFrameData = {};
|
SceneViewportOverlayFrameData editorOverlayFrameData = {};
|
||||||
editorOverlayFrameData.overlay = overlay;
|
editorOverlayFrameData.overlay = overlay;
|
||||||
@@ -310,7 +327,7 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanSkipsRhiOverlayPas
|
|||||||
|
|
||||||
size_t overlayFactoryCallCount = 0u;
|
size_t overlayFactoryCallCount = 0u;
|
||||||
const auto result = BuildSceneViewportRenderPlan(
|
const auto result = BuildSceneViewportRenderPlan(
|
||||||
{},
|
targets,
|
||||||
overlay,
|
overlay,
|
||||||
{},
|
{},
|
||||||
editorOverlayFrameData,
|
editorOverlayFrameData,
|
||||||
@@ -318,7 +335,7 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanSkipsRhiOverlayPas
|
|||||||
return std::make_unique<NoopRenderPass>();
|
return std::make_unique<NoopRenderPass>();
|
||||||
},
|
},
|
||||||
[](
|
[](
|
||||||
RHIResourceView*,
|
ViewportRenderTargets*,
|
||||||
const std::vector<uint64_t>&,
|
const std::vector<uint64_t>&,
|
||||||
const SceneViewportSelectionOutlineStyle&) {
|
const SceneViewportSelectionOutlineStyle&) {
|
||||||
return std::make_unique<NoopRenderPass>();
|
return std::make_unique<NoopRenderPass>();
|
||||||
@@ -337,8 +354,9 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanSkipsRhiOverlayPas
|
|||||||
TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanWarnsWhenSelectionOutlineCannotAccessObjectIdTexture) {
|
TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanWarnsWhenSelectionOutlineCannotAccessObjectIdTexture) {
|
||||||
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
||||||
|
|
||||||
|
ViewportRenderTargets targets = {};
|
||||||
const auto result = BuildSceneViewportRenderPlan(
|
const auto result = BuildSceneViewportRenderPlan(
|
||||||
{},
|
targets,
|
||||||
overlay,
|
overlay,
|
||||||
{ 42u },
|
{ 42u },
|
||||||
{},
|
{},
|
||||||
@@ -346,7 +364,7 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanWarnsWhenSelection
|
|||||||
return std::make_unique<NoopRenderPass>();
|
return std::make_unique<NoopRenderPass>();
|
||||||
},
|
},
|
||||||
[](
|
[](
|
||||||
RHIResourceView*,
|
ViewportRenderTargets*,
|
||||||
const std::vector<uint64_t>&,
|
const std::vector<uint64_t>&,
|
||||||
const SceneViewportSelectionOutlineStyle&) {
|
const SceneViewportSelectionOutlineStyle&) {
|
||||||
return std::make_unique<NoopRenderPass>();
|
return std::make_unique<NoopRenderPass>();
|
||||||
@@ -357,11 +375,12 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanWarnsWhenSelection
|
|||||||
false);
|
false);
|
||||||
|
|
||||||
EXPECT_EQ(result.plan.postScenePasses.GetPassCount(), 1u);
|
EXPECT_EQ(result.plan.postScenePasses.GetPassCount(), 1u);
|
||||||
EXPECT_STREQ(result.warningStatusText, "Scene object id shader view is unavailable");
|
EXPECT_STREQ(result.warningStatusText, "Scene selection outline resources are unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ViewportRenderFlowUtilsTest, ApplySceneViewportRenderPlanAttachesPlannedPassesAndClearState) {
|
TEST(ViewportRenderFlowUtilsTest, ApplySceneViewportRenderPlanAttachesPlannedPassesAndClearState) {
|
||||||
DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
|
DummyResourceView objectIdDepthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
DummyResourceView objectIdView(ResourceViewType::RenderTarget);
|
DummyResourceView objectIdView(ResourceViewType::RenderTarget);
|
||||||
DummyResourceView objectIdShaderView(ResourceViewType::ShaderResource);
|
DummyResourceView objectIdShaderView(ResourceViewType::ShaderResource);
|
||||||
|
|
||||||
@@ -369,6 +388,7 @@ TEST(ViewportRenderFlowUtilsTest, ApplySceneViewportRenderPlanAttachesPlannedPas
|
|||||||
targets.width = 800;
|
targets.width = 800;
|
||||||
targets.height = 600;
|
targets.height = 600;
|
||||||
targets.depthView = &depthView;
|
targets.depthView = &depthView;
|
||||||
|
targets.objectIdDepthView = &objectIdDepthView;
|
||||||
targets.objectIdView = &objectIdView;
|
targets.objectIdView = &objectIdView;
|
||||||
targets.objectIdShaderView = &objectIdShaderView;
|
targets.objectIdShaderView = &objectIdShaderView;
|
||||||
|
|
||||||
@@ -395,14 +415,19 @@ TEST(ViewportRenderFlowUtilsTest, ApplySceneViewportRenderPlanAttachesPlannedPas
|
|||||||
TEST(ViewportRenderFlowUtilsTest, MarkSceneRenderSuccessMovesTargetsToShaderResourceState) {
|
TEST(ViewportRenderFlowUtilsTest, MarkSceneRenderSuccessMovesTargetsToShaderResourceState) {
|
||||||
DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
DummyResourceView objectIdView(ResourceViewType::RenderTarget);
|
DummyResourceView objectIdView(ResourceViewType::RenderTarget);
|
||||||
|
DummyResourceView objectIdDepthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
|
DummyResourceView selectionMaskView(ResourceViewType::RenderTarget);
|
||||||
|
|
||||||
ViewportRenderTargets targets = {};
|
ViewportRenderTargets targets = {};
|
||||||
targets.width = 640;
|
targets.width = 640;
|
||||||
targets.height = 360;
|
targets.height = 360;
|
||||||
targets.depthView = &depthView;
|
targets.depthView = &depthView;
|
||||||
|
targets.objectIdDepthView = &objectIdDepthView;
|
||||||
targets.objectIdView = &objectIdView;
|
targets.objectIdView = &objectIdView;
|
||||||
|
targets.selectionMaskView = &selectionMaskView;
|
||||||
targets.colorState = ResourceStates::Common;
|
targets.colorState = ResourceStates::Common;
|
||||||
targets.objectIdState = ResourceStates::Common;
|
targets.objectIdState = ResourceStates::Common;
|
||||||
|
targets.selectionMaskState = ResourceStates::Common;
|
||||||
|
|
||||||
XCEngine::Rendering::CameraRenderRequest request = {};
|
XCEngine::Rendering::CameraRenderRequest request = {};
|
||||||
request.surface = RenderSurface(640, 360);
|
request.surface = RenderSurface(640, 360);
|
||||||
@@ -411,16 +436,19 @@ TEST(ViewportRenderFlowUtilsTest, MarkSceneRenderSuccessMovesTargetsToShaderReso
|
|||||||
MarkSceneViewportRenderSuccess(targets, request);
|
MarkSceneViewportRenderSuccess(targets, request);
|
||||||
EXPECT_EQ(targets.colorState, ResourceStates::PixelShaderResource);
|
EXPECT_EQ(targets.colorState, ResourceStates::PixelShaderResource);
|
||||||
EXPECT_EQ(targets.objectIdState, ResourceStates::PixelShaderResource);
|
EXPECT_EQ(targets.objectIdState, ResourceStates::PixelShaderResource);
|
||||||
|
EXPECT_EQ(targets.selectionMaskState, ResourceStates::PixelShaderResource);
|
||||||
EXPECT_TRUE(targets.hasValidObjectIdFrame);
|
EXPECT_TRUE(targets.hasValidObjectIdFrame);
|
||||||
|
|
||||||
ViewportRenderTargets noObjectIdTargets = {};
|
ViewportRenderTargets noObjectIdTargets = {};
|
||||||
noObjectIdTargets.colorState = ResourceStates::Common;
|
noObjectIdTargets.colorState = ResourceStates::Common;
|
||||||
noObjectIdTargets.objectIdState = ResourceStates::Common;
|
noObjectIdTargets.objectIdState = ResourceStates::Common;
|
||||||
|
noObjectIdTargets.selectionMaskState = ResourceStates::Common;
|
||||||
XCEngine::Rendering::CameraRenderRequest noObjectIdRequest = {};
|
XCEngine::Rendering::CameraRenderRequest noObjectIdRequest = {};
|
||||||
|
|
||||||
MarkSceneViewportRenderSuccess(noObjectIdTargets, noObjectIdRequest);
|
MarkSceneViewportRenderSuccess(noObjectIdTargets, noObjectIdRequest);
|
||||||
EXPECT_EQ(noObjectIdTargets.colorState, ResourceStates::PixelShaderResource);
|
EXPECT_EQ(noObjectIdTargets.colorState, ResourceStates::PixelShaderResource);
|
||||||
EXPECT_EQ(noObjectIdTargets.objectIdState, ResourceStates::PixelShaderResource);
|
EXPECT_EQ(noObjectIdTargets.objectIdState, ResourceStates::PixelShaderResource);
|
||||||
|
EXPECT_EQ(noObjectIdTargets.selectionMaskState, ResourceStates::PixelShaderResource);
|
||||||
EXPECT_FALSE(noObjectIdTargets.hasValidObjectIdFrame);
|
EXPECT_FALSE(noObjectIdTargets.hasValidObjectIdFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ namespace {
|
|||||||
|
|
||||||
using XCEngine::Editor::BuildViewportColorSurface;
|
using XCEngine::Editor::BuildViewportColorSurface;
|
||||||
using XCEngine::Editor::BuildViewportObjectIdSurface;
|
using XCEngine::Editor::BuildViewportObjectIdSurface;
|
||||||
|
using XCEngine::Editor::BuildViewportSelectionMaskSurface;
|
||||||
using XCEngine::Editor::BuildViewportRenderTargetsReuseQuery;
|
using XCEngine::Editor::BuildViewportRenderTargetsReuseQuery;
|
||||||
using XCEngine::Editor::DestroyViewportRenderTargets;
|
using XCEngine::Editor::DestroyViewportRenderTargets;
|
||||||
using XCEngine::Editor::EditorViewportKind;
|
using XCEngine::Editor::EditorViewportKind;
|
||||||
@@ -78,10 +79,16 @@ TEST(ViewportRenderTargetsTest, BuildReuseQueryReflectsCurrentResourcePresence)
|
|||||||
targets.colorView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0x2));
|
targets.colorView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0x2));
|
||||||
targets.depthTexture = reinterpret_cast<RHITexture*>(static_cast<uintptr_t>(0x3));
|
targets.depthTexture = reinterpret_cast<RHITexture*>(static_cast<uintptr_t>(0x3));
|
||||||
targets.depthView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0x4));
|
targets.depthView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0x4));
|
||||||
targets.objectIdTexture = reinterpret_cast<RHITexture*>(static_cast<uintptr_t>(0x5));
|
targets.depthShaderView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0x5));
|
||||||
targets.objectIdView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0x6));
|
targets.objectIdTexture = reinterpret_cast<RHITexture*>(static_cast<uintptr_t>(0x6));
|
||||||
targets.objectIdShaderView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0x7));
|
targets.objectIdDepthTexture = reinterpret_cast<RHITexture*>(static_cast<uintptr_t>(0x7));
|
||||||
targets.textureHandle.nativeHandle = 0x8;
|
targets.objectIdDepthView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0x8));
|
||||||
|
targets.objectIdView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0x9));
|
||||||
|
targets.objectIdShaderView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0xA));
|
||||||
|
targets.selectionMaskTexture = reinterpret_cast<RHITexture*>(static_cast<uintptr_t>(0xB));
|
||||||
|
targets.selectionMaskView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0xC));
|
||||||
|
targets.selectionMaskShaderView = reinterpret_cast<RHIResourceView*>(static_cast<uintptr_t>(0xD));
|
||||||
|
targets.textureHandle.nativeHandle = 0xE;
|
||||||
targets.textureHandle.width = 1280;
|
targets.textureHandle.width = 1280;
|
||||||
targets.textureHandle.height = 720;
|
targets.textureHandle.height = 720;
|
||||||
|
|
||||||
@@ -94,25 +101,36 @@ TEST(ViewportRenderTargetsTest, BuildReuseQueryReflectsCurrentResourcePresence)
|
|||||||
EXPECT_TRUE(query.resources.hasColorView);
|
EXPECT_TRUE(query.resources.hasColorView);
|
||||||
EXPECT_TRUE(query.resources.hasDepthTexture);
|
EXPECT_TRUE(query.resources.hasDepthTexture);
|
||||||
EXPECT_TRUE(query.resources.hasDepthView);
|
EXPECT_TRUE(query.resources.hasDepthView);
|
||||||
|
EXPECT_TRUE(query.resources.hasDepthShaderView);
|
||||||
EXPECT_TRUE(query.resources.hasObjectIdTexture);
|
EXPECT_TRUE(query.resources.hasObjectIdTexture);
|
||||||
|
EXPECT_TRUE(query.resources.hasObjectIdDepthTexture);
|
||||||
|
EXPECT_TRUE(query.resources.hasObjectIdDepthView);
|
||||||
EXPECT_TRUE(query.resources.hasObjectIdView);
|
EXPECT_TRUE(query.resources.hasObjectIdView);
|
||||||
EXPECT_TRUE(query.resources.hasObjectIdShaderView);
|
EXPECT_TRUE(query.resources.hasObjectIdShaderView);
|
||||||
|
EXPECT_TRUE(query.resources.hasSelectionMaskTexture);
|
||||||
|
EXPECT_TRUE(query.resources.hasSelectionMaskView);
|
||||||
|
EXPECT_TRUE(query.resources.hasSelectionMaskShaderView);
|
||||||
EXPECT_TRUE(query.resources.hasTextureDescriptor);
|
EXPECT_TRUE(query.resources.hasTextureDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ViewportRenderTargetsTest, BuildSurfaceUsesTargetAttachmentsAndStates) {
|
TEST(ViewportRenderTargetsTest, BuildSurfaceUsesTargetAttachmentsAndStates) {
|
||||||
DummyResourceView colorView(ResourceViewType::RenderTarget);
|
DummyResourceView colorView(ResourceViewType::RenderTarget);
|
||||||
DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
DummyResourceView depthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
|
DummyResourceView objectIdDepthView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
DummyResourceView objectIdView(ResourceViewType::RenderTarget);
|
DummyResourceView objectIdView(ResourceViewType::RenderTarget);
|
||||||
|
DummyResourceView selectionMaskView(ResourceViewType::RenderTarget);
|
||||||
|
|
||||||
ViewportRenderTargets targets = {};
|
ViewportRenderTargets targets = {};
|
||||||
targets.width = 800;
|
targets.width = 800;
|
||||||
targets.height = 600;
|
targets.height = 600;
|
||||||
targets.colorView = &colorView;
|
targets.colorView = &colorView;
|
||||||
targets.depthView = &depthView;
|
targets.depthView = &depthView;
|
||||||
|
targets.objectIdDepthView = &objectIdDepthView;
|
||||||
targets.objectIdView = &objectIdView;
|
targets.objectIdView = &objectIdView;
|
||||||
|
targets.selectionMaskView = &selectionMaskView;
|
||||||
targets.colorState = ResourceStates::Common;
|
targets.colorState = ResourceStates::Common;
|
||||||
targets.objectIdState = ResourceStates::PixelShaderResource;
|
targets.objectIdState = ResourceStates::PixelShaderResource;
|
||||||
|
targets.selectionMaskState = ResourceStates::PixelShaderResource;
|
||||||
|
|
||||||
const auto colorSurface = BuildViewportColorSurface(targets);
|
const auto colorSurface = BuildViewportColorSurface(targets);
|
||||||
ASSERT_EQ(colorSurface.GetColorAttachments().size(), 1u);
|
ASSERT_EQ(colorSurface.GetColorAttachments().size(), 1u);
|
||||||
@@ -123,8 +141,14 @@ TEST(ViewportRenderTargetsTest, BuildSurfaceUsesTargetAttachmentsAndStates) {
|
|||||||
const auto objectIdSurface = BuildViewportObjectIdSurface(targets);
|
const auto objectIdSurface = BuildViewportObjectIdSurface(targets);
|
||||||
ASSERT_EQ(objectIdSurface.GetColorAttachments().size(), 1u);
|
ASSERT_EQ(objectIdSurface.GetColorAttachments().size(), 1u);
|
||||||
EXPECT_EQ(objectIdSurface.GetColorAttachments()[0], &objectIdView);
|
EXPECT_EQ(objectIdSurface.GetColorAttachments()[0], &objectIdView);
|
||||||
EXPECT_EQ(objectIdSurface.GetDepthAttachment(), &depthView);
|
EXPECT_EQ(objectIdSurface.GetDepthAttachment(), &objectIdDepthView);
|
||||||
EXPECT_EQ(objectIdSurface.GetColorStateBefore(), ResourceStates::PixelShaderResource);
|
EXPECT_EQ(objectIdSurface.GetColorStateBefore(), ResourceStates::PixelShaderResource);
|
||||||
|
|
||||||
|
const auto selectionMaskSurface = BuildViewportSelectionMaskSurface(targets);
|
||||||
|
ASSERT_EQ(selectionMaskSurface.GetColorAttachments().size(), 1u);
|
||||||
|
EXPECT_EQ(selectionMaskSurface.GetColorAttachments()[0], &selectionMaskView);
|
||||||
|
EXPECT_EQ(selectionMaskSurface.GetDepthAttachment(), &depthView);
|
||||||
|
EXPECT_EQ(selectionMaskSurface.GetColorStateBefore(), ResourceStates::PixelShaderResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ViewportRenderTargetsTest, DestroyViewportRenderTargetsShutsDownAndClearsState) {
|
TEST(ViewportRenderTargetsTest, DestroyViewportRenderTargetsShutsDownAndClearsState) {
|
||||||
@@ -132,9 +156,15 @@ TEST(ViewportRenderTargetsTest, DestroyViewportRenderTargetsShutsDownAndClearsSt
|
|||||||
auto* colorView = new DummyResourceView(ResourceViewType::RenderTarget);
|
auto* colorView = new DummyResourceView(ResourceViewType::RenderTarget);
|
||||||
auto* depthTexture = new DummyTexture(Format::D24_UNorm_S8_UInt);
|
auto* depthTexture = new DummyTexture(Format::D24_UNorm_S8_UInt);
|
||||||
auto* depthView = new DummyResourceView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
auto* depthView = new DummyResourceView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
|
auto* depthShaderView = new DummyResourceView(ResourceViewType::ShaderResource, Format::D24_UNorm_S8_UInt);
|
||||||
auto* objectIdTexture = new DummyTexture();
|
auto* objectIdTexture = new DummyTexture();
|
||||||
|
auto* objectIdDepthTexture = new DummyTexture(Format::D24_UNorm_S8_UInt);
|
||||||
|
auto* objectIdDepthView = new DummyResourceView(ResourceViewType::DepthStencil, Format::D24_UNorm_S8_UInt);
|
||||||
auto* objectIdView = new DummyResourceView(ResourceViewType::RenderTarget);
|
auto* objectIdView = new DummyResourceView(ResourceViewType::RenderTarget);
|
||||||
auto* objectIdShaderView = new DummyResourceView(ResourceViewType::ShaderResource);
|
auto* objectIdShaderView = new DummyResourceView(ResourceViewType::ShaderResource);
|
||||||
|
auto* selectionMaskTexture = new DummyTexture();
|
||||||
|
auto* selectionMaskView = new DummyResourceView(ResourceViewType::RenderTarget);
|
||||||
|
auto* selectionMaskShaderView = new DummyResourceView(ResourceViewType::ShaderResource);
|
||||||
|
|
||||||
ViewportRenderTargets targets = {};
|
ViewportRenderTargets targets = {};
|
||||||
targets.width = 640;
|
targets.width = 640;
|
||||||
@@ -143,9 +173,15 @@ TEST(ViewportRenderTargetsTest, DestroyViewportRenderTargetsShutsDownAndClearsSt
|
|||||||
targets.colorView = colorView;
|
targets.colorView = colorView;
|
||||||
targets.depthTexture = depthTexture;
|
targets.depthTexture = depthTexture;
|
||||||
targets.depthView = depthView;
|
targets.depthView = depthView;
|
||||||
|
targets.depthShaderView = depthShaderView;
|
||||||
targets.objectIdTexture = objectIdTexture;
|
targets.objectIdTexture = objectIdTexture;
|
||||||
|
targets.objectIdDepthTexture = objectIdDepthTexture;
|
||||||
|
targets.objectIdDepthView = objectIdDepthView;
|
||||||
targets.objectIdView = objectIdView;
|
targets.objectIdView = objectIdView;
|
||||||
targets.objectIdShaderView = objectIdShaderView;
|
targets.objectIdShaderView = objectIdShaderView;
|
||||||
|
targets.selectionMaskTexture = selectionMaskTexture;
|
||||||
|
targets.selectionMaskView = selectionMaskView;
|
||||||
|
targets.selectionMaskShaderView = selectionMaskShaderView;
|
||||||
targets.imguiCpuHandle.ptr = 123;
|
targets.imguiCpuHandle.ptr = 123;
|
||||||
targets.imguiGpuHandle.ptr = 456;
|
targets.imguiGpuHandle.ptr = 456;
|
||||||
targets.textureHandle.nativeHandle = 789;
|
targets.textureHandle.nativeHandle = 789;
|
||||||
@@ -153,6 +189,7 @@ TEST(ViewportRenderTargetsTest, DestroyViewportRenderTargetsShutsDownAndClearsSt
|
|||||||
targets.textureHandle.height = 360;
|
targets.textureHandle.height = 360;
|
||||||
targets.colorState = ResourceStates::RenderTarget;
|
targets.colorState = ResourceStates::RenderTarget;
|
||||||
targets.objectIdState = ResourceStates::PixelShaderResource;
|
targets.objectIdState = ResourceStates::PixelShaderResource;
|
||||||
|
targets.selectionMaskState = ResourceStates::PixelShaderResource;
|
||||||
targets.hasValidObjectIdFrame = true;
|
targets.hasValidObjectIdFrame = true;
|
||||||
|
|
||||||
DestroyViewportRenderTargets(nullptr, targets);
|
DestroyViewportRenderTargets(nullptr, targets);
|
||||||
@@ -161,18 +198,30 @@ TEST(ViewportRenderTargetsTest, DestroyViewportRenderTargetsShutsDownAndClearsSt
|
|||||||
EXPECT_TRUE(colorView->shutdownCalled);
|
EXPECT_TRUE(colorView->shutdownCalled);
|
||||||
EXPECT_TRUE(depthTexture->shutdownCalled);
|
EXPECT_TRUE(depthTexture->shutdownCalled);
|
||||||
EXPECT_TRUE(depthView->shutdownCalled);
|
EXPECT_TRUE(depthView->shutdownCalled);
|
||||||
|
EXPECT_TRUE(depthShaderView->shutdownCalled);
|
||||||
EXPECT_TRUE(objectIdTexture->shutdownCalled);
|
EXPECT_TRUE(objectIdTexture->shutdownCalled);
|
||||||
|
EXPECT_TRUE(objectIdDepthTexture->shutdownCalled);
|
||||||
|
EXPECT_TRUE(objectIdDepthView->shutdownCalled);
|
||||||
EXPECT_TRUE(objectIdView->shutdownCalled);
|
EXPECT_TRUE(objectIdView->shutdownCalled);
|
||||||
EXPECT_TRUE(objectIdShaderView->shutdownCalled);
|
EXPECT_TRUE(objectIdShaderView->shutdownCalled);
|
||||||
|
EXPECT_TRUE(selectionMaskTexture->shutdownCalled);
|
||||||
|
EXPECT_TRUE(selectionMaskView->shutdownCalled);
|
||||||
|
EXPECT_TRUE(selectionMaskShaderView->shutdownCalled);
|
||||||
EXPECT_EQ(targets.width, 0u);
|
EXPECT_EQ(targets.width, 0u);
|
||||||
EXPECT_EQ(targets.height, 0u);
|
EXPECT_EQ(targets.height, 0u);
|
||||||
EXPECT_EQ(targets.colorTexture, nullptr);
|
EXPECT_EQ(targets.colorTexture, nullptr);
|
||||||
EXPECT_EQ(targets.colorView, nullptr);
|
EXPECT_EQ(targets.colorView, nullptr);
|
||||||
EXPECT_EQ(targets.depthTexture, nullptr);
|
EXPECT_EQ(targets.depthTexture, nullptr);
|
||||||
EXPECT_EQ(targets.depthView, nullptr);
|
EXPECT_EQ(targets.depthView, nullptr);
|
||||||
|
EXPECT_EQ(targets.depthShaderView, nullptr);
|
||||||
EXPECT_EQ(targets.objectIdTexture, nullptr);
|
EXPECT_EQ(targets.objectIdTexture, nullptr);
|
||||||
|
EXPECT_EQ(targets.objectIdDepthTexture, nullptr);
|
||||||
|
EXPECT_EQ(targets.objectIdDepthView, nullptr);
|
||||||
EXPECT_EQ(targets.objectIdView, nullptr);
|
EXPECT_EQ(targets.objectIdView, nullptr);
|
||||||
EXPECT_EQ(targets.objectIdShaderView, nullptr);
|
EXPECT_EQ(targets.objectIdShaderView, nullptr);
|
||||||
|
EXPECT_EQ(targets.selectionMaskTexture, nullptr);
|
||||||
|
EXPECT_EQ(targets.selectionMaskView, nullptr);
|
||||||
|
EXPECT_EQ(targets.selectionMaskShaderView, nullptr);
|
||||||
EXPECT_EQ(targets.imguiCpuHandle.ptr, 0u);
|
EXPECT_EQ(targets.imguiCpuHandle.ptr, 0u);
|
||||||
EXPECT_EQ(targets.imguiGpuHandle.ptr, 0u);
|
EXPECT_EQ(targets.imguiGpuHandle.ptr, 0u);
|
||||||
EXPECT_EQ(targets.textureHandle.nativeHandle, 0u);
|
EXPECT_EQ(targets.textureHandle.nativeHandle, 0u);
|
||||||
@@ -180,6 +229,7 @@ TEST(ViewportRenderTargetsTest, DestroyViewportRenderTargetsShutsDownAndClearsSt
|
|||||||
EXPECT_EQ(targets.textureHandle.height, 0u);
|
EXPECT_EQ(targets.textureHandle.height, 0u);
|
||||||
EXPECT_EQ(targets.colorState, ResourceStates::Common);
|
EXPECT_EQ(targets.colorState, ResourceStates::Common);
|
||||||
EXPECT_EQ(targets.objectIdState, ResourceStates::Common);
|
EXPECT_EQ(targets.objectIdState, ResourceStates::Common);
|
||||||
|
EXPECT_EQ(targets.selectionMaskState, ResourceStates::Common);
|
||||||
EXPECT_FALSE(targets.hasValidObjectIdFrame);
|
EXPECT_FALSE(targets.hasValidObjectIdFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user