NazaraEngine/src/Nazara/Graphics/Graphics.cpp

182 lines
5.4 KiB
C++

// Copyright (C) 2020 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Core/ECS.hpp>
#include <Nazara/Graphics/MaterialPipeline.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <stdexcept>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
namespace
{
const UInt8 r_blitShader[] = {
#include <Nazara/Graphics/Resources/Shaders/blit.nzsl.h>
};
}
/*!
* \ingroup graphics
* \class Nz::Graphics
* \brief Graphics class that represents the module initializer of Graphics
*/
Graphics::Graphics(Config config) :
ModuleBase("Graphics", this),
m_preferredDepthStencilFormat(PixelFormat::Undefined)
{
ECS::RegisterComponents();
Renderer* renderer = Renderer::Instance();
const std::vector<RenderDeviceInfo>& renderDeviceInfo = renderer->QueryRenderDevices();
if (renderDeviceInfo.empty())
throw std::runtime_error("no render device available");
std::size_t bestRenderDeviceIndex = 0;
for (std::size_t i = 0; i < renderDeviceInfo.size(); ++i)
{
const auto& deviceInfo = renderDeviceInfo[i];
if (config.useDedicatedRenderDevice && deviceInfo.type == RenderDeviceType::Dedicated)
{
bestRenderDeviceIndex = i;
break;
}
else if (!config.useDedicatedRenderDevice && deviceInfo.type == RenderDeviceType::Integrated)
{
bestRenderDeviceIndex = i;
break;
}
}
RenderDeviceFeatures enabledFeatures;
enabledFeatures.anisotropicFiltering = renderDeviceInfo[bestRenderDeviceIndex].features.anisotropicFiltering;
enabledFeatures.nonSolidFaceFilling = renderDeviceInfo[bestRenderDeviceIndex].features.nonSolidFaceFilling;
m_renderDevice = renderer->InstanciateRenderDevice(bestRenderDeviceIndex, enabledFeatures);
if (!m_renderDevice)
throw std::runtime_error("failed to instantiate render device");
m_samplerCache.emplace(m_renderDevice);
MaterialPipeline::Initialize();
RenderPipelineLayoutInfo referenceLayoutInfo;
FillViewerPipelineLayout(referenceLayoutInfo);
FillWorldPipelineLayout(referenceLayoutInfo);
m_referencePipelineLayout = m_renderDevice->InstantiateRenderPipelineLayout(std::move(referenceLayoutInfo));
BuildFullscreenVertexBuffer();
BuildBlitPipeline();
SelectDepthStencilFormats();
}
Graphics::~Graphics()
{
MaterialPipeline::Uninitialize();
m_samplerCache.reset();
m_fullscreenVertexBuffer.reset();
m_fullscreenVertexDeclaration.reset();
m_blitPipeline.reset();
m_blitPipelineLayout.reset();
}
void Graphics::FillViewerPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set)
{
layoutInfo.bindings.push_back({
set, 0,
ShaderBindingType::UniformBuffer,
ShaderStageType_All
});
}
void Graphics::FillWorldPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set)
{
layoutInfo.bindings.push_back({
set, 0,
ShaderBindingType::UniformBuffer,
ShaderStageType_All
});
}
void Graphics::BuildBlitPipeline()
{
RenderPipelineLayoutInfo layoutInfo;
layoutInfo.bindings.assign({
{
0, 0,
ShaderBindingType::Texture,
ShaderStageType::Fragment
}
});
m_blitPipelineLayout = m_renderDevice->InstantiateRenderPipelineLayout(std::move(layoutInfo));
if (!m_blitPipelineLayout)
throw std::runtime_error("failed to instantiate fullscreen renderpipeline layout");
auto blitShader = m_renderDevice->InstantiateShaderModule(ShaderStageType::Fragment | ShaderStageType::Vertex, ShaderLanguage::NazaraShader, r_blitShader, sizeof(r_blitShader), {});
if (!blitShader)
throw std::runtime_error("failed to instantiate blit shader");
RenderPipelineInfo pipelineInfo;
pipelineInfo.pipelineLayout = m_blitPipelineLayout;
pipelineInfo.shaderModules.push_back(std::move(blitShader));
pipelineInfo.vertexBuffers.assign({
{
0,
m_fullscreenVertexDeclaration
}
});
m_blitPipeline = m_renderDevice->InstantiateRenderPipeline(std::move(pipelineInfo));
}
void Graphics::BuildFullscreenVertexBuffer()
{
m_fullscreenVertexDeclaration = VertexDeclaration::Get(VertexLayout::XY_UV);
std::array<Nz::VertexStruct_XY_UV, 3> vertexData = {
{
{
Nz::Vector2f(-1.f, 1.f),
Nz::Vector2f(0.0f, 1.0f),
},
{
Nz::Vector2f(-1.f, -3.f),
Nz::Vector2f(0.0f, -1.0f),
},
{
Nz::Vector2f(3.f, 1.f),
Nz::Vector2f(2.0f, 1.0f),
}
}
};
m_fullscreenVertexBuffer = m_renderDevice->InstantiateBuffer(BufferType::Vertex);
if (!m_fullscreenVertexBuffer->Initialize(m_fullscreenVertexDeclaration->GetStride() * vertexData.size(), BufferUsage::DeviceLocal))
throw std::runtime_error("failed to initialize fullscreen vertex buffer");
if (!m_fullscreenVertexBuffer->Fill(vertexData.data(), 0, m_fullscreenVertexDeclaration->GetStride() * vertexData.size()))
throw std::runtime_error("failed to fill fullscreen vertex buffer");
}
void Graphics::SelectDepthStencilFormats()
{
for (PixelFormat depthStencilCandidate : { PixelFormat::Depth24Stencil8, PixelFormat::Depth32FStencil8, PixelFormat::Depth16Stencil8 })
{
if (m_renderDevice->IsTextureFormatSupported(depthStencilCandidate, TextureUsage::DepthStencilAttachment))
{
m_preferredDepthStencilFormat = depthStencilCandidate;
break;
}
}
if (m_preferredDepthStencilFormat == PixelFormat::Undefined)
throw std::runtime_error("no supported depth-stencil format found");
}
Graphics* Graphics::s_instance = nullptr;
}