This commit is contained in:
Dmitry 2022-04-01 19:23:39 +03:00
parent 2d2672829e
commit 11c10dbe14
154 changed files with 30339 additions and 18534 deletions

Binary file not shown.

Binary file not shown.

View File

@ -46,7 +46,7 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{26bd6e61-e36d-464a-a312-4110adf10083}</ProjectGuid>
<RootNamespace>HelloTexturedCube</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

View File

@ -46,7 +46,7 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{bc17acd3-97eb-4d5c-a2c9-574cdaa7576b}</ProjectGuid>
<RootNamespace>HelloTriangle</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

View File

@ -15,7 +15,7 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{EBF1E2F9-65AA-419D-A3D3-AD66EB086E57}</ProjectGuid>
<RootNamespace>PAKBuilder</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

View File

@ -42,8 +42,8 @@ void TraverseDirectory(CWSZ parentDir, CWSZ foundDir, IO::RFile pakFile);
void Run()
{
std::wcout << _T("PACK Builder 1.2.1") << std::endl;
std::wcout << _T("Copyright (c) 2006-2020 Dmitry Maluev") << std::endl;
std::wcout << _T("PACK Builder 1.3") << std::endl;
std::wcout << _T("Copyright (c) 2006-2022 Dmitry Maluev") << std::endl;
std::wcout << _T("Arguments: [PAK/folder name] [input directory] [PAK output directory]") << std::endl;
int argCount;

View File

@ -17,6 +17,7 @@ Verus Engine is a modern, platform-agnostic 3D game engine. It is developed usin
* Native cross-platform code
* Same HLSL shader code for all APIs
* Deferred shading
* PBR/GGX with Metallic-Roughness workflow
* Efficient textures and streaming
* Large terrain support
* Built-in audio system
@ -39,6 +40,7 @@ You can download the latest version of VerusEdit here: https://verushub.com/page
These features should be implemented in version **1.x**:
- [x] glTF file format support
- [x] Materials v2.0: PBR/GGX with Metallic-Roughness workflow
- [ ] Shadow maps for all lights
- [ ] Triggers
- [ ] Quest system, dialogue system
@ -47,11 +49,11 @@ These features should be implemented in version **1.x**:
- [ ] Waypoints and A-Star navigation
- [ ] Lua scripting
- [ ] Linux support
- [ ] OpenXR
These features should be implemented in version **2.x**:
- [ ] Signed distance field (SDF) fonts
- [ ] Materials v2.0: separate textures for gloss, emission, etc.
- [ ] Ray tracing
- [ ] Mesh shaders
- [ ] Multithreaded renderer

View File

@ -15,7 +15,7 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{53923514-84B2-4B78-889A-8709C6BFA3A5}</ProjectGuid>
<RootNamespace>RendererDirect3D12</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

View File

@ -20,6 +20,7 @@ void CommandBufferD3D12::Init()
_vClearValues.reserve(16);
_vAttachmentStates.reserve(4);
_vBarriers.reserve(VERUS_MAX_FB_ATTACH);
VERUS_FOR(i, BaseRenderer::s_ringBufferSize)
_pCommandLists[i] = pRendererD3D12->CreateCommandList(D3D12_COMMAND_LIST_TYPE_DIRECT, pRendererD3D12->GetD3DCommandAllocator(i));
}
@ -31,6 +32,8 @@ void CommandBufferD3D12::Done()
VERUS_COM_RELEASE_CHECK(_pCommandLists[i].Get());
_pCommandLists[i].Reset();
}
VERUS_RT_ASSERT(_vAttachmentStates.capacity() < 100);
VERUS_RT_ASSERT(_vBarriers.capacity() < 1000);
VERUS_DONE(CommandBufferD3D12);
}
@ -77,6 +80,24 @@ void CommandBufferD3D12::End()
throw VERUS_RUNTIME_ERROR << "Close(); hr=" << VERUS_HR(hr);
}
void CommandBufferD3D12::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, Range arrayLayers)
{
auto& texD3D12 = static_cast<RTextureD3D12>(*tex);
_vBarriers.clear();
_vBarriers.reserve(mipLevels.GetCount() * arrayLayers.GetCount());
for (int layer : arrayLayers)
{
for (int mip : mipLevels)
{
const UINT subresource = D3D12CalcSubresource(mip, layer, 0, texD3D12.GetMipLevelCount(), texD3D12.GetArrayLayerCount());
_vBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(
texD3D12.GetD3DResource(), ToNativeImageLayout(oldLayout), ToNativeImageLayout(newLayout), subresource));
}
}
if (!_vBarriers.empty())
GetD3DGraphicsCommandList()->ResourceBarrier(static_cast<UINT>(_vBarriers.size()), _vBarriers.data());
}
void CommandBufferD3D12::BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor)
{
VERUS_QREF_RENDERER_D3D12;
@ -120,62 +141,37 @@ void CommandBufferD3D12::EndRenderPass()
{
auto pCmdList = GetD3DGraphicsCommandList();
CD3DX12_RESOURCE_BARRIER barriers[VERUS_MAX_CA];
int barrierCount = 0;
_vBarriers.clear();
_vBarriers.reserve(VERUS_MAX_FB_ATTACH);
int index = 0;
for (const auto& attachment : _pRenderPass->_vAttachments)
{
if (_vAttachmentStates[index] != attachment._finalState)
{
const auto& resources = _pFramebuffer->_vResources[index];
const auto& resource = _pFramebuffer->_vResources[index];
UINT subresource = 0;
switch (_pFramebuffer->_cubeMapFace)
if (CubeMapFace::none != _pFramebuffer->_cubeMapFace)
{
case CubeMapFace::all: subresource = ToNativeCubeMapFace(static_cast<CubeMapFace>(index)); break;
case CubeMapFace::none: subresource = 0; break;
default: subresource = !index ? ToNativeCubeMapFace(_pFramebuffer->_cubeMapFace) : 0;
UINT arrayLayer = 0;
switch (_pFramebuffer->_cubeMapFace)
{
case CubeMapFace::all: arrayLayer = ToNativeCubeMapFace(static_cast<CubeMapFace>(index)); break;
default: arrayLayer = !index ? ToNativeCubeMapFace(_pFramebuffer->_cubeMapFace) : 0;
}
subresource = D3D12CalcSubresource(0, arrayLayer, 0, _pFramebuffer->_mipLevels, 0);
}
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[index], attachment._finalState, subresource);
_vBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(resource, _vAttachmentStates[index], attachment._finalState, subresource));
}
index++;
if (VERUS_MAX_CA == barrierCount)
{
pCmdList->ResourceBarrier(barrierCount, barriers);
barrierCount = 0;
}
}
if (barrierCount)
pCmdList->ResourceBarrier(barrierCount, barriers);
if (!_vBarriers.empty())
pCmdList->ResourceBarrier(static_cast<UINT>(_vBarriers.size()), _vBarriers.data());
_pRenderPass = nullptr;
_pFramebuffer = nullptr;
_subpassIndex = 0;
}
void CommandBufferD3D12::BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter)
{
auto& geoD3D12 = static_cast<RGeometryD3D12>(*geo);
D3D12_VERTEX_BUFFER_VIEW views[VERUS_MAX_VB];
const int count = geoD3D12.GetVertexBufferCount();
int filteredCount = 0;
VERUS_FOR(i, count)
{
if ((bindingsFilter >> i) & 0x1)
{
VERUS_RT_ASSERT(filteredCount < VERUS_MAX_VB);
views[filteredCount] = *geoD3D12.GetD3DVertexBufferView(i);
filteredCount++;
}
}
GetD3DGraphicsCommandList()->IASetVertexBuffers(0, filteredCount, views);
}
void CommandBufferD3D12::BindIndexBuffer(GeometryPtr geo)
{
auto& geoD3D12 = static_cast<RGeometryD3D12>(*geo);
GetD3DGraphicsCommandList()->IASetIndexBuffer(geoD3D12.GetD3DIndexBufferView());
}
void CommandBufferD3D12::BindPipeline(PipelinePtr pipe)
{
auto pCmdList = GetD3DGraphicsCommandList();
@ -228,6 +224,30 @@ void CommandBufferD3D12::SetBlendConstants(const float* p)
GetD3DGraphicsCommandList()->OMSetBlendFactor(p);
}
void CommandBufferD3D12::BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter)
{
auto& geoD3D12 = static_cast<RGeometryD3D12>(*geo);
D3D12_VERTEX_BUFFER_VIEW views[VERUS_MAX_VB];
const int count = geoD3D12.GetVertexBufferCount();
int filteredCount = 0;
VERUS_FOR(i, count)
{
if ((bindingsFilter >> i) & 0x1)
{
VERUS_RT_ASSERT(filteredCount < VERUS_MAX_VB);
views[filteredCount] = *geoD3D12.GetD3DVertexBufferView(i);
filteredCount++;
}
}
GetD3DGraphicsCommandList()->IASetVertexBuffers(0, filteredCount, views);
}
void CommandBufferD3D12::BindIndexBuffer(GeometryPtr geo)
{
auto& geoD3D12 = static_cast<RGeometryD3D12>(*geo);
GetD3DGraphicsCommandList()->IASetIndexBuffer(geoD3D12.GetD3DIndexBufferView());
}
bool CommandBufferD3D12::BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle)
{
bool copyDescOnly = false;
@ -276,21 +296,6 @@ void CommandBufferD3D12::PushConstants(ShaderPtr shader, int offset, int size, c
GetD3DGraphicsCommandList()->SetGraphicsRoot32BitConstants(0, size, p, offset);
}
void CommandBufferD3D12::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, int arrayLayer)
{
auto& texD3D12 = static_cast<RTextureD3D12>(*tex);
CD3DX12_RESOURCE_BARRIER rb[16];
VERUS_RT_ASSERT(mipLevels.GetCount() <= VERUS_COUNT_OF(rb));
int index = 0;
for (int mip : mipLevels)
{
const UINT subresource = D3D12CalcSubresource(mip, arrayLayer, 0, texD3D12.GetMipLevelCount(), texD3D12.GetArrayLayerCount());
rb[index++] = CD3DX12_RESOURCE_BARRIER::Transition(
texD3D12.GetD3DResource(), ToNativeImageLayout(oldLayout), ToNativeImageLayout(newLayout), subresource);
}
GetD3DGraphicsCommandList()->ResourceBarrier(index, rb);
}
void CommandBufferD3D12::Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
{
GetD3DGraphicsCommandList()->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
@ -334,54 +339,62 @@ void CommandBufferD3D12::PrepareSubpass()
RP::RcD3DFramebufferSubpass fs = _pFramebuffer->_vSubpasses[_subpassIndex];
// Resource transitions for this subpass:
CD3DX12_RESOURCE_BARRIER barriers[VERUS_MAX_FB_ATTACH];
int resIndex = 0;
int barrierCount = 0;
UINT subresource = 0;
switch (_pFramebuffer->_cubeMapFace)
_vBarriers.clear();
_vBarriers.reserve(VERUS_MAX_FB_ATTACH);
int index = 0;
auto CalcSubresource = [this](int index) -> UINT
{
case CubeMapFace::all: subresource = ToNativeCubeMapFace(static_cast<CubeMapFace>(resIndex)); break;
case CubeMapFace::none: subresource = 0; break;
default: subresource = !resIndex ? ToNativeCubeMapFace(_pFramebuffer->_cubeMapFace) : 0;
}
if (CubeMapFace::none == _pFramebuffer->_cubeMapFace)
{
return 0;
}
else
{
UINT arrayLayer = 0;
switch (_pFramebuffer->_cubeMapFace)
{
case CubeMapFace::all: arrayLayer = ToNativeCubeMapFace(static_cast<CubeMapFace>(index)); break;
default: arrayLayer = !index ? ToNativeCubeMapFace(_pFramebuffer->_cubeMapFace) : 0;
}
return D3D12CalcSubresource(0, arrayLayer, 0, _pFramebuffer->_mipLevels, 0);
}
};
VERUS_FOR(i, subpass._vInput.size())
{
const auto& ref = subpass._vInput[i];
if (_vAttachmentStates[ref._index] != ref._state)
{
VERUS_RT_ASSERT(barrierCount < VERUS_MAX_FB_ATTACH);
const auto& resources = fs._vResources[resIndex];
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state, subresource);
const auto& resource = fs._vResources[index];
_vBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(resource, _vAttachmentStates[ref._index], ref._state, CalcSubresource(index)));
_vAttachmentStates[ref._index] = ref._state;
}
resIndex++;
index++;
}
VERUS_FOR(i, subpass._vColor.size())
{
const auto& ref = subpass._vColor[i];
if (_vAttachmentStates[ref._index] != ref._state)
{
VERUS_RT_ASSERT(barrierCount < VERUS_MAX_FB_ATTACH);
const auto& resources = fs._vResources[resIndex];
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(resources, _vAttachmentStates[ref._index], ref._state, subresource);
const auto& resource = fs._vResources[index];
_vBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(resource, _vAttachmentStates[ref._index], ref._state, CalcSubresource(index)));
_vAttachmentStates[ref._index] = ref._state;
}
resIndex++;
index++;
}
if (subpass._depthStencil._index >= 0)
{
const auto& ref = subpass._depthStencil;
if (_vAttachmentStates[ref._index] != ref._state)
{
VERUS_RT_ASSERT(barrierCount < VERUS_MAX_FB_ATTACH);
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(fs._vResources.back(), _vAttachmentStates[ref._index], ref._state, subresource);
_vBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(fs._vResources.back(), _vAttachmentStates[ref._index], ref._state, CalcSubresource(index)));
_vAttachmentStates[ref._index] = ref._state;
}
}
pCmdList->ResourceBarrier(barrierCount, barriers);
if (!_vBarriers.empty())
pCmdList->ResourceBarrier(static_cast<UINT>(_vBarriers.size()), _vBarriers.data());
// Clear attachments for this subpass:
int index = 0;
index = 0;
for (const auto& ref : subpass._vColor)
{
const auto& attachment = _pRenderPass->_vAttachments[ref._index];

View File

@ -13,6 +13,7 @@ namespace verus
RP::PcD3DFramebuffer _pFramebuffer = nullptr;
Vector<FLOAT> _vClearValues;
Vector<D3D12_RESOURCE_STATES> _vAttachmentStates;
Vector<D3D12_RESOURCE_BARRIER> _vBarriers;
int _subpassIndex = 0;
public:
@ -28,23 +29,24 @@ namespace verus
virtual void Begin() override;
virtual void End() override;
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, Range arrayLayers) override;
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle,
std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
virtual void NextSubpass() override;
virtual void EndRenderPass() override;
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter) override;
virtual void BindIndexBuffer(GeometryPtr geo) override;
virtual void BindPipeline(PipelinePtr pipe) override;
virtual void SetViewport(std::initializer_list<Vector4> il, float minDepth, float maxDepth) override;
virtual void SetScissor(std::initializer_list<Vector4> il) override;
virtual void SetBlendConstants(const float* p) override;
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter) override;
virtual void BindIndexBuffer(GeometryPtr geo) override;
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle) override;
virtual void PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags) override;
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, int arrayLayer) override;
virtual void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance) override;
virtual void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance) override;
virtual void Dispatch(int groupCountX, int groupCountY, int groupCountZ) override;

View File

@ -132,7 +132,11 @@ DXGI_FORMAT CGI::ToNativeFormat(Format format, bool typeless)
case Format::unormBC1: return DXGI_FORMAT_BC1_UNORM;
case Format::unormBC2: return DXGI_FORMAT_BC2_UNORM;
case Format::unormBC3: return DXGI_FORMAT_BC3_UNORM;
case Format::unormBC4: return DXGI_FORMAT_BC4_UNORM;
case Format::unormBC5: return DXGI_FORMAT_BC5_UNORM;
case Format::unormBC7: return DXGI_FORMAT_BC7_UNORM;
case Format::snormBC4: return DXGI_FORMAT_BC4_SNORM;
case Format::snormBC5: return DXGI_FORMAT_BC5_SNORM;
case Format::srgbBC1: return DXGI_FORMAT_BC1_UNORM_SRGB;
case Format::srgbBC2: return DXGI_FORMAT_BC2_UNORM_SRGB;
case Format::srgbBC3: return DXGI_FORMAT_BC3_UNORM_SRGB;
@ -177,6 +181,7 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
{
VERUS_RT_ASSERT(components >= 1 && components <= 4);
int index = components - 1;
static const DXGI_FORMAT floats[] =
{
DXGI_FORMAT_R32_FLOAT,
@ -184,6 +189,24 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT
};
static const DXGI_FORMAT halfs[] =
{
DXGI_FORMAT_R16_FLOAT,
DXGI_FORMAT_R16G16_FLOAT,
DXGI_FORMAT_R16G16_FLOAT,
DXGI_FORMAT_R16G16B16A16_FLOAT
};
static const DXGI_FORMAT shorts[] =
{
DXGI_FORMAT_R16G16_SINT,
DXGI_FORMAT_R16G16_SINT,
DXGI_FORMAT_R16G16B16A16_SINT,
DXGI_FORMAT_R16G16B16A16_SINT,
DXGI_FORMAT_R16G16_SNORM,
DXGI_FORMAT_R16G16_SNORM,
DXGI_FORMAT_R16G16B16A16_SNORM,
DXGI_FORMAT_R16G16B16A16_SNORM
};
static const DXGI_FORMAT bytes[] =
{
DXGI_FORMAT_R8G8B8A8_UINT,
@ -199,17 +222,7 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
DXGI_FORMAT_R8G8B8A8_SNORM,
DXGI_FORMAT_R8G8B8A8_SNORM
};
static const DXGI_FORMAT shorts[] =
{
DXGI_FORMAT_R16G16_SINT,
DXGI_FORMAT_R16G16_SINT,
DXGI_FORMAT_R16G16B16A16_SINT,
DXGI_FORMAT_R16G16B16A16_SINT,
DXGI_FORMAT_R16G16_SNORM,
DXGI_FORMAT_R16G16_SNORM,
DXGI_FORMAT_R16G16B16A16_SNORM,
DXGI_FORMAT_R16G16B16A16_SNORM
};
switch (type)
{
case ViaType::floats:
@ -217,15 +230,10 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
return floats[index];
}
break;
case ViaType::ubytes:
case ViaType::halfs:
{
VERUS_RT_ASSERT(4 == components);
switch (usage)
{
case ViaUsage::normal: index += 8; break; // SNORM.
case ViaUsage::color: index += 4; break; // UNORM.
}
return bytes[index];
VERUS_RT_ASSERT(3 != components);
return halfs[index];
}
break;
case ViaType::shorts:
@ -233,6 +241,7 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
VERUS_RT_ASSERT(2 == components || 4 == components);
switch (usage)
{
case ViaUsage::normal:
case ViaUsage::tangent:
case ViaUsage::binormal:
index += 4; break; // SNORM.
@ -240,6 +249,21 @@ DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
return shorts[index];
}
break;
case ViaType::ubytes:
{
VERUS_RT_ASSERT(4 == components);
switch (usage)
{
case ViaUsage::normal:
case ViaUsage::tangent:
case ViaUsage::binormal:
index += 8; break; // SNORM.
case ViaUsage::color:
index += 4; break; // UNORM.
}
return bytes[index];
}
break;
default: throw VERUS_RECOVERABLE << "ToNativeFormat(); ViaType=?";
}
}

View File

@ -71,6 +71,7 @@ namespace verus
Vector<D3DFramebufferSubpass> _vSubpasses;
int _width = 0;
int _height = 0;
int _mipLevels = 1;
CubeMapFace _cubeMapFace = CubeMapFace::none;
};
VERUS_TYPEDEFS(D3DFramebuffer);

View File

@ -187,6 +187,7 @@ void RendererD3D12::InitD3D()
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
allocatorDesc.pDevice = _pDevice.Get();
allocatorDesc.pAdapter = pAdapter.Get();
if (FAILED(hr = D3D12MA::CreateAllocator(&allocatorDesc, &_pMaAllocator)))
throw VERUS_RUNTIME_ERROR << "CreateAllocator(); hr=" << VERUS_HR(hr);
@ -732,7 +733,9 @@ FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initia
return texD3D12.GetD3DResource();
}
else
{
return _vSwapChainBuffers[swapChainBufferIndex].Get();
}
}
else
{
@ -750,7 +753,9 @@ FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initia
return texD3D12.GetDescriptorHeapRTV().AtCPU(0);
}
else
{
return _dhSwapChainBuffersRTVs.AtCPU(swapChainBufferIndex);
}
}
else
{
@ -787,7 +792,11 @@ FBHandle RendererD3D12::CreateFramebuffer(RPHandle renderPassHandle, std::initia
framebuffer._vResources.reserve(renderPass._vAttachments.size());
VERUS_FOR(i, renderPass._vAttachments.size())
{
if (!i && -1 == swapChainBufferIndex)
framebuffer._mipLevels = vTex.front()->GetMipLevelCount();
framebuffer._vResources.push_back(GetResource(i));
}
framebuffer._vSubpasses.reserve(renderPass._vSubpasses.size());
for (const auto& subpass : renderPass._vSubpasses)

View File

@ -75,14 +75,15 @@ namespace verus
// Which graphics API?
virtual Gapi GetGapi() override { return Gapi::direct3D12; }
// Frame cycle:
// <FrameCycle>
virtual void BeginFrame(bool present) override;
virtual void EndFrame(bool present) override;
virtual void Present() override;
virtual void Sync(bool present) override;
virtual void WaitIdle() override;
// </FrameCycle>
// Resources:
// <Resources>
virtual PBaseCommandBuffer InsertCommandBuffer() override;
virtual PBaseGeometry InsertGeometry() override;
virtual PBasePipeline InsertPipeline() override;
@ -104,6 +105,7 @@ namespace verus
int GetNextFramebufferIndex() const;
RP::RcD3DRenderPass GetRenderPass(RPHandle handle) const;
RP::RcD3DFramebuffer GetFramebuffer(FBHandle handle) const;
// </Resources>
RDynamicDescriptorHeap GetViewHeap() { return _dhViews; }
RDynamicDescriptorHeap GetSamplerHeap() { return _dhSamplers; }

View File

@ -401,7 +401,7 @@ void ShaderD3D12::CreatePipelineLayout()
_pRootSignature->SetName(_C(Str::Utf8ToWide("RootSignature (" + _sourceName + ")")));
}
CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips)
CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMipLevels, const int* pArrayLayers)
{
VERUS_QREF_RENDERER_D3D12;
@ -442,7 +442,9 @@ CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_
for (auto x : il)
{
complexSet._vTextures.push_back(x);
const int mip = pMips ? pMips[index] : 0;
const int mipLevelCount = x->GetMipLevelCount();
const int mipLevel = pMipLevels ? pMipLevels[index] : 0;
const int arrayLayer = pArrayLayers ? pArrayLayers[index] : 0;
auto& texD3D12 = static_cast<RTextureD3D12>(*x);
if (Sampler::storage == dsd._vSamplers[index])
{
@ -450,14 +452,14 @@ CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_
{
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
CD3DX12_CPU_DESCRIPTOR_HANDLE(complexSet._hpBase._hCPU, 1 + index, pRendererD3D12->GetViewHeap().GetHandleIncrementSize()),
texD3D12.GetDescriptorHeapUAV().AtCPU(mip),
texD3D12.GetDescriptorHeapUAV().AtCPU(mipLevel + arrayLayer * (mipLevelCount - 1)),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
else
{
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
complexSet._dhViews.AtCPU(index),
texD3D12.GetDescriptorHeapUAV().AtCPU(mip),
texD3D12.GetDescriptorHeapUAV().AtCPU(mipLevel + arrayLayer * (mipLevelCount - 1)),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
}
@ -467,14 +469,14 @@ CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_
{
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
CD3DX12_CPU_DESCRIPTOR_HANDLE(complexSet._hpBase._hCPU, 1 + index, pRendererD3D12->GetViewHeap().GetHandleIncrementSize()),
texD3D12.GetDescriptorHeapSRV().AtCPU(mip),
texD3D12.GetDescriptorHeapSRV().AtCPU(mipLevel + arrayLayer * mipLevelCount),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
else
{
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
complexSet._dhViews.AtCPU(index),
texD3D12.GetDescriptorHeapSRV().AtCPU(mip),
texD3D12.GetDescriptorHeapSRV().AtCPU(mipLevel + arrayLayer * mipLevelCount),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
if (Sampler::custom == dsd._vSamplers[index])
@ -578,7 +580,7 @@ CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateUniformBuffer(int setNumber, in
if (dsd._offset + dsd._alignedSize > dsd._capacityInBytes)
{
VERUS_RT_FAIL("UniformBuffer is full.");
return CD3DX12_GPU_DESCRIPTOR_HANDLE();
return CD3DX12_GPU_DESCRIPTOR_HANDLE(D3D12_DEFAULT);
}
VERUS_RT_ASSERT(dsd._pMappedData);
@ -629,9 +631,9 @@ CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateSamplers(int setNumber, int com
auto& dsd = _vDescriptorSetDesc[setNumber];
if (dsd._staticSamplersOnly)
return CD3DX12_GPU_DESCRIPTOR_HANDLE();
return CD3DX12_GPU_DESCRIPTOR_HANDLE(D3D12_DEFAULT);
CD3DX12_GPU_DESCRIPTOR_HANDLE hOffset = CD3DX12_GPU_DESCRIPTOR_HANDLE();
CD3DX12_GPU_DESCRIPTOR_HANDLE hOffset(D3D12_DEFAULT);
const auto& complexSet = _vComplexSets[complexSetHandle];
const int maxCount = Utils::Cast32(complexSet._vTextures.size());
VERUS_FOR(i, maxCount)

View File

@ -82,7 +82,7 @@ namespace verus
virtual void CreateDescriptorSet(int setNumber, const void* pSrc, int size, int capacity, std::initializer_list<Sampler> il, ShaderStageFlags stageFlags) override;
virtual void CreatePipelineLayout() override;
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips) override;
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMipLevels, const int* pArrayLayers) override;
virtual void FreeDescriptorSet(CSHandle& complexSetHandle) override;
virtual void BeginBindDescriptors() override;

View File

@ -21,26 +21,29 @@ void TextureD3D12::Init(RcTextureDesc desc)
VERUS_QREF_RENDERER_D3D12;
HRESULT hr = 0;
_initAtFrame = renderer.GetFrameCount();
if (desc._name)
_name = desc._name;
// Variables:
_size = Vector4(
float(desc._width),
float(desc._height),
1.f / desc._width,
1.f / desc._height);
if (desc._name)
_name = desc._name;
_desc = desc;
_desc._mipLevels = desc._mipLevels ? desc._mipLevels : Math::ComputeMipLevels(desc._width, desc._height, desc._depth);
_initAtFrame = renderer.GetFrameCount();
if (desc._flags & TextureDesc::Flags::anyShaderResource)
_mainLayout = ImageLayout::xsReadOnly;
_bytesPerPixel = FormatToBytesPerPixel(desc._format);
_desc._mipLevels = _desc._mipLevels ? _desc._mipLevels : Math::ComputeMipLevels(_desc._width, _desc._height, _desc._depth);
const bool renderTarget = (_desc._flags & TextureDesc::Flags::colorAttachment);
const bool depthFormat = IsDepthFormat(desc._format);
const bool depthFormat = IsDepthFormat(_desc._format);
const bool depthSampled = _desc._flags & (TextureDesc::Flags::depthSampledR | TextureDesc::Flags::depthSampledW);
const bool cubeMap = (_desc._flags & TextureDesc::Flags::cubeMap);
if (cubeMap)
_desc._arrayLayers *= +CubeMapFace::count;
if (_desc._flags & TextureDesc::Flags::anyShaderResource)
_mainLayout = ImageLayout::xsReadOnly;
// Create:
D3D12_RESOURCE_DESC resDesc = {};
resDesc.Dimension = (_desc._depth > 1) ? D3D12_RESOURCE_DIMENSION_TEXTURE3D : D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resDesc.Width = _desc._width;
@ -58,7 +61,6 @@ void TextureD3D12::Init(RcTextureDesc desc)
if (!depthSampled)
resDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
}
D3D12_RESOURCE_STATES initialResourceState = ToNativeImageLayout(_mainLayout);
D3D12_CLEAR_VALUE clearValue = {};
clearValue.Format = ToNativeFormat(_desc._format, false);
@ -83,8 +85,10 @@ void TextureD3D12::Init(RcTextureDesc desc)
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_DEFAULT); hr=" << VERUS_HR(hr);
_resource._pResource->SetName(_C(Str::Utf8ToWide(_name)));
// Optional mipmap:
if (_desc._flags & TextureDesc::Flags::generateMips)
{
VERUS_RT_ASSERT(_desc._mipLevels > 1);
// Create storage image for compute shader's output. No need to have the first mip level.
const int uavMipLevels = Math::Max(1, _desc._mipLevels - 1);
D3D12_RESOURCE_DESC resDescUAV = resDesc;
@ -111,17 +115,38 @@ void TextureD3D12::Init(RcTextureDesc desc)
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_DEFAULT); hr=" << VERUS_HR(hr);
_uaResource._pResource->SetName(_C(Str::Utf8ToWide(_name + " (UAV)")));
_dhUAV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, uavMipLevels);
VERUS_FOR(i, uavMipLevels)
_vCshGenerateMips.reserve(Math::DivideByMultiple<int>(_desc._mipLevels, 4));
_dhUAV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, uavMipLevels * _desc._arrayLayers);
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
uavDesc.Format = resDescUAV.Format;
uavDesc.ViewDimension = (_desc._arrayLayers > 1) ? D3D12_UAV_DIMENSION_TEXTURE2DARRAY : D3D12_UAV_DIMENSION_TEXTURE2D;
VERUS_FOR(layer, _desc._arrayLayers)
{
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
uavDesc.Format = resDescUAV.Format;
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
uavDesc.Texture2D.MipSlice = i;
pRendererD3D12->GetD3DDevice()->CreateUnorderedAccessView(_uaResource._pResource.Get(), nullptr, &uavDesc, _dhUAV.AtCPU(i));
VERUS_FOR(mip, uavMipLevels)
{
if (D3D12_UAV_DIMENSION_TEXTURE2D == uavDesc.ViewDimension)
{
uavDesc.Texture2D.MipSlice = mip;
pRendererD3D12->GetD3DDevice()->CreateUnorderedAccessView(_uaResource._pResource.Get(), nullptr, &uavDesc, _dhUAV.AtCPU(mip));
}
else
{
uavDesc.Texture2DArray.MipSlice = mip;
uavDesc.Texture2DArray.FirstArraySlice = layer;
uavDesc.Texture2DArray.ArraySize = 1;
if (cubeMap)
{
const int cubeIndex = layer / +CubeMapFace::count;
const int faceIndex = layer % +CubeMapFace::count;
uavDesc.Texture2DArray.FirstArraySlice = (cubeIndex * +CubeMapFace::count) + ToNativeCubeMapFace(static_cast<CubeMapFace>(faceIndex));
}
pRendererD3D12->GetD3DDevice()->CreateUnorderedAccessView(_uaResource._pResource.Get(), nullptr, &uavDesc, _dhUAV.AtCPU(mip + layer * uavMipLevels));
}
}
}
}
// Optional readback buffer:
if (_desc._readbackMip != SHRT_MAX)
{
if (_desc._readbackMip < 0)
@ -147,6 +172,7 @@ void TextureD3D12::Init(RcTextureDesc desc)
}
}
// Create views:
if (renderTarget)
{
if (cubeMap)
@ -169,7 +195,6 @@ void TextureD3D12::Init(RcTextureDesc desc)
pRendererD3D12->GetD3DDevice()->CreateRenderTargetView(_resource._pResource.Get(), nullptr, _dhRTV.AtCPU(0));
}
}
if (depthFormat)
{
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
@ -220,6 +245,7 @@ void TextureD3D12::Init(RcTextureDesc desc)
}
}
// Custom sampler:
if (_desc._pSamplerDesc)
CreateSampler();
@ -372,6 +398,9 @@ bool TextureD3D12::ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCom
void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
{
VERUS_RT_ASSERT(_desc._flags & TextureDesc::Flags::generateMips);
if (_desc._flags & TextureDesc::Flags::cubeMap)
return GenerateCubeMapMips(pCB);
VERUS_QREF_RENDERER;
if (!pCB)
@ -409,10 +438,10 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
ub._dstTexelSize.x = 1.f / dstWidth;
ub._dstTexelSize.y = 1.f / dstHeight;
int mips[5] = {}; // For input texture (always mip 0) and 4 UAV mips.
VERUS_FOR(mip, dispatchMipCount)
mips[mip + 1] = srcMip + mip;
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0 | ShaderD3D12::SET_MOD_TO_VIEW_HEAP, { tex, tex, tex, tex, tex }, mips);
int mipLevels[5] = {}; // For input texture (always mip 0) and 4 UAV mips.
VERUS_FOR(i, dispatchMipCount)
mipLevels[i + 1] = srcMip + i;
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0 | ShaderD3D12::SET_MOD_TO_VIEW_HEAP, { tex, tex, tex, tex, tex }, mipLevels);
_vCshGenerateMips.push_back(complexSetHandle);
pCB->BindDescriptors(shader, 0, complexSetHandle);
@ -425,19 +454,18 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
{
CD3DX12_RESOURCE_BARRIER barriers[4];
int barrierCount = 0;
VERUS_FOR(mip, dispatchMipCount)
VERUS_FOR(i, dispatchMipCount)
{
const int subUAV = srcMip + mip;
const int subUAV = srcMip + i;
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uaResource._pResource.Get(),
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE, subUAV);
}
pCmdList->ResourceBarrier(barrierCount, barriers);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, ImageLayout::transferDst, Range(0, dispatchMipCount).OffsetBy(srcMip + 1));
}
VERUS_FOR(mip, dispatchMipCount)
VERUS_FOR(i, dispatchMipCount)
{
const int subUAV = srcMip + mip;
const int subUAV = srcMip + i;
const int subSRV = subUAV + 1;
const auto dstCopyLoc = CD3DX12_TEXTURE_COPY_LOCATION(_resource._pResource.Get(), subSRV);
const auto srcCopyLoc = CD3DX12_TEXTURE_COPY_LOCATION(_uaResource._pResource.Get(), subUAV);
@ -451,14 +479,13 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
{
CD3DX12_RESOURCE_BARRIER barriers[4];
int barrierCount = 0;
VERUS_FOR(mip, dispatchMipCount)
VERUS_FOR(i, dispatchMipCount)
{
const int subUAV = srcMip + mip;
const int subUAV = srcMip + i;
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uaResource._pResource.Get(),
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, subUAV);
}
pCmdList->ResourceBarrier(barrierCount, barriers);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferDst, ImageLayout::xsReadOnly, Range(0, dispatchMipCount).OffsetBy(srcMip + 1));
}
@ -475,6 +502,108 @@ void TextureD3D12::GenerateMips(PBaseCommandBuffer pCB)
Schedule(0);
}
void TextureD3D12::GenerateCubeMapMips(PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
if (!pCB)
pCB = renderer.GetCommandBuffer().Get();
auto pCmdList = static_cast<PCommandBufferD3D12>(pCB)->GetD3DGraphicsCommandList();
auto shader = renderer.GetShaderGenerateCubeMapMips();
auto& ub = renderer.GetUbGenerateCubeMapMips();
auto tex = TexturePtr::From(this);
const int maxMipLevel = _desc._mipLevels - 1;
// Transition state for sampling in compute shader:
if (_mainLayout != ImageLayout::xsReadOnly)
pCB->PipelineImageMemoryBarrier(tex, _mainLayout, ImageLayout::xsReadOnly, Range(0, _desc._mipLevels), Range(0, +CubeMapFace::count));
pCB->BindPipeline(renderer.GetPipelineGenerateCubeMapMips());
shader->BeginBindDescriptors();
int dispatchIndex = 0;
for (int srcMip = 0; srcMip < maxMipLevel;)
{
const int srcWidth = Math::Max(1, _desc._width >> srcMip);
const int srcHeight = Math::Max(1, _desc._height >> srcMip);
const int dstWidth = Math::Max(1, srcWidth >> 1);
const int dstHeight = Math::Max(1, srcHeight >> 1);
ub._srcMipLevel = srcMip;
ub._srgb = IsSRGBFormat(_desc._format);
ub._dstTexelSize.x = 1.f / dstWidth;
ub._dstTexelSize.y = 1.f / dstHeight;
int mipLevels[7] = {};
VERUS_FOR(i, +CubeMapFace::count)
mipLevels[i + 1] = srcMip;
int arrayLayers[7] = {};
VERUS_FOR(i, +CubeMapFace::count)
arrayLayers[i + 1] = ToNativeCubeMapFace(static_cast<CubeMapFace>(i));
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0 | ShaderD3D12::SET_MOD_TO_VIEW_HEAP, { tex, tex, tex, tex, tex, tex, tex }, mipLevels, arrayLayers);
_vCshGenerateMips.push_back(complexSetHandle);
pCB->BindDescriptors(shader, 0, complexSetHandle);
pCB->Dispatch(Math::DivideByMultiple(dstWidth, 8), Math::DivideByMultiple(dstHeight, 8));
auto rb = CD3DX12_RESOURCE_BARRIER::UAV(_uaResource._pResource.Get());
pCmdList->ResourceBarrier(1, &rb);
// Transition state for upcoming CopyTextureRegion():
{
CD3DX12_RESOURCE_BARRIER barriers[+CubeMapFace::count];
int barrierCount = 0;
VERUS_FOR(i, +CubeMapFace::count)
{
const int subUAV = D3D12CalcSubresource(srcMip, i, 0, _desc._mipLevels - 1, _desc._arrayLayers);
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uaResource._pResource.Get(),
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE, subUAV);
}
pCmdList->ResourceBarrier(barrierCount, barriers);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, ImageLayout::transferDst, srcMip + 1, Range(0, +CubeMapFace::count));
}
VERUS_FOR(i, +CubeMapFace::count)
{
const int subUAV = D3D12CalcSubresource(srcMip, i, 0, _desc._mipLevels - 1, _desc._arrayLayers);
const int subSRV = D3D12CalcSubresource(srcMip + 1, i, 0, _desc._mipLevels, _desc._arrayLayers);
const auto dstCopyLoc = CD3DX12_TEXTURE_COPY_LOCATION(_resource._pResource.Get(), subSRV);
const auto srcCopyLoc = CD3DX12_TEXTURE_COPY_LOCATION(_uaResource._pResource.Get(), subUAV);
pCmdList->CopyTextureRegion(
&dstCopyLoc,
0, 0, 0,
&srcCopyLoc,
nullptr);
}
// Transition state for next Dispatch():
{
CD3DX12_RESOURCE_BARRIER barriers[+CubeMapFace::count];
int barrierCount = 0;
VERUS_FOR(i, +CubeMapFace::count)
{
const int subUAV = D3D12CalcSubresource(srcMip, i, 0, _desc._mipLevels - 1, _desc._arrayLayers);
barriers[barrierCount++] = CD3DX12_RESOURCE_BARRIER::Transition(_uaResource._pResource.Get(),
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, subUAV);
}
pCmdList->ResourceBarrier(barrierCount, barriers);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferDst, ImageLayout::xsReadOnly, srcMip + 1, Range(0, +CubeMapFace::count));
}
srcMip++;
dispatchIndex++;
}
shader->EndBindDescriptors();
// Revert to main state:
if (_mainLayout != ImageLayout::xsReadOnly)
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, _mainLayout, Range(0, _desc._mipLevels), Range(0, +CubeMapFace::count));
ClearCshGenerateMips();
Schedule(0);
}
Continue TextureD3D12::Scheduled_Update()
{
if (!IsScheduledAllowed())

View File

@ -35,6 +35,7 @@ namespace verus
virtual bool ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) override;
virtual void GenerateMips(PBaseCommandBuffer pCB) override;
void GenerateCubeMapMips(PBaseCommandBuffer pCB);
virtual Continue Scheduled_Update() override;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -24,4 +24,35 @@
</LinkedListItems>
</Expand>
</Type>
<!--
Due to custom way of accesing next items in
D3D12MA::IntrusiveLinkedList via methods in provided type traits,
every specialization must be manually added with
custom <NextPointer> field describing proper way of iterating the list.
-->
<Type Name="D3D12MA::IntrusiveLinkedList&lt;D3D12MA::CommittedAllocationListItemTraits&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<LinkedListItems>
<Size>m_Count</Size>
<HeadPointer>m_Front</HeadPointer>
<NextPointer>m_Committed.next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="D3D12MA::IntrusiveLinkedList&lt;D3D12MA::PoolListItemTraits&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<LinkedListItems>
<Size>m_Count</Size>
<HeadPointer>m_Front</HeadPointer>
<NextPointer>m_NextPool</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
</AutoVisualizer>

View File

@ -15,7 +15,7 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{C9195A1C-9224-4B40-BBBC-AA90EF3BE3E0}</ProjectGuid>
<RootNamespace>RendererVulkan</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

View File

@ -73,6 +73,116 @@ void CommandBufferVulkan::End()
throw VERUS_RUNTIME_ERROR << "vkEndCommandBuffer(); res=" << res;
}
void CommandBufferVulkan::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, Range arrayLayers)
{
auto& texVulkan = static_cast<RTextureVulkan>(*tex);
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; // Waiting for this stage to finish (TOP_OF_PIPE means wait for nothing).
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; // Which stage is waiting to start (BOTTOM_OF_PIPE means nothing is waiting).
const VkPipelineStageFlags dstStageMaskXS = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
VkImageMemoryBarrier vkimb = {};
vkimb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
vkimb.oldLayout = ToNativeImageLayout(oldLayout);
vkimb.newLayout = ToNativeImageLayout(newLayout);
vkimb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkimb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkimb.image = texVulkan.GetVkImage();
vkimb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkimb.subresourceRange.baseMipLevel = mipLevels._begin;
vkimb.subresourceRange.levelCount = mipLevels.GetCount();
vkimb.subresourceRange.baseArrayLayer = arrayLayers._begin;
vkimb.subresourceRange.layerCount = arrayLayers.GetCount();
// See: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples
auto UseDefaultsForOldLayout = [&vkimb, &srcStageMask]()
{
vkimb.srcAccessMask = 0;
switch (vkimb.oldLayout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
case VK_IMAGE_LAYOUT_GENERAL:
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
default:
VERUS_RT_FAIL("Unknown oldLayout");
}
};
auto UseDefaultsForNewLayout = [&vkimb, &dstStageMask, dstStageMaskXS, newLayout, tex]()
{
switch (vkimb.newLayout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
case VK_IMAGE_LAYOUT_GENERAL:
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
vkimb.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
vkimb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
dstStageMask = (ImageLayout::xsReadOnly == newLayout) ? dstStageMaskXS : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
vkimb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
default:
VERUS_RT_FAIL("Unknown newLayout");
}
if (vkimb.newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
vkimb.newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)
{
vkimb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (Format::unormD24uintS8 == tex->GetFormat())
vkimb.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
};
if (vkimb.oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && vkimb.newLayout == VK_IMAGE_LAYOUT_GENERAL)
{
UseDefaultsForOldLayout();
dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
vkimb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
else
{
UseDefaultsForOldLayout();
UseDefaultsForNewLayout();
}
vkCmdPipelineBarrier(GetVkCommandBuffer(), srcStageMask, dstStageMask, 0,
0, nullptr,
0, nullptr,
1, &vkimb);
}
void CommandBufferVulkan::BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor)
{
VERUS_QREF_RENDERER_VULKAN;
@ -114,34 +224,6 @@ void CommandBufferVulkan::EndRenderPass()
vkCmdEndRenderPass(GetVkCommandBuffer());
}
void CommandBufferVulkan::BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter)
{
auto& geoVulkan = static_cast<RGeometryVulkan>(*geo);
VkBuffer buffers[VERUS_MAX_VB];
VkDeviceSize offsets[VERUS_MAX_VB];
const int count = geoVulkan.GetVertexBufferCount();
int filteredCount = 0;
VERUS_FOR(i, count)
{
if ((bindingsFilter >> i) & 0x1)
{
VERUS_RT_ASSERT(filteredCount < VERUS_MAX_VB);
buffers[filteredCount] = geoVulkan.GetVkVertexBuffer(i);
offsets[filteredCount] = geoVulkan.GetVkVertexBufferOffset(i);
filteredCount++;
}
}
vkCmdBindVertexBuffers(GetVkCommandBuffer(), 0, filteredCount, buffers, offsets);
}
void CommandBufferVulkan::BindIndexBuffer(GeometryPtr geo)
{
auto& geoVulkan = static_cast<RGeometryVulkan>(*geo);
VkBuffer buffer = geoVulkan.GetVkIndexBuffer();
VkDeviceSize offset = geoVulkan.GetVkIndexBufferOffset();
vkCmdBindIndexBuffer(GetVkCommandBuffer(), buffer, offset, geoVulkan.Has32BitIndices() ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16);
}
void CommandBufferVulkan::BindPipeline(PipelinePtr pipe)
{
auto& pipeVulkan = static_cast<RPipelineVulkan>(*pipe);
@ -196,6 +278,34 @@ void CommandBufferVulkan::SetBlendConstants(const float* p)
vkCmdSetBlendConstants(GetVkCommandBuffer(), p);
}
void CommandBufferVulkan::BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter)
{
auto& geoVulkan = static_cast<RGeometryVulkan>(*geo);
VkBuffer buffers[VERUS_MAX_VB];
VkDeviceSize offsets[VERUS_MAX_VB];
const int count = geoVulkan.GetVertexBufferCount();
int filteredCount = 0;
VERUS_FOR(i, count)
{
if ((bindingsFilter >> i) & 0x1)
{
VERUS_RT_ASSERT(filteredCount < VERUS_MAX_VB);
buffers[filteredCount] = geoVulkan.GetVkVertexBuffer(i);
offsets[filteredCount] = geoVulkan.GetVkVertexBufferOffset(i);
filteredCount++;
}
}
vkCmdBindVertexBuffers(GetVkCommandBuffer(), 0, filteredCount, buffers, offsets);
}
void CommandBufferVulkan::BindIndexBuffer(GeometryPtr geo)
{
auto& geoVulkan = static_cast<RGeometryVulkan>(*geo);
VkBuffer buffer = geoVulkan.GetVkIndexBuffer();
VkDeviceSize offset = geoVulkan.GetVkIndexBufferOffset();
vkCmdBindIndexBuffer(GetVkCommandBuffer(), buffer, offset, geoVulkan.Has32BitIndices() ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16);
}
bool CommandBufferVulkan::BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle)
{
if (setNumber < 0)
@ -226,122 +336,6 @@ void CommandBufferVulkan::PushConstants(ShaderPtr shader, int offset, int size,
vkCmdPushConstants(GetVkCommandBuffer(), shaderVulkan.GetVkPipelineLayout(), vkssf, offset << 2, size << 2, p);
}
void CommandBufferVulkan::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, int arrayLayer)
{
auto& texVulkan = static_cast<RTextureVulkan>(*tex);
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; // Waiting for this stage to finish (TOP_OF_PIPE means wait for nothing).
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; // Which stage is waiting to start (BOTTOM_OF_PIPE means nothing is waiting).
const VkPipelineStageFlags dstStageMaskXS = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
VkImageMemoryBarrier vkimb[16];
VERUS_RT_ASSERT(mipLevels.GetCount() <= VERUS_COUNT_OF(vkimb));
int index = 0;
for (int mip : mipLevels)
{
vkimb[index].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
vkimb[index].pNext = nullptr;
vkimb[index].oldLayout = ToNativeImageLayout(oldLayout);
vkimb[index].newLayout = ToNativeImageLayout(newLayout);
vkimb[index].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkimb[index].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkimb[index].image = texVulkan.GetVkImage();
vkimb[index].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkimb[index].subresourceRange.baseMipLevel = mip;
vkimb[index].subresourceRange.levelCount = 1;
vkimb[index].subresourceRange.baseArrayLayer = arrayLayer;
vkimb[index].subresourceRange.layerCount = 1;
// See: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples
auto UseDefaultsForOldLayout = [&vkimb, index, &srcStageMask]()
{
vkimb[index].srcAccessMask = 0;
switch (vkimb[index].oldLayout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
case VK_IMAGE_LAYOUT_GENERAL:
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb[index].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
default:
VERUS_RT_FAIL("Unknown oldLayout");
}
};
auto UseDefaultsForNewLayout = [&vkimb, index, &dstStageMask, dstStageMaskXS, newLayout, tex]()
{
switch (vkimb[index].newLayout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
case VK_IMAGE_LAYOUT_GENERAL:
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
dstStageMask = (ImageLayout::xsReadOnly == newLayout) ? dstStageMaskXS : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
break;
default:
VERUS_RT_FAIL("Unknown newLayout");
}
if (vkimb[index].newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
vkimb[index].newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)
{
vkimb[index].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (Format::unormD24uintS8 == tex->GetFormat())
vkimb[index].subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
};
if (vkimb[index].oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && vkimb[index].newLayout == VK_IMAGE_LAYOUT_GENERAL)
{
UseDefaultsForOldLayout();
dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
vkimb[index].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
else
{
UseDefaultsForOldLayout();
UseDefaultsForNewLayout();
}
index++;
}
vkCmdPipelineBarrier(GetVkCommandBuffer(), srcStageMask, dstStageMask, 0,
0, nullptr,
0, nullptr,
index, vkimb);
}
void CommandBufferVulkan::Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
{
vkCmdDraw(GetVkCommandBuffer(), vertexCount, instanceCount, firstVertex, firstInstance);

View File

@ -23,23 +23,24 @@ namespace verus
virtual void Begin() override;
virtual void End() override;
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, Range arrayLayers) override;
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle,
std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor) override;
virtual void NextSubpass() override;
virtual void EndRenderPass() override;
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter) override;
virtual void BindIndexBuffer(GeometryPtr geo) override;
virtual void BindPipeline(PipelinePtr pipe) override;
virtual void SetViewport(std::initializer_list<Vector4> il, float minDepth, float maxDepth) override;
virtual void SetScissor(std::initializer_list<Vector4> il) override;
virtual void SetBlendConstants(const float* p) override;
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter) override;
virtual void BindIndexBuffer(GeometryPtr geo) override;
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle) override;
virtual void PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags) override;
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, int arrayLayer) override;
virtual void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance) override;
virtual void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance) override;
virtual void Dispatch(int groupCountX, int groupCountY, int groupCountZ) override;

View File

@ -101,12 +101,12 @@ void GeometryVulkan::CreateVertexBuffer(int count, int binding)
if (((_instBindingsMask | _dynBindingsMask) >> binding) & 0x1)
{
pRendererVulkan->CreateBuffer(vb._bufferSize * BaseRenderer::s_ringBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU,
pRendererVulkan->CreateBuffer(vb._bufferSize * BaseRenderer::s_ringBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, HostAccess::sequentialWrite,
vb._buffer, vb._vmaAllocation);
}
else
{
pRendererVulkan->CreateBuffer(vb._bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY,
pRendererVulkan->CreateBuffer(vb._bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, HostAccess::forbidden,
vb._buffer, vb._vmaAllocation);
}
}
@ -138,7 +138,7 @@ void GeometryVulkan::UpdateVertexBuffer(const void* p, int binding, PBaseCommand
auto& svb = _vStagingVertexBuffers[binding];
if (VK_NULL_HANDLE == svb._buffer)
{
pRendererVulkan->CreateBuffer(vb._bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY,
pRendererVulkan->CreateBuffer(vb._bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, HostAccess::sequentialWrite,
svb._buffer, svb._vmaAllocation);
}
@ -163,12 +163,12 @@ void GeometryVulkan::CreateIndexBuffer(int count)
if ((_dynBindingsMask >> 31) & 0x1)
{
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize * BaseRenderer::s_ringBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU,
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize * BaseRenderer::s_ringBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, HostAccess::sequentialWrite,
_indexBuffer._buffer, _indexBuffer._vmaAllocation);
}
else
{
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY,
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, HostAccess::forbidden,
_indexBuffer._buffer, _indexBuffer._vmaAllocation);
}
}
@ -194,7 +194,7 @@ void GeometryVulkan::UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB, IN
{
if (VK_NULL_HANDLE == _stagingIndexBuffer._buffer)
{
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY,
pRendererVulkan->CreateBuffer(_indexBuffer._bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, HostAccess::sequentialWrite,
_stagingIndexBuffer._buffer, _stagingIndexBuffer._vmaAllocation);
}

View File

@ -162,7 +162,11 @@ VkFormat CGI::ToNativeFormat(Format format)
case Format::unormBC1: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
case Format::unormBC2: return VK_FORMAT_BC2_UNORM_BLOCK;
case Format::unormBC3: return VK_FORMAT_BC3_UNORM_BLOCK;
case Format::unormBC4: return VK_FORMAT_BC4_UNORM_BLOCK;
case Format::unormBC5: return VK_FORMAT_BC5_UNORM_BLOCK;
case Format::unormBC7: return VK_FORMAT_BC7_UNORM_BLOCK;
case Format::snormBC4: return VK_FORMAT_BC4_SNORM_BLOCK;
case Format::snormBC5: return VK_FORMAT_BC5_SNORM_BLOCK;
case Format::srgbBC1: return VK_FORMAT_BC1_RGBA_SRGB_BLOCK;
case Format::srgbBC2: return VK_FORMAT_BC2_SRGB_BLOCK;
case Format::srgbBC3: return VK_FORMAT_BC3_SRGB_BLOCK;
@ -196,6 +200,7 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
{
VERUS_RT_ASSERT(components >= 1 && components <= 4);
int index = components - 1;
static const VkFormat floats[] =
{
VK_FORMAT_R32_SFLOAT,
@ -203,6 +208,24 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT
};
static const VkFormat halfs[] =
{
VK_FORMAT_R16_SFLOAT,
VK_FORMAT_R16G16_SFLOAT,
VK_FORMAT_R16G16_SFLOAT,
VK_FORMAT_R16G16B16A16_SFLOAT
};
static const VkFormat shorts[] =
{
VK_FORMAT_R16G16_SINT,
VK_FORMAT_R16G16_SINT,
VK_FORMAT_R16G16B16A16_SINT,
VK_FORMAT_R16G16B16A16_SINT,
VK_FORMAT_R16G16_SNORM,
VK_FORMAT_R16G16_SNORM,
VK_FORMAT_R16G16B16A16_SNORM,
VK_FORMAT_R16G16B16A16_SNORM
};
static const VkFormat bytes[] =
{
VK_FORMAT_R8G8B8A8_UINT,
@ -218,17 +241,7 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
VK_FORMAT_R8G8B8A8_SNORM,
VK_FORMAT_R8G8B8A8_SNORM
};
static const VkFormat shorts[] =
{
VK_FORMAT_R16G16_SINT,
VK_FORMAT_R16G16_SINT,
VK_FORMAT_R16G16B16A16_SINT,
VK_FORMAT_R16G16B16A16_SINT,
VK_FORMAT_R16G16_SNORM,
VK_FORMAT_R16G16_SNORM,
VK_FORMAT_R16G16B16A16_SNORM,
VK_FORMAT_R16G16B16A16_SNORM
};
switch (type)
{
case ViaType::floats:
@ -236,15 +249,10 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
return floats[index];
}
break;
case ViaType::ubytes:
case ViaType::halfs:
{
VERUS_RT_ASSERT(4 == components);
switch (usage)
{
case ViaUsage::normal: index += 8; break; // SNORM.
case ViaUsage::color: index += 4; break; // UNORM.
}
return bytes[index];
VERUS_RT_ASSERT(3 != components);
return halfs[index];
}
break;
case ViaType::shorts:
@ -252,6 +260,7 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
VERUS_RT_ASSERT(2 == components || 4 == components);
switch (usage)
{
case ViaUsage::normal:
case ViaUsage::tangent:
case ViaUsage::binormal:
index += 4; break; // SNORM.
@ -259,6 +268,21 @@ VkFormat CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
return shorts[index];
}
break;
case ViaType::ubytes:
{
VERUS_RT_ASSERT(4 == components);
switch (usage)
{
case ViaUsage::normal:
case ViaUsage::tangent:
case ViaUsage::binormal:
index += 8; break; // SNORM.
case ViaUsage::color:
index += 4; break; // UNORM.
}
return bytes[index];
}
break;
default: throw VERUS_RECOVERABLE << "ToNativeFormat(); ViaType=?";
}
}

View File

@ -85,8 +85,8 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
VkPipelineViewportStateCreateInfo viewportState = {};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = desc._multiViewport;
viewportState.scissorCount = desc._multiViewport;
viewportState.viewportCount = 1;
viewportState.scissorCount = 1;
VkPipelineRasterizationLineStateCreateInfoEXT rasterizationLineState = {};
rasterizationLineState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
@ -95,7 +95,7 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
rasterizationLineState.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
VkPipelineRasterizationStateCreateInfo rasterizationState = {};
rasterizationState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizationState.pNext = &rasterizationLineState;
rasterizationState.pNext = pRendererVulkan->IsAdvancedLineRasterizationSupported() ? &rasterizationLineState : nullptr;
rasterizationState.depthClampEnable = VK_FALSE;
rasterizationState.polygonMode = ToNativePolygonMode(desc._rasterizationState._polygonMode);
rasterizationState.cullMode = ToNativeCullMode(desc._rasterizationState._cullMode);

View File

@ -36,9 +36,6 @@ CSZ RendererVulkan::s_requiredValidationLayers[] =
CSZ RendererVulkan::s_requiredDeviceExtensions[] =
{
VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
@ -76,11 +73,11 @@ void RendererVulkan::Init()
CreateDevice();
VmaAllocatorCreateInfo vmaaci = {};
vmaaci.flags = VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT | VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
vmaaci.physicalDevice = _physicalDevice;
vmaaci.device = _device;
vmaaci.pAllocationCallbacks = GetAllocator();
vmaaci.frameInUseCount = s_ringBufferSize;
vmaaci.instance = _instance;
vmaaci.vulkanApiVersion = s_apiVersion;
if (VK_SUCCESS != (res = vmaCreateAllocator(&vmaaci, &_vmaAllocator)))
throw VERUS_RUNTIME_ERROR << "vmaCreateAllocator(); res=" << res;
@ -265,7 +262,7 @@ void RendererVulkan::CreateInstance()
vkai.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
vkai.pEngineName = "Verus";
vkai.engineVersion = VK_MAKE_VERSION(major, minor, patch);
vkai.apiVersion = VK_API_VERSION_1_1;
vkai.apiVersion = s_apiVersion;
VkInstanceCreateInfo vkici = {};
vkici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
@ -410,8 +407,18 @@ void RendererVulkan::CreateDevice()
VkPhysicalDeviceLineRasterizationFeaturesEXT lineRasterizationFeatures = {};
lineRasterizationFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT;
lineRasterizationFeatures.bresenhamLines = VK_TRUE;
lineRasterizationFeatures.smoothLines = VK_TRUE;
VkPhysicalDeviceFeatures2 vkpdf2 = {};
vkpdf2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
vkpdf2.pNext = &lineRasterizationFeatures;
vkGetPhysicalDeviceFeatures2(_physicalDevice, &vkpdf2);
lineRasterizationFeatures.stippledRectangularLines = VK_FALSE;
lineRasterizationFeatures.stippledBresenhamLines = VK_FALSE;
lineRasterizationFeatures.stippledSmoothLines = VK_FALSE;
_advancedLineRasterization =
lineRasterizationFeatures.rectangularLines &&
lineRasterizationFeatures.bresenhamLines &&
lineRasterizationFeatures.smoothLines;
_queueFamilyIndices = FindQueueFamilyIndices(_physicalDevice);
VERUS_RT_ASSERT(_queueFamilyIndices.IsComplete());
@ -429,14 +436,15 @@ void RendererVulkan::CreateDevice()
vDeviceQueueCreateInfos.push_back(vkdqci);
}
// Check https://vulkan.gpuinfo.org/ for device coverage:
VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
physicalDeviceFeatures.geometryShader = VK_TRUE;
physicalDeviceFeatures.tessellationShader = settings._gpuTessellation ? VK_TRUE : VK_FALSE;
physicalDeviceFeatures.fillModeNonSolid = VK_TRUE;
physicalDeviceFeatures.multiViewport = VK_TRUE;
physicalDeviceFeatures.samplerAnisotropy = VK_TRUE;
physicalDeviceFeatures.shaderImageGatherExtended = VK_TRUE;
physicalDeviceFeatures.shaderClipDistance = VK_TRUE;
physicalDeviceFeatures.fillModeNonSolid = VK_TRUE; // 79%
physicalDeviceFeatures.geometryShader = VK_TRUE; // 80%
physicalDeviceFeatures.independentBlend = VK_TRUE; // 99%
physicalDeviceFeatures.samplerAnisotropy = VK_TRUE; // 90%
physicalDeviceFeatures.shaderClipDistance = VK_TRUE; // 85%
physicalDeviceFeatures.shaderImageGatherExtended = VK_TRUE; // 94%
physicalDeviceFeatures.tessellationShader = settings._gpuTessellation ? VK_TRUE : VK_FALSE; // 81%
VkDeviceCreateInfo vkdci = {};
vkdci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
@ -1286,7 +1294,7 @@ RendererVulkan::RcFramebuffer RendererVulkan::GetFramebuffer(FBHandle handle) co
return _vFramebuffers[handle.Get()];
}
void RendererVulkan::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaMemoryUsage vmaUsage, VkBuffer& buffer, VmaAllocation& vmaAllocation)
void RendererVulkan::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, HostAccess hostAccess, VkBuffer& buffer, VmaAllocation& vmaAllocation)
{
VkResult res = VK_SUCCESS;
@ -1295,7 +1303,12 @@ void RendererVulkan::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, V
vkbci.size = size;
vkbci.usage = usage;
VmaAllocationCreateInfo vmaaci = {};
vmaaci.usage = vmaUsage;
vmaaci.usage = VMA_MEMORY_USAGE_AUTO;
switch (hostAccess)
{
case HostAccess::sequentialWrite: vmaaci.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; break;
case HostAccess::random: vmaaci.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; break;
}
if (VK_SUCCESS != (res = vmaCreateBuffer(_vmaAllocator, &vkbci, &vmaaci, &buffer, &vmaAllocation, nullptr)))
throw VERUS_RECOVERABLE << "vmaCreateBuffer(); res=" << res;
}
@ -1313,12 +1326,17 @@ void RendererVulkan::CopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDevice
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &region);
}
void RendererVulkan::CreateImage(const VkImageCreateInfo* pImageCreateInfo, VmaMemoryUsage vmaUsage, VkImage& image, VmaAllocation& vmaAllocation)
void RendererVulkan::CreateImage(const VkImageCreateInfo* pImageCreateInfo, HostAccess hostAccess, VkImage& image, VmaAllocation& vmaAllocation)
{
VkResult res = VK_SUCCESS;
VmaAllocationCreateInfo vmaaci = {};
vmaaci.usage = vmaUsage;
vmaaci.usage = VMA_MEMORY_USAGE_AUTO;
switch (hostAccess)
{
case HostAccess::sequentialWrite: vmaaci.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; break;
case HostAccess::random: vmaaci.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; break;
}
if (VK_SUCCESS != (res = vmaCreateImage(_vmaAllocator, pImageCreateInfo, &vmaaci, &image, &vmaAllocation, nullptr)))
throw VERUS_RECOVERABLE << "vmaCreateImage(); res=" << res;
}

View File

@ -5,6 +5,13 @@ namespace verus
{
namespace CGI
{
enum class HostAccess : int
{
forbidden,
sequentialWrite,
random
};
struct BaseShaderInclude
{
virtual void Open(CSZ filename, void** ppData, UINT32* pBytes) = 0;
@ -52,6 +59,8 @@ namespace verus
Vector<VkPresentModeKHR> _vSurfacePresentModes;
};
static const uint32_t s_apiVersion = VK_API_VERSION_1_1;
static CSZ s_requiredValidationLayers[];
static CSZ s_requiredDeviceExtensions[];
@ -79,6 +88,7 @@ namespace verus
Vector<VkSampler> _vSamplers;
Vector<VkRenderPass> _vRenderPasses;
Vector<Framebuffer> _vFramebuffers;
bool _advancedLineRasterization = false;
public:
RendererVulkan();
@ -137,14 +147,15 @@ namespace verus
// Which graphics API?
virtual Gapi GetGapi() override { return Gapi::vulkan; }
// Frame cycle:
// <FrameCycle>
virtual void BeginFrame(bool present) override;
virtual void EndFrame(bool present) override;
virtual void Present() override;
virtual void Sync(bool present) override;
virtual void WaitIdle() override;
// </FrameCycle>
// Resources:
// <Resources>
virtual PBaseCommandBuffer InsertCommandBuffer() override;
virtual PBaseGeometry InsertGeometry() override;
virtual PBasePipeline InsertPipeline() override;
@ -166,10 +177,12 @@ namespace verus
int GetNextFramebufferIndex() const;
VkRenderPass GetRenderPass(RPHandle handle) const;
RcFramebuffer GetFramebuffer(FBHandle handle) const;
// </Resources>
void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaMemoryUsage vmaUsage, VkBuffer& buffer, VmaAllocation& vmaAllocation);
// <BufferAndImage>
void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, HostAccess hostAccess, VkBuffer& buffer, VmaAllocation& vmaAllocation);
void CopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size, PBaseCommandBuffer pCB = nullptr);
void CreateImage(const VkImageCreateInfo* pImageCreateInfo, VmaMemoryUsage vmaUsage, VkImage& image, VmaAllocation& vmaAllocation);
void CreateImage(const VkImageCreateInfo* pImageCreateInfo, HostAccess hostAccess, VkImage& image, VmaAllocation& vmaAllocation);
void CopyImage(
VkImage srcImage, uint32_t srcMipLevel, uint32_t srcArrayLayer,
VkImage dstImage, uint32_t dstMipLevel, uint32_t dstArrayLayer,
@ -185,8 +198,11 @@ namespace verus
uint32_t width, uint32_t height,
VkBuffer buffer,
PBaseCommandBuffer pCB = nullptr);
// </BufferAndImage>
virtual void UpdateUtilization() override;
bool IsAdvancedLineRasterizationSupported() const { return _advancedLineRasterization; }
};
VERUS_TYPEDEFS(RendererVulkan);
}

View File

@ -245,7 +245,7 @@ void ShaderVulkan::CreateDescriptorSet(int setNumber, const void* pSrc, int size
if (capacity > 0)
{
const VkDeviceSize bufferSize = dsd._capacityInBytes * BaseRenderer::s_ringBufferSize;
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU,
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, HostAccess::sequentialWrite,
dsd._buffer, dsd._vmaAllocation);
}
@ -405,7 +405,7 @@ void ShaderVulkan::CreatePipelineLayout()
}
}
CSHandle ShaderVulkan::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips)
CSHandle ShaderVulkan::BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMipLevels, const int* pArrayLayers)
{
VERUS_QREF_RENDERER_VULKAN;
VkResult res = VK_SUCCESS;
@ -451,11 +451,12 @@ CSHandle ShaderVulkan::BindDescriptorSetTextures(int setNumber, std::initializer
for (const auto& x : il)
{
auto& texVulkan = static_cast<RTextureVulkan>(*x);
const int mip = pMips ? pMips[index] : 0;
const int mipLevel = pMipLevels ? pMipLevels[index] : 0;
const int arrayLayer = pArrayLayers ? pArrayLayers[index] : 0;
VkDescriptorImageInfo vkdii = {};
if (Sampler::storage == dsd._vSamplers[index])
{
vkdii.imageView = texVulkan.GetStorageVkImageView(mip);
vkdii.imageView = texVulkan.GetStorageVkImageView(mipLevel, arrayLayer);
vkdii.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
}
else if (Sampler::shadow == dsd._vSamplers[index])

View File

@ -59,7 +59,7 @@ namespace verus
virtual void CreateDescriptorSet(int setNumber, const void* pSrc, int size, int capacity, std::initializer_list<Sampler> il, ShaderStageFlags stageFlags) override;
virtual void CreatePipelineLayout() override;
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips) override;
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMipLevels, const int* pArrayLayers) override;
virtual void FreeDescriptorSet(CSHandle& complexSetHandle) override;
virtual void BeginBindDescriptors() override;

View File

@ -21,24 +21,28 @@ void TextureVulkan::Init(RcTextureDesc desc)
VERUS_QREF_RENDERER_VULKAN;
VkResult res = VK_SUCCESS;
_initAtFrame = renderer.GetFrameCount();
// Variables:
_size = Vector4(
float(desc._width),
float(desc._height),
1.f / desc._width,
1.f / desc._height);
_desc = desc;
_desc._mipLevels = desc._mipLevels ? desc._mipLevels : Math::ComputeMipLevels(desc._width, desc._height, desc._depth);
_initAtFrame = renderer.GetFrameCount();
if (desc._flags & TextureDesc::Flags::anyShaderResource)
_mainLayout = ImageLayout::xsReadOnly;
_bytesPerPixel = FormatToBytesPerPixel(desc._format);
_desc._mipLevels = _desc._mipLevels ? _desc._mipLevels : Math::ComputeMipLevels(_desc._width, _desc._height, _desc._depth);
const bool renderTarget = (_desc._flags & TextureDesc::Flags::colorAttachment);
const bool depthFormat = IsDepthFormat(desc._format);
const bool depthFormat = IsDepthFormat(_desc._format);
const bool depthSampled = _desc._flags & (TextureDesc::Flags::depthSampledR | TextureDesc::Flags::depthSampledW);
const bool cubeMap = (_desc._flags & TextureDesc::Flags::cubeMap);
if (cubeMap)
_desc._arrayLayers *= +CubeMapFace::count;
if (_desc._flags & TextureDesc::Flags::anyShaderResource)
_mainLayout = ImageLayout::xsReadOnly;
const bool arrayTexture = (_desc._arrayLayers > 1) || (_desc._flags & TextureDesc::Flags::forceArrayTexture);
// Create:
VkImageCreateInfo vkici = {};
vkici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
vkici.imageType = (_desc._depth > 1) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
@ -69,10 +73,12 @@ void TextureVulkan::Init(RcTextureDesc desc)
vkici.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
if (cubeMap)
vkici.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
pRendererVulkan->CreateImage(&vkici, VMA_MEMORY_USAGE_GPU_ONLY, _image, _vmaAllocation);
pRendererVulkan->CreateImage(&vkici, HostAccess::forbidden, _image, _vmaAllocation);
// Optional mipmap:
if (_desc._flags & TextureDesc::Flags::generateMips)
{
VERUS_RT_ASSERT(_desc._mipLevels > 1);
// Create storage image for compute shader's output. No need to have the first mip level.
VkImageCreateInfo vkiciStorage = vkici;
vkiciStorage.extent.width = Math::Max(1, _desc._width >> 1);
@ -85,27 +91,37 @@ void TextureVulkan::Init(RcTextureDesc desc)
case VK_FORMAT_R8G8B8A8_SRGB: vkiciStorage.format = VK_FORMAT_R8G8B8A8_UNORM; break;
case VK_FORMAT_B8G8R8A8_SRGB: vkiciStorage.format = VK_FORMAT_B8G8R8A8_UNORM; break;
}
pRendererVulkan->CreateImage(&vkiciStorage, VMA_MEMORY_USAGE_GPU_ONLY, _storageImage, _storageVmaAllocation);
pRendererVulkan->CreateImage(&vkiciStorage, HostAccess::forbidden, _storageImage, _storageVmaAllocation);
_vCshGenerateMips.reserve(Math::DivideByMultiple<int>(_desc._mipLevels, 4));
_vStorageImageViews.resize(vkiciStorage.mipLevels);
VERUS_U_FOR(mip, vkiciStorage.mipLevels)
_vStorageImageViews.resize(vkiciStorage.mipLevels * _desc._arrayLayers);
VkImageViewCreateInfo vkivci = {};
vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
vkivci.image = _storageImage;
vkivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
vkivci.format = vkiciStorage.format;
VERUS_FOR(layer, _desc._arrayLayers)
{
VkImageViewCreateInfo vkivci = {};
vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
vkivci.image = _storageImage;
vkivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
vkivci.format = vkiciStorage.format;
vkivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkivci.subresourceRange.baseMipLevel = mip;
vkivci.subresourceRange.levelCount = 1;
vkivci.subresourceRange.baseArrayLayer = 0;
vkivci.subresourceRange.layerCount = 1;
if (VK_SUCCESS != (res = vkCreateImageView(pRendererVulkan->GetVkDevice(), &vkivci, pRendererVulkan->GetAllocator(), &_vStorageImageViews[mip])))
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(); res=" << res;
VERUS_U_FOR(mip, vkiciStorage.mipLevels)
{
vkivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkivci.subresourceRange.baseMipLevel = mip;
vkivci.subresourceRange.levelCount = 1;
vkivci.subresourceRange.baseArrayLayer = layer;
vkivci.subresourceRange.layerCount = 1;
if (cubeMap)
{
const int cubeIndex = layer / +CubeMapFace::count;
const int faceIndex = layer % +CubeMapFace::count;
vkivci.subresourceRange.baseArrayLayer = (cubeIndex * +CubeMapFace::count) + ToNativeCubeMapFace(static_cast<CubeMapFace>(faceIndex));
}
if (VK_SUCCESS != (res = vkCreateImageView(pRendererVulkan->GetVkDevice(), &vkivci, pRendererVulkan->GetAllocator(), &_vStorageImageViews[mip + layer * vkiciStorage.mipLevels])))
throw VERUS_RUNTIME_ERROR << "vkCreateImageView(); res=" << res;
}
}
}
// Optional readback buffer:
if (_desc._readbackMip != SHRT_MAX)
{
if (_desc._readbackMip < 0)
@ -116,18 +132,19 @@ void TextureVulkan::Init(RcTextureDesc desc)
_vReadbackBuffers.resize(BaseRenderer::s_ringBufferSize);
for (auto& x : _vReadbackBuffers)
{
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU,
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, HostAccess::random,
x._buffer, x._vmaAllocation);
}
}
// Create views:
VkImageViewCreateInfo vkivci = {};
vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
vkivci.image = _image;
vkivci.viewType = (_desc._depth > 1) ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D;
if (cubeMap)
vkivci.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
else if (_desc._arrayLayers > 1 || (_desc._flags & TextureDesc::Flags::forceArrayTexture))
else if (arrayTexture)
vkivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
vkivci.format = vkici.format;
vkivci.subresourceRange.aspectMask = depthFormat ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
@ -158,22 +175,19 @@ void TextureVulkan::Init(RcTextureDesc desc)
}
}
// Custom sampler:
if (_desc._pSamplerDesc)
CreateSampler();
// Define:
if (renderTarget)
{
CommandBufferVulkan commandBuffer;
commandBuffer.InitOneTimeSubmit();
if (cubeMap)
{
VERUS_FOR(i, +CubeMapFace::count)
commandBuffer.PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::undefined, ImageLayout::fsReadOnly, 0, i);
}
commandBuffer.PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::undefined, ImageLayout::fsReadOnly, 0, Range(0, +CubeMapFace::count));
else
{
commandBuffer.PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::undefined, ImageLayout::fsReadOnly, 0, 0);
}
commandBuffer.DoneOneTimeSubmit();
}
if (depthFormat)
@ -233,7 +247,7 @@ void TextureVulkan::UpdateSubresource(const void* p, int mipLevel, int arrayLaye
auto& sb = _vStagingBuffers[sbIndex];
if (VK_NULL_HANDLE == sb._buffer)
{
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY,
pRendererVulkan->CreateBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, HostAccess::sequentialWrite,
sb._buffer, sb._vmaAllocation);
}
@ -297,6 +311,9 @@ bool TextureVulkan::ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCo
void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
{
VERUS_RT_ASSERT(_desc._flags & TextureDesc::Flags::generateMips);
if (_desc._flags & TextureDesc::Flags::cubeMap)
return GenerateCubeMapMips(pCB);
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_VULKAN;
@ -351,10 +368,10 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
if (createComplexSets)
{
int mips[5] = {}; // For input texture (always mip 0) and 4 storage mips.
VERUS_FOR(mip, dispatchMipCount)
mips[mip + 1] = srcMip + mip;
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex }, mips);
int mipLevels[5] = {}; // For input texture (always mip 0) and 4 storage mips.
VERUS_FOR(i, dispatchMipCount)
mipLevels[i + 1] = srcMip + i;
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex }, mipLevels);
_vCshGenerateMips.push_back(complexSetHandle);
pCB->BindDescriptors(shader, 0, complexSetHandle);
}
@ -370,12 +387,11 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
std::swap(_image, _storageImage);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::general, ImageLayout::transferSrc, Range(0, dispatchMipCount).OffsetBy(srcMip));
std::swap(_image, _storageImage);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, ImageLayout::transferDst, Range(0, dispatchMipCount).OffsetBy(srcMip + 1));
}
VERUS_FOR(mip, dispatchMipCount)
VERUS_FOR(i, dispatchMipCount)
{
const int dstMip = srcMip + 1 + mip;
const int dstMip = srcMip + 1 + i;
const int w = Math::Max(1, _desc._width >> dstMip);
const int h = Math::Max(1, _desc._height >> dstMip);
pRendererVulkan->CopyImage(
@ -389,7 +405,6 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
std::swap(_image, _storageImage);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferSrc, ImageLayout::general, Range(0, dispatchMipCount).OffsetBy(srcMip));
std::swap(_image, _storageImage);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferDst, ImageLayout::xsReadOnly, Range(0, dispatchMipCount).OffsetBy(srcMip + 1));
}
@ -406,6 +421,116 @@ void TextureVulkan::GenerateMips(PBaseCommandBuffer pCB)
Schedule(0);
}
void TextureVulkan::GenerateCubeMapMips(PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_VULKAN;
if (!pCB)
pCB = renderer.GetCommandBuffer().Get();
auto shader = renderer.GetShaderGenerateCubeMapMips();
auto& ub = renderer.GetUbGenerateCubeMapMips();
auto tex = TexturePtr::From(this);
const int maxMipLevel = _desc._mipLevels - 1;
if (!_definedStorage)
{
_definedStorage = true;
std::swap(_image, _storageImage);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::undefined, ImageLayout::general, Range(0, maxMipLevel), Range(0, +CubeMapFace::count));
std::swap(_image, _storageImage);
}
// Change layout for sampling in compute shader (assume all layers have the same layout):
const ImageLayout firstMipLayout = GetSubresourceMainLayout(0, 0);
const ImageLayout otherMipsLayout = GetSubresourceMainLayout(1, 0);
if (firstMipLayout != ImageLayout::xsReadOnly)
pCB->PipelineImageMemoryBarrier(tex, firstMipLayout, ImageLayout::xsReadOnly, 0, Range(0, +CubeMapFace::count));
if (otherMipsLayout != ImageLayout::xsReadOnly)
pCB->PipelineImageMemoryBarrier(tex, otherMipsLayout, ImageLayout::xsReadOnly, Range(1, _desc._mipLevels), Range(0, +CubeMapFace::count));
VERUS_FOR(layer, +CubeMapFace::count)
{
VERUS_FOR(mip, _desc._mipLevels)
MarkSubresourceDefined(mip, layer);
}
pCB->BindPipeline(renderer.GetPipelineGenerateCubeMapMips());
shader->BeginBindDescriptors();
const bool createComplexSets = _vCshGenerateMips.empty();
int dispatchIndex = 0;
for (int srcMip = 0; srcMip < maxMipLevel;)
{
const int srcWidth = Math::Max(1, _desc._width >> srcMip);
const int srcHeight = Math::Max(1, _desc._height >> srcMip);
const int dstWidth = Math::Max(1, srcWidth >> 1);
const int dstHeight = Math::Max(1, srcHeight >> 1);
ub._srcMipLevel = srcMip;
ub._srgb = IsSRGBFormat(_desc._format);
ub._dstTexelSize.x = 1.f / dstWidth;
ub._dstTexelSize.y = 1.f / dstHeight;
if (createComplexSets)
{
int mipLevels[7] = {};
VERUS_FOR(i, +CubeMapFace::count)
mipLevels[i + 1] = srcMip;
int arrayLayers[7] = {};
VERUS_FOR(i, +CubeMapFace::count)
arrayLayers[i + 1] = ToNativeCubeMapFace(static_cast<CubeMapFace>(i));
const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex, tex, tex }, mipLevels, arrayLayers);
_vCshGenerateMips.push_back(complexSetHandle);
pCB->BindDescriptors(shader, 0, complexSetHandle);
}
else
{
pCB->BindDescriptors(shader, 0, _vCshGenerateMips[dispatchIndex]);
}
pCB->Dispatch(Math::DivideByMultiple(dstWidth, 8), Math::DivideByMultiple(dstHeight, 8));
// Change layout for upcoming CopyImage():
{
std::swap(_image, _storageImage);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::general, ImageLayout::transferSrc, srcMip, Range(0, +CubeMapFace::count));
std::swap(_image, _storageImage);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, ImageLayout::transferDst, srcMip + 1, Range(0, +CubeMapFace::count));
}
VERUS_FOR(layer, +CubeMapFace::count)
{
const int storageMip = srcMip;
const int dstMip = srcMip + 1;
const int w = Math::Max(1, _desc._width >> dstMip);
const int h = Math::Max(1, _desc._height >> dstMip);
pRendererVulkan->CopyImage(
_storageImage, storageMip, layer,
_image, dstMip, layer,
w, h,
pCB);
}
// Change layout for next Dispatch():
{
std::swap(_image, _storageImage);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferSrc, ImageLayout::general, srcMip, Range(0, +CubeMapFace::count));
std::swap(_image, _storageImage);
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::transferDst, ImageLayout::xsReadOnly, srcMip + 1, Range(0, +CubeMapFace::count));
}
srcMip++;
dispatchIndex++;
}
shader->EndBindDescriptors();
// Revert to main layout:
const ImageLayout finalMipLayout = GetSubresourceMainLayout(0, 0);
if (finalMipLayout != ImageLayout::xsReadOnly)
pCB->PipelineImageMemoryBarrier(tex, ImageLayout::xsReadOnly, finalMipLayout, Range(0, _desc._mipLevels), Range(0, +CubeMapFace::count));
Schedule(0);
}
Continue TextureVulkan::Scheduled_Update()
{
if (!IsScheduledAllowed())

View File

@ -38,6 +38,7 @@ namespace verus
virtual bool ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) override;
virtual void GenerateMips(PBaseCommandBuffer pCB) override;
void GenerateCubeMapMips(PBaseCommandBuffer pCB);
virtual Continue Scheduled_Update() override;
@ -50,7 +51,7 @@ namespace verus
VkImage GetVkImage() const { return _image; }
VkImageView GetVkImageView() const { return _imageView; }
VkImageView GetVkImageViewForFramebuffer(CubeMapFace face) const;
VkImageView GetStorageVkImageView(int mip) const { return _vStorageImageViews[mip]; }
VkImageView GetStorageVkImageView(int mipLevel, int arrayLayer) const { return _vStorageImageViews[mipLevel + arrayLayer * (_desc._mipLevels - 1)]; }
VkSampler GetVkSampler() const { return _sampler; }
ImageLayout GetSubresourceMainLayout(int mipLevel, int arrayLayer) const;
void MarkSubresourceDefined(int mipLevel, int arrayLayer);

File diff suppressed because it is too large Load Diff

View File

@ -1,40 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="VmaRawList&lt;*&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<LinkedListItems>
<Size>m_Count</Size>
<HeadPointer>m_pFront</HeadPointer>
<NextPointer>pNext</NextPointer>
<ValueNode>Value</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="VmaRawList&lt;*&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<LinkedListItems>
<Size>m_Count</Size>
<HeadPointer>m_pFront</HeadPointer>
<NextPointer>pNext</NextPointer>
<ValueNode>Value</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="VmaList&lt;*&gt;">
<DisplayString>{{ Count={m_RawList.m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_RawList.m_Count</Item>
<LinkedListItems>
<Size>m_RawList.m_Count</Size>
<HeadPointer>m_RawList.m_pFront</HeadPointer>
<NextPointer>pNext</NextPointer>
<ValueNode>Value</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="VmaList&lt;*&gt;">
<DisplayString>{{ Count={m_RawList.m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_RawList.m_Count</Item>
<LinkedListItems>
<Size>m_RawList.m_Count</Size>
<HeadPointer>m_RawList.m_pFront</HeadPointer>
<NextPointer>pNext</NextPointer>
<ValueNode>Value</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="VmaVector&lt;*&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<Item Name="[Capacity]">m_Capacity</Item>
<ArrayItems>
<Size>m_Count</Size>
<ValuePointer>m_pArray</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="VmaVector&lt;*&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<Item Name="[Capacity]">m_Capacity</Item>
<ArrayItems>
<Size>m_Count</Size>
<ValuePointer>m_pArray</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!--
Due to custom way of accesing next items in
VmaIntrusiveLinkedList via methods in provided type traits,
every specialization must be manually added with
custom <NextPointer> field describing proper way of iterating the list.
-->
<Type Name="VmaIntrusiveLinkedList&lt;VmaDedicatedAllocationListItemTraits&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<LinkedListItems>
<Size>m_Count</Size>
<HeadPointer>m_Front</HeadPointer>
<NextPointer>m_DedicatedAllocation.m_Next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="VmaIntrusiveLinkedList&lt;VmaPoolListItemTraits&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<LinkedListItems>
<Size>m_Count</Size>
<HeadPointer>m_Front</HeadPointer>
<NextPointer>m_NextPool</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
</AutoVisualizer>

View File

@ -15,7 +15,7 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{5A1A3E76-7F69-48B6-B1E3-F6BB281B7E73}</ProjectGuid>
<RootNamespace>TextureTool</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

View File

@ -4,86 +4,228 @@
using namespace verus;
void DeleteMipmap(CWSZ pathname);
CMP_BOOL CompressionCallback(CMP_FLOAT progress, CMP_DWORD_PTR pUser1, CMP_DWORD_PTR pUser2)
class TextureTool
{
std::wcout << _T("ProcessTexture progress = ") << static_cast<int>(progress) << _T("%") << std::endl;
struct CursorGuard
{
CONSOLE_CURSOR_INFO _defaultCursorInfo;
CursorGuard()
{
GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &_defaultCursorInfo);
CONSOLE_CURSOR_INFO info = {};
info.dwSize = 100;
info.bVisible = FALSE;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
}
~CursorGuard()
{
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &_defaultCursorInfo);
}
};
enum class TexMode : int
{
automatic,
color,
nonColor,
a,
n,
x,
all
};
String _pathname;
TexMode _texMode = TexMode::automatic;
bool _asIs = false;
bool _edgePaddingUsingAlpha = false;
bool _edgePaddingUsingFaces = false;
bool _deleteMip = false;
static CMP_BOOL FeedbackProc(CMP_FLOAT progress, CMP_DWORD_PTR pUser1, CMP_DWORD_PTR pUser2);
public:
TextureTool();
~TextureTool();
void Main(VERUS_MAIN_DEFAULT_ARGS);
void ParseCommandLine(VERUS_MAIN_DEFAULT_ARGS);
void PrintUsage();
void ConvertTexture(TexMode currentTexMode);
void ComputeEdgePadding();
};
CMP_BOOL TextureTool::FeedbackProc(CMP_FLOAT progress, CMP_DWORD_PTR pUser1, CMP_DWORD_PTR pUser2)
{
const int edge = static_cast<int>(progress * 0.5f + 0.5f);
std::wcout << _T("\rCompressing [");
VERUS_FOR(i, 50)
{
if (i < edge)
std::wcout << _T("=");
else
std::wcout << _T(" ");
}
std::wcout << _T("] ") << std::setw(3) << static_cast<int>(progress + 0.5f) << _T("%") << std::flush;
return false;
}
void Run()
TextureTool::TextureTool()
{
int argCount = 0;
LPWSTR* argArray = CommandLineToArgvW(GetCommandLine(), &argCount);
WideString pathnameW;
std::wcout << _T("TextureTool") << std::endl;
std::wcout << _T("Copyright (c) 2016-2021 Dmitry Maluev") << std::endl;
if (argCount < 2)
{
std::wcout << _T("Enter file name: ");
std::wcin >> pathnameW;
}
else
pathnameW = argArray[argCount - 1];
String pathname = Str::WideToUtf8(pathnameW);
bool argDeleteMipmap = false;
bool argFade = false;
bool argNormalMap = false;
bool argColorData = true;
VERUS_FOR(i, argCount)
{
if (!_wcsicmp(argArray[i], L"--delete-mipmap"))
argDeleteMipmap = true;
if (!_wcsicmp(argArray[i], L"--fade"))
argFade = true;
if (!_wcsicmp(argArray[i], L"--normal-map"))
argNormalMap = true;
if (!_wcsicmp(argArray[i], L"--non-color-data"))
argColorData = false;
}
LocalFree(argArray);
}
if (argDeleteMipmap)
TextureTool::~TextureTool()
{
}
void TextureTool::Main(VERUS_MAIN_DEFAULT_ARGS)
{
if (argc <= 1)
{
DeleteMipmap(_C(pathnameW));
PrintUsage();
return;
}
ParseCommandLine(argc, argv);
if (_edgePaddingUsingAlpha || _edgePaddingUsingFaces)
{
ComputeEdgePadding();
}
else if (_deleteMip)
{
}
else
{
std::wcout << _T("Mode: ");
switch (_texMode)
{
case TexMode::automatic: std::wcout << _T("automatic"); break;
case TexMode::color: std::wcout << _T("color"); break;
case TexMode::nonColor: std::wcout << _T("non-color"); break;
case TexMode::a: std::wcout << _T("a"); break;
case TexMode::n: std::wcout << _T("n"); break;
case TexMode::x: std::wcout << _T("x"); break;
case TexMode::all: std::wcout << _T("all"); break;
}
std::wcout << std::endl;
if (TexMode::automatic == _texMode)
{
const String ext = Str::GetExtension(_C(_pathname));
if (Str::EndsWith(_C(_pathname), _C(".X." + ext)))
ConvertTexture(TexMode::nonColor);
else
ConvertTexture(TexMode::color);
}
else if (TexMode::all == _texMode)
{
const String pathname = _pathname;
const String ext = Str::GetExtension(_C(pathname));
ConvertTexture(TexMode::a);
_pathname = pathname;
Str::ReplaceExtension(_pathname, ".N.png");
ConvertTexture(TexMode::n);
_pathname = pathname;
Str::ReplaceExtension(_pathname, _C(".X." + ext));
ConvertTexture(TexMode::x);
}
else
{
ConvertTexture(_texMode);
}
}
}
void TextureTool::ParseCommandLine(VERUS_MAIN_DEFAULT_ARGS)
{
VERUS_FOR(i, argc)
{
if (!strcmp(argv[i], "--tex-auto"))
_texMode = TexMode::automatic;
else if (!strcmp(argv[i], "--tex-color"))
_texMode = TexMode::color;
else if (!strcmp(argv[i], "--tex-non-color"))
_texMode = TexMode::nonColor;
else if (!strcmp(argv[i], "--tex-a"))
_texMode = TexMode::a;
else if (!strcmp(argv[i], "--tex-n"))
_texMode = TexMode::n;
else if (!strcmp(argv[i], "--tex-x"))
_texMode = TexMode::x;
else if (!strcmp(argv[i], "--tex-all"))
_texMode = TexMode::all;
else if (!strcmp(argv[i], "--as-is"))
_asIs = true;
else if (!strcmp(argv[i], "--edge-padding-using-alpha") || !strcmp(argv[i], "-epua"))
_edgePaddingUsingAlpha = true;
else if (!strcmp(argv[i], "--edge-padding-using-faces") || !strcmp(argv[i], "-epuf"))
_edgePaddingUsingFaces = true;
else if (!strcmp(argv[i], "--delete-mip"))
_deleteMip = true;
else if (i > 0 && i < argc - 1)
{
std::wcout << _T("WARNING: Unknown argument ") << Str::Utf8ToWide(argv[i]) << std::endl;
std::cin.ignore();
}
}
#ifdef _WIN32
int argCount = 0;
LPWSTR* argArray = CommandLineToArgvW(GetCommandLine(), &argCount);
_pathname = Str::WideToUtf8(argArray[argCount - 1]);
LocalFree(argArray);
#endif
}
void TextureTool::PrintUsage()
{
std::wcout << _T("Usage: TextureTool [options] <file>") << std::endl;
std::wcout << std::endl;
std::wcout << _T("TextureTool 2. Powered by Compressonator.") << std::endl;
std::wcout << _T("Preferred output formats are DDS/BC5 for normal map and DDS/BC7 for everything else.") << std::endl;
std::wcout << _T("Create a batch file with similar content to convert multiple files:") << std::endl;
std::wcout << _T(" for %%f in (*.*) do TextureTool %%f") << std::endl;
std::wcout << std::endl;
std::wcout << _T("Options:") << std::endl;
std::wcout << _T(" --tex-auto Use filename to select between color and non-color data (default).") << std::endl;
std::wcout << _T(" --tex-color Convert texture with color (sRGB).") << std::endl;
std::wcout << _T(" --tex-non-color Convert texture with non-color data (linear).") << std::endl;
std::wcout << _T(" --tex-a Convert {Albedo.rgb, Alpha} texture.") << std::endl;
std::wcout << _T(" --tex-n Convert Normal Map texture.") << std::endl;
std::wcout << _T(" --tex-x Convert {Occlusion, Roughness, Metallic, Emission} texture.") << std::endl;
std::wcout << _T(" --tex-all Convert all textures.") << std::endl;
std::wcout << _T(" --as-is Don't use block compression.") << std::endl;
std::wcout << _T(" --edge-padding-using-alpha, -epua Add edge padding to an image with alpha.") << std::endl;
std::wcout << _T(" --edge-padding-using-faces, -epuf Add edge padding to an image, take alpha from Faces.png.") << std::endl;
std::wcout << _T(" --delete-mip Delete topmost mip level.") << std::endl;
}
void TextureTool::ConvertTexture(TexMode currentTexMode)
{
std::wcout << _T("Converting texture: ");
switch (currentTexMode)
{
case TexMode::color: std::wcout << _T("COLOR"); break;
case TexMode::nonColor: std::wcout << _T("NON-COLOR"); break;
case TexMode::a: std::wcout << _T("A (Albedo, Alpha)"); break;
case TexMode::n: std::wcout << _T("N (Normal Map)"); break;
case TexMode::x: std::wcout << _T("X (Occlusion, Roughness, Metallic, Emission)"); break;
default:
std::wcerr << _T("ERROR: Unknown mode.") << std::endl;
throw std::exception();
}
std::wcout << std::endl;
std::wcout << _T("Location: ") << Str::Utf8ToWide(_pathname) << std::endl;
CMP_ERROR cmpError = CMP_OK;
CMP_MipSet srcMipSet = {};
cmpError = CMP_LoadTexture(_C(pathname), &srcMipSet);
cmpError = CMP_LoadTexture(_C(_pathname), &srcMipSet);
if (CMP_OK != cmpError)
{
std::wcerr << _T("ERROR: CMP_LoadTexture(), ") << cmpError << std::endl;
std::wcerr << _T("ERROR: CMP_LoadTexture(); ") << cmpError << std::endl;
throw std::exception();
}
// FX image with extra info:
Vector<UINT32> vMipFX[2];
String pathnameFX(pathname);
Str::ReplaceExtension(pathnameFX, ".FX.png");
if (argNormalMap && IO::FileSystem::FileExist(_C(pathnameFX)))
{
std::wcout << _T("FX file: ") << Str::Utf8ToWide(pathnameFX) << std::endl;
IO::Image imageFX;
imageFX.Init(_C(pathnameFX));
if (imageFX._width == srcMipSet.m_nWidth && imageFX._height == srcMipSet.m_nHeight)
{
const int pixelCount = imageFX._width * imageFX._height;
vMipFX[0].resize(pixelCount);
vMipFX[1].resize(pixelCount);
VERUS_FOR(i, pixelCount)
memcpy(&vMipFX[0][i], imageFX._p + imageFX._bytesPerPixel * i, imageFX._bytesPerPixel);
}
else
{
std::wcerr << _T("ERROR: FX image has different dimensions: ") << imageFX._width << _T("x") << imageFX._height << std::endl;
throw std::exception();
}
}
if (srcMipSet.m_nMipLevels <= 1)
CMP_GenerateMIPLevels(&srcMipSet, 0);
@ -92,226 +234,300 @@ void Run()
const BYTE* pData = pMipLevel->m_pbData;
const int pixelCount = srcMipSet.m_nWidth * srcMipSet.m_nHeight;
Vector<UINT32> vMip[2];
bool normalMapToRoughness = false;
const int bytesPerPixel = sizeof(UINT32);
Vector<UINT32> vMip[4];
vMip[0].resize(pixelCount);
vMip[1].resize(pixelCount);
if (TexMode::x == currentTexMode)
{
String pathname = _pathname;
Str::ReplaceExtension(pathname, "");
Str::ReplaceExtension(pathname, ".N.TempR.tga");
if (IO::FileSystem::FileExist(_C(pathname)))
{
IO::Image image;
image.Init(_C(pathname));
if (image._width == srcMipSet.m_nWidth && image._height == srcMipSet.m_nHeight)
{
vMip[2].resize(pixelCount);
vMip[3].resize(pixelCount);
memcpy(vMip[3].data(), image._p, vMip[3].size() * bytesPerPixel);
normalMapToRoughness = true;
}
else
{
std::wcout << _T("WARNING: Normal map for roughness has different size.") << std::endl;
std::cin.ignore();
}
}
const float fadePerMip = pow(0.02f, 1.f / srcMipSet.m_nMipLevels);
if (!normalMapToRoughness)
{
std::wcout << _T("WARNING: Normal map for roughness not found.") << std::endl;
std::cin.ignore();
}
}
const bool sRGB = (TexMode::color == currentTexMode) || (TexMode::a == currentTexMode);
bool normWarning = false;
int mip = 0;
bool finish = false;
do
{
std::wcout << _T("Processing mipmap ") << mip << std::endl;
const int mipW = Math::Max(1, srcMipSet.m_nWidth >> mip);
const int mipH = Math::Max(1, srcMipSet.m_nHeight >> mip);
std::wcout << _T("Processing mip ") << std::setw(2) << mip << _T(" [");
const int length = Math::HighestBit(mipW) + 1;
VERUS_FOR(i, length)
std::wcout << _T("=");
std::wcout << _T("]") << std::endl;
// Switch between in and out:
const int inIndex = (mip & 0x1);
const int outIndex = ((mip + 1) & 0x1);
VERUS_FOR(i, mipH)
{
const int offsetH = i * mipW;
VERUS_FOR(j, mipW)
{
int offset = 0;
int offset = offsetH;
UINT32 color = 0;
UINT32 colorFX = 0;
UINT32 color2 = 0;
if (mip) // Generate mipmap level 1+:
if (mip) // Generate mip level 1+:
{
offset = i * mipW + j;
offset += j;
const int aboveMipW = mipW << 1;
const int aboveMipH = mipH << 1;
const int aboveMipEdgeW = aboveMipW - 1;
const int aboveMipEdgeH = aboveMipH - 1;
const int srcMipW = mipW << 1;
const int srcMipH = mipH << 1;
const int srcMipEdgeW = srcMipW - 1;
const int srcMipEdgeH = srcMipH - 1;
const int sampleA[2] = { Math::Clamp((j << 1) + 0, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 0, 0, aboveMipEdgeH) };
const int sampleB[2] = { Math::Clamp((j << 1) + 1, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 0, 0, aboveMipEdgeH) };
const int sampleC[2] = { Math::Clamp((j << 1) + 0, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 1, 0, aboveMipEdgeH) };
const int sampleD[2] = { Math::Clamp((j << 1) + 1, 0, aboveMipEdgeW), Math::Clamp((i << 1) + 1, 0, aboveMipEdgeH) };
const int coordA[2] = { Math::Clamp((j << 1) + 0, 0, srcMipEdgeW), Math::Clamp((i << 1) + 0, 0, srcMipEdgeH) };
const int coordB[2] = { Math::Clamp((j << 1) + 1, 0, srcMipEdgeW), Math::Clamp((i << 1) + 0, 0, srcMipEdgeH) };
const int coordC[2] = { Math::Clamp((j << 1) + 0, 0, srcMipEdgeW), Math::Clamp((i << 1) + 1, 0, srcMipEdgeH) };
const int coordD[2] = { Math::Clamp((j << 1) + 1, 0, srcMipEdgeW), Math::Clamp((i << 1) + 1, 0, srcMipEdgeH) };
const int offsetA = sampleA[1] * aboveMipW + sampleA[0];
const int offsetB = sampleB[1] * aboveMipW + sampleB[0];
const int offsetC = sampleC[1] * aboveMipW + sampleC[0];
const int offsetD = sampleD[1] * aboveMipW + sampleD[0];
const int offsetA = coordA[1] * srcMipW + coordA[0];
const int offsetB = coordB[1] * srcMipW + coordB[0];
const int offsetC = coordC[1] * srcMipW + coordC[0];
const int offsetD = coordD[1] * srcMipW + coordD[0];
if (argNormalMap)
BYTE computedRoughness = 0;
if (TexMode::n == currentTexMode || normalMapToRoughness) // N or X:
{
// Compute average normal:
const int inIndexEx = normalMapToRoughness ? inIndex + 2 : inIndex;
Vector4 data[4];
float raw[4];
Convert::ColorInt32ToFloat(vMip[inIndex][offsetA], raw, false); data[0] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetB], raw, false); data[1] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetC], raw, false); data[2] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetD], raw, false); data[3] = Vector4::MakeFromPointer(raw);
float floats[4];
Convert::ColorInt32ToFloat(vMip[inIndexEx][offsetA], floats, false); data[0] = Vector4::MakeFromPointer(floats);
Convert::ColorInt32ToFloat(vMip[inIndexEx][offsetB], floats, false); data[1] = Vector4::MakeFromPointer(floats);
Convert::ColorInt32ToFloat(vMip[inIndexEx][offsetC], floats, false); data[2] = Vector4::MakeFromPointer(floats);
Convert::ColorInt32ToFloat(vMip[inIndexEx][offsetD], floats, false); data[3] = Vector4::MakeFromPointer(floats);
// Generate FX mipmap:
if (!vMipFX[inIndex].empty())
{
const BYTE* rgbaA = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetA]);
const BYTE* rgbaB = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetB]);
const BYTE* rgbaC = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetC]);
const BYTE* rgbaD = reinterpret_cast<BYTE*>(&vMipFX[inIndex][offsetD]);
BYTE rgbaOut[4] =
{
static_cast<BYTE>((rgbaA[0] + rgbaB[0] + rgbaC[0] + rgbaD[0]) >> 2),
static_cast<BYTE>((rgbaA[1] + rgbaB[1] + rgbaC[1] + rgbaD[1]) >> 2),
static_cast<BYTE>((rgbaA[2] + rgbaB[2] + rgbaC[2] + rgbaD[2]) >> 2),
static_cast<BYTE>((rgbaA[3] + rgbaB[3] + rgbaC[3] + rgbaD[3]) >> 2)
};
memcpy(&colorFX, rgbaOut, 4);
}
const float prevAvgLength[4] =
{
data[0].getW(),
data[1].getW(),
data[2].getW(),
data[3].getW()
};
data[0].setW(0);
data[1].setW(0);
data[2].setW(0);
data[3].setW(0);
float minAvgLength = 1;
VERUS_FOR(i, 4) // To [-1 to 1]:
{
data[i] = data[i] * 2.f - Vector4(1, 1, 1, 0);
minAvgLength = Math::Min(minAvgLength, prevAvgLength[i]);
data[i] = data[i] * 2.f - Vector4::Replicate(1);
data[i].setW(0);
}
const Vector4 averageNormal = VMath::normalize(data[0] + data[1] + data[2] + data[3]);
Vector4 computedData = averageNormal;
computedData = computedData * 0.5f + Vector4::Replicate(0.5f); // To [0 to 1]:
computedData.setW(0);
color = Convert::ColorFloatToInt32(computedData.ToPointer(), false);
Vector4 avg = (
data[0] * prevAvgLength[0] +
data[1] * prevAvgLength[1] +
data[2] * prevAvgLength[2] +
data[3] * prevAvgLength[3]) * 0.25f;
float len = VMath::length(avg);
if (len > minAvgLength) // Don't make it too smooth.
len = (len + minAvgLength) * 0.5f;
Vector4 dataOut = VMath::normalize(data[0] + data[1] + data[2] + data[3]);
if (argFade)
dataOut = VMath::normalize(VMath::lerp(fadePerMip, Vector4(0, 0, 1, 0), dataOut));
dataOut = dataOut * 0.5f + Vector4(0.5f, 0.5f, 0.5f, 0); // To [0 to 1]:
dataOut.setW(len);
color = Convert::ColorFloatToInt32(dataOut.ToPointer(), false);
}
else
{
Vector4 data[4];
float raw[4];
Convert::ColorInt32ToFloat(vMip[inIndex][offsetA], raw, argColorData); data[0] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetB], raw, argColorData); data[1] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetC], raw, argColorData); data[2] = Vector4::MakeFromPointer(raw);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetD], raw, argColorData); data[3] = Vector4::MakeFromPointer(raw);
Vector4 dataOut = (data[0] + data[1] + data[2] + data[3]) * 0.25f;
color = Convert::ColorFloatToInt32(dataOut.ToPointer(), argColorData);
}
}
else // Handle topmost mipmap level:
{
if (argNormalMap)
{
const bool upsideDownBGRA = false;
if (upsideDownBGRA)
// Compute roughness from normal:
const bool saveRoughnessToAlpha = TexMode::n == currentTexMode && 1 == mip;
if (normalMapToRoughness || saveRoughnessToAlpha)
{
// Input image is upside down BGRA (?):
offset = (mipH - i - 1) * mipW + j;
UINT32 input = 0;
memcpy(&input, &pData[offset * 4], 4);
reinterpret_cast<BYTE*>(&input)[3] >>= 2; // Divide alpha by 4.
color = VERUS_COLOR_TO_D3D(input);
offset = i * mipW + j;
}
else
{
offset = i * mipW + j;
UINT32 input = 0;
memcpy(&input, &pData[offset * 4], 4);
reinterpret_cast<BYTE*>(&input)[3] = 0xFF;
color = input;
if (!vMipFX[inIndex].empty())
color2 = color;
float averageRoughness = 0;
VERUS_FOR(i, 4)
{
colorFX = vMipFX[inIndex][offset];
BYTE* rgbaFX = reinterpret_cast<BYTE*>(&colorFX);
rgbaFX[0] /= 4;
rgbaFX[1] /= 4;
rgbaFX[2] /= 4;
rgbaFX[3] /= 4;
const float d = VMath::dot(averageNormal, data[i]);
const float bias = 0.85f;
const float scale = 1.f / (1.f - 0.85f);
averageRoughness += 1.f - Math::Clamp<float>((d - bias) * scale, 0, 1);
}
averageRoughness = Math::Clamp<float>(averageRoughness * 0.25f, 0, 1);
computedRoughness = Convert::UnormToUint8(averageRoughness);
if (saveRoughnessToAlpha)
{
BYTE* pChannels = reinterpret_cast<BYTE*>(&color);
pChannels[3] = computedRoughness;
}
}
}
else // Simple copy for color:
if (TexMode::n != currentTexMode)
{
offset = i * mipW + j;
UINT32 input = 0;
memcpy(&input, &pData[offset * 4], 4);
color = input;
// Compute average value:
Vector4 data[4];
float floats[4];
Convert::ColorInt32ToFloat(vMip[inIndex][offsetA], floats, sRGB); data[0] = Vector4::MakeFromPointer(floats);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetB], floats, sRGB); data[1] = Vector4::MakeFromPointer(floats);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetC], floats, sRGB); data[2] = Vector4::MakeFromPointer(floats);
Convert::ColorInt32ToFloat(vMip[inIndex][offsetD], floats, sRGB); data[3] = Vector4::MakeFromPointer(floats);
Vector4 computedData = (data[0] + data[1] + data[2] + data[3]) * 0.25f;
color = Convert::ColorFloatToInt32(computedData.ToPointer(), sRGB);
if (normalMapToRoughness) // For X:
{
BYTE* pChannels = reinterpret_cast<BYTE*>(&color);
pChannels[1] = Math::Max(pChannels[1], computedRoughness);
}
}
}
else // Handle topmost mip level:
{
offset += j;
UINT32 input = 0;
memcpy(&input, &pData[offset * bytesPerPixel], bytesPerPixel);
// Normalize source normal map:
if (TexMode::n == currentTexMode)
{
Vector4 data;
float floats[4];
Convert::ColorInt32ToFloat(input, floats, false); data = Vector4::MakeFromPointer(floats);
data = data * 2.f - Vector4::Replicate(1); // To [-1 to 1]:
data.setW(0);
const float length = VMath::length(data);
if (abs(length - 1.f) >= 0.01f)
normWarning = true;
data /= length;
data = data * 0.5f + Vector4::Replicate(0.5f); // To [0 to 1]:
data.setW(0);
input = Convert::ColorFloatToInt32(data.ToPointer(), false);
}
// Add computed roughness from normal map:
if (normalMapToRoughness)
{
const BYTE computedRoughness = vMip[outIndex + 2][offset] >> 24;
BYTE* pChannels = reinterpret_cast<BYTE*>(&input);
pChannels[1] = Math::Max(pChannels[1], computedRoughness);
}
color = input;
}
vMip[outIndex][offset] = color;
if (!vMipFX[outIndex].empty())
vMipFX[outIndex][offset] = colorFX;
if (mip && normalMapToRoughness)
vMip[outIndex + 2][offset] = color2;
}
}
if (argNormalMap)
{
// Shuffle channels, read from outIndex, write to inIndex:
const int pixelCount = mipW * mipH;
VERUS_FOR(i, pixelCount)
{
BYTE* rgbaFX = vMipFX[outIndex].empty() ? nullptr : reinterpret_cast<BYTE*>(&vMipFX[outIndex][i]);
BYTE* rgba = reinterpret_cast<BYTE*>(&vMip[outIndex][i]);
const int len = Math::Clamp(rgba[3] - 128, 0, 0xFF);
vMip[inIndex][i] = VERUS_COLOR_RGBA(rgbaFX ? rgbaFX[0] : 0, rgba[1], len, rgba[0]);
}
// Save shuffled mip level, read from inIndex:
CMP_MipLevel* pDstMipLevel = nullptr;
CMP_GetMipLevel(&pDstMipLevel, &srcMipSet, mip, 0);
memcpy(pDstMipLevel->m_pbData, vMip[inIndex].data(), mipW * mipH * sizeof(UINT32));
}
else
{
CMP_MipLevel* pDstMipLevel = nullptr;
CMP_GetMipLevel(&pDstMipLevel, &srcMipSet, mip, 0);
memcpy(pDstMipLevel->m_pbData, vMip[outIndex].data(), mipW * mipH * sizeof(UINT32));
}
// Copy to CMP_MipLevel:
CMP_MipLevel* pDstMipLevel = nullptr;
CMP_GetMipLevel(&pDstMipLevel, &srcMipSet, mip, 0);
memcpy(pDstMipLevel->m_pbData, vMip[outIndex].data(), mipW * mipH * bytesPerPixel);
finish = (mipW == 1) && (mipH == 1);
mip++; // Next level, switch between in and out.
if (2 == mip && TexMode::n == currentTexMode)
{
String pathname = _pathname;
Str::ReplaceExtension(pathname, ".TempR.tga");
IO::FileSystem::SaveImage(_C(pathname), vMip[outIndex].data(), mipW, mipH);
std::wcout << _T("Saved normal map for roughness as: ") << Str::Utf8ToWide(pathname) << std::endl;
}
} while (!finish);
CMP_MipSet dstMipSet = {};
KernelOptions kernelOptions = {};
kernelOptions.format = CMP_FORMAT_BC7;
kernelOptions.fquality = 0.51f; // Tests show that 51% is production quality.
cmpError = CMP_ProcessTexture(&srcMipSet, &dstMipSet, kernelOptions, CompressionCallback);
if (CMP_OK != cmpError)
if (normWarning)
{
std::wcerr << _T("ERROR: CMP_ProcessTexture(), ") << cmpError << std::endl;
throw std::exception();
std::wcout << _T("WARNING: Source normal map was not normalized.") << std::endl;
std::cin.ignore();
}
Str::ReplaceExtension(pathname, ".dds");
cmpError = CMP_SaveTexture(_C(pathname), &dstMipSet);
if (CMP_OK != cmpError)
Str::ReplaceExtension(_pathname, ".dds");
if (_asIs)
{
std::wcerr << _T("ERROR: CMP_SaveTexture(), ") << cmpError << std::endl;
throw std::exception();
cmpError = CMP_SaveTexture(_C(_pathname), &srcMipSet);
if (CMP_OK != cmpError)
{
std::wcerr << _T("ERROR: CMP_SaveTexture(); ") << cmpError << std::endl;
throw std::exception();
}
}
else
{
CMP_MipSet dstMipSet = {};
KernelOptions kernelOptions = {};
if (TexMode::n == currentTexMode)
{
kernelOptions.format = CMP_FORMAT_BC5;
kernelOptions.fquality = 0.8f; // Use 80% for BC5.
}
else
{
kernelOptions.format = CMP_FORMAT_BC7;
kernelOptions.fquality = 0.6f; // Use 60% for BC7.
}
{
CursorGuard cursorGuard;
cmpError = CMP_ProcessTexture(&srcMipSet, &dstMipSet, kernelOptions, FeedbackProc);
std::wcout << std::endl;
}
if (CMP_OK != cmpError)
{
std::wcerr << _T("ERROR: CMP_ProcessTexture(), ") << cmpError << std::endl;
throw std::exception();
}
cmpError = CMP_SaveTexture(_C(_pathname), &dstMipSet);
if (CMP_OK != cmpError)
{
std::wcerr << _T("ERROR: CMP_SaveTexture(); ") << cmpError << std::endl;
throw std::exception();
}
CMP_FreeMipSet(&dstMipSet);
}
CMP_FreeMipSet(&srcMipSet);
CMP_FreeMipSet(&dstMipSet);
std::wcout << _T("Saved as: ") << Str::Utf8ToWide(_pathname) << std::endl;
}
void TextureTool::ComputeEdgePadding()
{
if (!IO::FileSystem::FileExist(_C(_pathname)))
{
std::wcerr << _T("ERROR: File not found: ") << Str::Utf8ToWide(_pathname) << std::endl;
throw std::exception();
}
IO::Image image;
image.Init(_C(_pathname));
IO::Image imageFaces;
if (_edgePaddingUsingFaces)
{
Str::ReplaceFilename(_pathname, "Faces.png");
if (!IO::FileSystem::FileExist(_C(_pathname)))
{
std::wcerr << _T("ERROR: File not found: ") << Str::Utf8ToWide(_pathname) << std::endl;
throw std::exception();
}
imageFaces.Init(_C(_pathname));
if (image._width != imageFaces._width || image._height != imageFaces._height)
{
std::wcerr << _T("ERROR: Faces image has different size.") << std::endl;
throw std::exception();
}
}
if (_edgePaddingUsingAlpha)
Utils::ComputeEdgePadding(image._p, image._pixelStride, image._p + 3, image._pixelStride, image._width, image._height, 0, 3);
else if (_edgePaddingUsingFaces)
Utils::ComputeEdgePadding(image._p, image._pixelStride, imageFaces._p, imageFaces._pixelStride, image._width, image._height, 0, 4);
Str::ReplaceFilename(_pathname, "ComputedEdgePadding.tga");
IO::FileSystem::SaveImage(_C(_pathname), reinterpret_cast<UINT32*>(image._p), image._width, image._height, IO::ImageFormat::tga, image._pixelStride);
}
void DeleteMipmap(CWSZ pathname)
@ -356,7 +572,8 @@ int main(VERUS_MAIN_DEFAULT_ARGS)
{
try
{
Run();
TextureTool textureTool;
textureTool.Main(argc, argv);
}
catch (const std::exception& e)
{

View File

@ -3,8 +3,8 @@
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IncludePath>C:\Compressonator_4.2.5185\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.89\src;C:\Home\Middleware\bullet3-2.89\Extras;C:\Home\Middleware\libogg-1.3.4\include;C:\Home\Middleware\libvorbis-1.3.7\include;C:\Home\Middleware\openal-soft-1.21.1-bin\include;C:\Home\Middleware\SDL2-2.0.16\include;C:\VulkanSDK\1.3.204.1\Include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Compressonator_4.2.5185\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\libogg-1.3.4\lib;C:\Home\Middleware\libvorbis-1.3.7\lib2;C:\Home\Middleware\openal-soft-1.21.1-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.16\lib\x64;C:\VulkanSDK\1.3.204.1\Lib;$(LibraryPath)</LibraryPath>
<IncludePath>C:\Compressonator_4.2.5185\include;C:\Home\Projects\Verus\verus\Verus\src;C:\Home\Middleware\AMD Tootle 2.3\include;C:\Home\Middleware\bullet3-2.89\src;C:\Home\Middleware\bullet3-2.89\Extras;C:\Home\Middleware\libogg-1.3.5\include;C:\Home\Middleware\libvorbis-1.3.7\include;C:\Home\Middleware\openal-soft-1.22.0-bin\include;C:\Home\Middleware\SDL2-2.0.22\include;C:\VulkanSDK\1.3.216.0\Include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Compressonator_4.2.5185\lib\VS2017\x64;C:\Home\Middleware\bullet3-2.89\bin;C:\Home\Middleware\AMD Tootle 2.3\lib;C:\Home\Middleware\libogg-1.3.5\lib;C:\Home\Middleware\libvorbis-1.3.7\lib2;C:\Home\Middleware\openal-soft-1.22.0-bin\libs\Win64;C:\Home\Middleware\SDL2-2.0.22\lib\x64;C:\VulkanSDK\1.3.216.0\Lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup />

View File

@ -15,7 +15,7 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{B154D670-E4B1-4D8A-885C-69546A5BD833}</ProjectGuid>
<RootNamespace>Verus</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@ -673,25 +673,6 @@
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS.inc.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_Compose.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_Compose.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\LibDeferredShading.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\LibLighting.hlsl">
<FileType>Document</FileType>
@ -817,22 +798,6 @@
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS_AO.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_AO.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS_BakeSprites.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_BakeSprites.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS_Forest.hlsl">
<FileType>Document</FileType>
@ -889,6 +854,49 @@
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\GenerateCubeMapMips.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\GenerateCubeMapMips.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS.inc.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_Compose.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_Compose.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\LibDeferredShading.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS_BakeSprites.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_BakeSprites.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\DS_Ambient.hlsl">
<FileType>Document</FileType>
</None>
<None Include="src\Shaders\DS_Ambient.inc.hlsl">
<FileType>Document</FileType>
</None>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -489,9 +489,6 @@
<ClInclude Include="src\Scene\EditorTerrain.h">
<Filter>src\Scene</Filter>
</ClInclude>
<ClInclude Include="src\CGI\DeferredShading.h">
<Filter>src\CGI</Filter>
</ClInclude>
<ClInclude Include="src\Scene\Helpers.h">
<Filter>src\Scene</Filter>
</ClInclude>
@ -786,6 +783,9 @@
<ClInclude Include="src\Scene\LightMapBaker.h">
<Filter>src\Scene</Filter>
</ClInclude>
<ClInclude Include="src\CGI\DeferredShading.h">
<Filter>src\CGI</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\CGI\BaseGeometry.cpp">
@ -1073,9 +1073,6 @@
<ClCompile Include="src\Scene\EditorTerrain.cpp">
<Filter>src\Scene</Filter>
</ClCompile>
<ClCompile Include="src\CGI\DeferredShading.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
<ClCompile Include="src\Scene\Helpers.cpp">
<Filter>src\Scene</Filter>
</ClCompile>
@ -1349,6 +1346,9 @@
<ClCompile Include="src\Scene\LightMapBaker.cpp">
<Filter>src\Scene</Filter>
</ClCompile>
<ClCompile Include="src\CGI\DeferredShading.cpp">
<Filter>src\CGI</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="src\Shaders\Lib.hlsl">
@ -1378,21 +1378,6 @@
<None Include="src\Shaders\GenerateMips.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\LibDeferredShading.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_Compose.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_Compose.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\LibLighting.hlsl">
<Filter>src\Shaders</Filter>
</None>
@ -1477,18 +1462,6 @@
<None Include="src\Shaders\Bloom.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_AO.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_AO.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_BakeSprites.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_BakeSprites.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_Forest.hlsl">
<Filter>src\Shaders</Filter>
</None>
@ -1531,6 +1504,39 @@
<None Include="src\Shaders\DS_Reflection.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\GenerateCubeMapMips.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\GenerateCubeMapMips.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_Compose.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_Compose.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\LibDeferredShading.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_BakeSprites.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_BakeSprites.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_Ambient.hlsl">
<Filter>src\Shaders</Filter>
</None>
<None Include="src\Shaders\DS_Ambient.inc.hlsl">
<Filter>src\Shaders</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Natvis Include="src\ThirdParty\pugixml-1.11\pugixml.natvis">

View File

@ -50,7 +50,7 @@ void QualitySettings::SetQuality(OverallQuality q)
_postProcessBloom = false;
_postProcessLightShafts = false;
_postProcessSSAO = false;
_sceneGrassDensity = 600;
_sceneGrassDensity = 500;
_sceneShadowQuality = Quality::low;
_sceneWaterQuality = WaterQuality::solidColor;
break;
@ -61,7 +61,7 @@ void QualitySettings::SetQuality(OverallQuality q)
_gpuShaderQuality = Quality::high;
_postProcessCinema = true;
_sceneAmbientOcclusion = true;
_sceneGrassDensity = 900;
_sceneGrassDensity = 700;
_sceneShadowQuality = Quality::high;
_sceneWaterQuality = WaterQuality::trueWavesReflection;
break;
@ -72,7 +72,7 @@ void QualitySettings::SetQuality(OverallQuality q)
_postProcessMotionBlur = true;
_postProcessSSR = true;
_sceneAmbientOcclusion = true;
_sceneGrassDensity = 1000;
_sceneGrassDensity = 800;
_sceneShadowQuality = Quality::ultra;
_sceneWaterQuality = WaterQuality::trueWavesRefraction;
break;

View File

@ -57,7 +57,7 @@ namespace verus
bool _postProcessSSAO = true;
bool _postProcessSSR = false;
bool _sceneAmbientOcclusion = false;
int _sceneGrassDensity = 800;
int _sceneGrassDensity = 600;
Quality _sceneShadowQuality = Quality::medium;
WaterQuality _sceneWaterQuality = WaterQuality::solidColor;
@ -83,6 +83,7 @@ namespace verus
int _ds_ubAOTexturesFSCapacity = 2;
int _ds_ubAOPerMeshVSCapacity = 10;
int _generateMips_ubCapacity = 50;
int _generateCubeMapMips_ubCapacity = 50;
int _grass_ubVSCapacity = 4;
int _grass_ubFSCapacity = 4;
int _gui_ubGuiCapacity = 100;

View File

@ -23,30 +23,41 @@ namespace verus
virtual void Begin() = 0;
virtual void End() = 0;
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor = true) = 0;
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout,
Range mipLevels, Range arrayLayers = 0) = 0;
// <RenderPass>
virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle,
std::initializer_list<Vector4> ilClearValues, bool setViewportAndScissor = true) = 0;
virtual void NextSubpass() = 0;
virtual void EndRenderPass() = 0;
// </RenderPass>
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter = UINT32_MAX) = 0;
virtual void BindIndexBuffer(GeometryPtr geo) = 0;
// <Pipeline>
virtual void BindPipeline(PipelinePtr pipe) = 0;
virtual void SetViewport(std::initializer_list<Vector4> il, float minDepth = 0, float maxDepth = 1) = 0;
virtual void SetScissor(std::initializer_list<Vector4> il) = 0;
virtual void SetBlendConstants(const float* p) = 0;
// </Pipeline>
// <VertexInput>
virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter = UINT32_MAX) = 0;
virtual void BindIndexBuffer(GeometryPtr geo) = 0;
// </VertexInput>
// <Descriptors>
virtual bool BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle = CSHandle()) = 0;
virtual void PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags = ShaderStageFlags::vs_fs) = 0;
// </Descriptors>
virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout,
Range mipLevels, int arrayLayer = 0) = 0;
// <Draw>
virtual void Draw(int vertexCount, int instanceCount = 1, int firstVertex = 0, int firstInstance = 0) = 0;
virtual void DrawIndexed(int indexCount, int instanceCount = 1, int firstIndex = 0, int vertexOffset = 0, int firstInstance = 0) = 0;
virtual void Dispatch(int groupCountX, int groupCountY, int groupCountZ = 1) = 0;
virtual void DispatchIndirect() {} // WIP.
virtual void DispatchMesh(int groupCountX, int groupCountY, int groupCountZ) {} // WIP.
virtual void TraceRays(int width, int height, int depth) {} // WIP.
// </Draw>
RcVector4 GetViewportSize() const { return _viewportSize; }
};

View File

@ -17,7 +17,6 @@ namespace verus
int _sampleCount = 1;
RPHandle _renderPassHandle;
int _subpass = 0;
int _multiViewport = 1; // See SV_ViewportArrayIndex semantic output by a geometry shader.
UINT32 _vertexInputBindingsFilter = UINT32_MAX;
CompareOp _depthCompareOp = CompareOp::less;
bool _depthTestEnable = true;

View File

@ -59,14 +59,15 @@ namespace verus
// Which graphics API?
virtual Gapi GetGapi() = 0;
// Frame cycle:
// <FrameCycle>
virtual void BeginFrame(bool present = true) = 0;
virtual void EndFrame(bool present = true) = 0;
virtual void Present() = 0;
virtual void Sync(bool present = true) = 0;
virtual void WaitIdle() = 0;
// </FrameCycle>
// Resources:
// <Resources>
virtual PBaseCommandBuffer InsertCommandBuffer() = 0;
virtual PBaseGeometry InsertGeometry() = 0;
virtual PBasePipeline InsertPipeline() = 0;
@ -86,6 +87,7 @@ namespace verus
int swapChainBufferIndex = -1, CubeMapFace cubeMapFace = CubeMapFace::none) = 0;
virtual void DeleteRenderPass(RPHandle handle) = 0;
virtual void DeleteFramebuffer(FBHandle handle) = 0;
// </Resources>
static void SetAlphaBlendHelper(
CSZ sz,

View File

@ -61,7 +61,8 @@ namespace verus
virtual void CreateDescriptorSet(int setNumber, const void* pSrc, int size,
int capacity = 1, std::initializer_list<Sampler> il = {}, ShaderStageFlags stageFlags = ShaderStageFlags::vs_fs) = 0;
virtual void CreatePipelineLayout() = 0;
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il, const int* pMips = nullptr) = 0;
virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list<TexturePtr> il,
const int* pMipLevels = nullptr, const int* pArrayLayers = nullptr) = 0;
virtual void FreeDescriptorSet(CSHandle& complexSetHandle) = 0;
virtual void BeginBindDescriptors() = 0;

View File

@ -25,6 +25,28 @@ bool BaseTexture::IsSRGB() const
!Str::EndsWith(_C(_name), ".X.dds");
}
Format BaseTexture::ToTextureBcFormat(IO::RcDDSHeader header, IO::RcDDSHeaderDXT10 header10) const
{
auto SelectFormat = [this](Format unorm, Format srgb)
{
return IsSRGB() ? srgb : unorm;
};
if (header.IsBC1())
return SelectFormat(Format::unormBC1, Format::srgbBC1);
else if (header.IsBC2())
return SelectFormat(Format::unormBC2, Format::srgbBC2);
else if (header.IsBC3())
return SelectFormat(Format::unormBC3, Format::srgbBC3);
else if (header.IsBC4U() || header.IsBC4S())
return Format::unormBC4;
else if (header.IsBC5U() || header.IsBC5S())
return Format::unormBC5;
else if (header10.IsBC7())
return SelectFormat(Format::unormBC7, Format::srgbBC7);
VERUS_RT_FAIL("DDS format is not BC.");
return Format::unormR8G8B8A8;
}
void BaseTexture::LoadDDS(CSZ url, int texturePart)
{
_name = url;
@ -58,20 +80,8 @@ void BaseTexture::LoadDDS(CSZ url, RcBlob blob)
if (header.IsBC())
{
auto SelectFormat = [this](Format unorm, Format srgb)
{
return IsSRGB() ? srgb : unorm;
};
TextureDesc desc;
if (header.IsBC1())
desc._format = SelectFormat(Format::unormBC1, Format::srgbBC1);
else if (header.IsBC2())
desc._format = SelectFormat(Format::unormBC2, Format::srgbBC2);
else if (header.IsBC3())
desc._format = SelectFormat(Format::unormBC3, Format::srgbBC3);
else if (header10.IsBC7())
desc._format = SelectFormat(Format::unormBC7, Format::srgbBC7);
desc._format = ToTextureBcFormat(header, header10);
desc._width = header._width >> lod;
desc._height = header._height >> lod;
desc._mipLevels = header._mipMapCount - lod;
@ -236,14 +246,8 @@ void BaseTexture::LoadDDSArray(CSZ* urls)
if (header.IsBC())
{
auto SelectFormat = [this](Format unorm, Format srgb)
{
return IsSRGB() ? srgb : unorm;
};
const int w = header._width >> lod;
const int h = header._height >> lod;
if (desc._width)
{
VERUS_RT_ASSERT(desc._width == w);
@ -253,14 +257,7 @@ void BaseTexture::LoadDDSArray(CSZ* urls)
VERUS_RT_ASSERT(desc._height == h);
}
if (header.IsBC1())
desc._format = SelectFormat(Format::unormBC1, Format::srgbBC1);
else if (header.IsBC2())
desc._format = SelectFormat(Format::unormBC2, Format::srgbBC2);
else if (header.IsBC3())
desc._format = SelectFormat(Format::unormBC3, Format::srgbBC3);
else if (header10.IsBC7())
desc._format = SelectFormat(Format::unormBC7, Format::srgbBC7);
desc._format = ToTextureBcFormat(header, header10);
desc._width = w;
desc._height = h;
desc._mipLevels = header._mipMapCount - lod;
@ -350,7 +347,7 @@ bool BaseTexture::IsBC(Format format)
bool BaseTexture::Is4BitsBC(Format format)
{
return format == Format::unormBC1 || format == Format::srgbBC1;
return format == Format::unormBC1 || format == Format::srgbBC1 || format == Format::unormBC4;
}
bool BaseTexture::IsDepthFormat(Format format)

View File

@ -104,6 +104,7 @@ namespace verus
int GetPart() const { return _part; }
RcVector4 GetSize() const { return _size; }
bool IsSRGB() const;
Format ToTextureBcFormat(IO::RcDDSHeader header, IO::RcDDSHeaderDXT10 header10) const;
void SetLoadingFlags(TextureDesc::Flags flags) { _desc._flags = flags; }
void SetLoadingSamplerDesc(PcSamplerDesc pSamplerDesc) { _desc._pSamplerDesc = pSamplerDesc; }

View File

@ -10,10 +10,8 @@ DeferredShading::UB_PerMeshVS DeferredShading::s_ubPerMeshVS;
DeferredShading::UB_ShadowFS DeferredShading::s_ubShadowFS;
DeferredShading::UB_PerObject DeferredShading::s_ubPerObject;
DeferredShading::UB_AOPerFrame DeferredShading::s_ubAOPerFrame;
DeferredShading::UB_AOTexturesFS DeferredShading::s_ubAOTexturesFS;
DeferredShading::UB_AOPerMeshVS DeferredShading::s_ubAOPerMeshVS;
DeferredShading::UB_AOPerObject DeferredShading::s_ubAOPerObject;
DeferredShading::UB_AmbientVS DeferredShading::s_ubAmbientVS;
DeferredShading::UB_AmbientFS DeferredShading::s_ubAmbientFS;
DeferredShading::UB_ComposeVS DeferredShading::s_ubComposeVS;
DeferredShading::UB_ComposeFS DeferredShading::s_ubComposeFS;
@ -45,6 +43,8 @@ void DeferredShading::Init()
RP::Attachment("GBuffer0", Format::srgbR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer1", Format::unormR10G10B10A2).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer2", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer3", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("LightAccAmb", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("LightAccDiff", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("LightAccSpec", Format::floatR11G11B10).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("Depth", Format::unormD24uintS8).LoadOpClear().Layout(ImageLayout::depthStencilAttachment, ImageLayout::depthStencilReadOnly)
@ -54,16 +54,19 @@ void DeferredShading::Init()
{
RP::Ref("GBuffer0", ImageLayout::colorAttachment),
RP::Ref("GBuffer1", ImageLayout::colorAttachment),
RP::Ref("GBuffer2", ImageLayout::colorAttachment)
RP::Ref("GBuffer2", ImageLayout::colorAttachment),
RP::Ref("GBuffer3", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilAttachment)),
RP::Subpass("Sp1").Input(
{
RP::Ref("GBuffer0", ImageLayout::fsReadOnly),
RP::Ref("GBuffer1", ImageLayout::fsReadOnly),
RP::Ref("GBuffer2", ImageLayout::fsReadOnly),
RP::Ref("GBuffer3", ImageLayout::fsReadOnly),
RP::Ref("Depth", ImageLayout::depthStencilReadOnly)
}).Color(
{
RP::Ref("LightAccAmb", ImageLayout::colorAttachment),
RP::Ref("LightAccDiff", ImageLayout::colorAttachment),
RP::Ref("LightAccSpec", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilReadOnly))
@ -71,37 +74,23 @@ void DeferredShading::Init()
{
RP::Dependency("Sp0", "Sp1").Mode(1)
});
const RP::Attachment::LoadOp loadOp = settings._postProcessSSAO ? RP::Attachment::LoadOp::load : RP::Attachment::LoadOp::clear;
_rphAO = renderer->CreateRenderPass(
{
RP::Attachment("Attach", Format::unormR8).SetLoadOp(loadOp).Layout(ImageLayout::fsReadOnly),
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilReadOnly)
},
{
RP::Subpass("Sp0").Input(
{
RP::Ref("Depth", ImageLayout::depthStencilReadOnly)
}).Color(
{
RP::Ref("Attach", ImageLayout::colorAttachment)
}).DepthStencil(RP::Ref("Depth", ImageLayout::depthStencilReadOnly))
},
{});
_rphCompose = renderer->CreateRenderPass(
{
RP::Attachment("ComposedA", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
RP::Attachment("ComposedB", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly)
RP::Attachment("ComposedB", Format::floatR11G11B10).LoadOpDontCare().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer3", Format::unormR8G8B8A8).LoadOpDontCare().Layout(ImageLayout::fsReadOnly)
},
{
RP::Subpass("Sp0").Color(
{
RP::Ref("ComposedA", ImageLayout::colorAttachment),
RP::Ref("ComposedB", ImageLayout::colorAttachment)
RP::Ref("ComposedB", ImageLayout::colorAttachment),
RP::Ref("GBuffer3", ImageLayout::colorAttachment)
})
},
{});
// Extra stuff, which is not using deferred shading, for example water and sky:
_rphExtraCompose = renderer->CreateRenderPass(
_rphForwardRendering = renderer->CreateRenderPass(
{
RP::Attachment("ComposedA", Format::floatR11G11B10).Layout(ImageLayout::fsReadOnly),
RP::Attachment("Depth", Format::unormD24uintS8).Layout(ImageLayout::depthStencilReadOnly, ImageLayout::depthStencilAttachment)
@ -120,35 +109,39 @@ void DeferredShading::Init()
_shader[SHADER_LIGHT]->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame), settings._limits._ds_ubPerFrameCapacity);
_shader[SHADER_LIGHT]->CreateDescriptorSet(1, &s_ubTexturesFS, sizeof(s_ubTexturesFS), settings._limits._ds_ubTexturesFSCapacity,
{
Sampler::input,
Sampler::input,
Sampler::input,
Sampler::input,
Sampler::shadow,
Sampler::nearestClampMipN
Sampler::input, // GBuffer0
Sampler::input, // GBuffer1
Sampler::input, // GBuffer2
Sampler::input, // GBuffer3
Sampler::input, // Depth
Sampler::shadow, // ShadowCmp
Sampler::nearestClampMipN // Shadow
}, ShaderStageFlags::fs);
_shader[SHADER_LIGHT]->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), settings._limits._ds_ubPerMeshVSCapacity, {}, ShaderStageFlags::vs);
_shader[SHADER_LIGHT]->CreateDescriptorSet(3, &s_ubShadowFS, sizeof(s_ubShadowFS), settings._limits._ds_ubShadowFSCapacity, {}, ShaderStageFlags::fs);
_shader[SHADER_LIGHT]->CreateDescriptorSet(4, &s_ubPerObject, sizeof(s_ubPerObject), 0);
_shader[SHADER_LIGHT]->CreatePipelineLayout();
_shader[SHADER_AO].Init("[Shaders]:DS_AO.hlsl");
_shader[SHADER_AO]->CreateDescriptorSet(0, &s_ubAOPerFrame, sizeof(s_ubAOPerFrame), settings._limits._ds_ubAOPerFrameCapacity);
_shader[SHADER_AO]->CreateDescriptorSet(1, &s_ubAOTexturesFS, sizeof(s_ubAOTexturesFS), settings._limits._ds_ubAOTexturesFSCapacity,
_shader[SHADER_AMBIENT].Init("[Shaders]:DS_Ambient.hlsl");
_shader[SHADER_AMBIENT]->CreateDescriptorSet(0, &s_ubAmbientVS, sizeof(s_ubAmbientVS), 2);
_shader[SHADER_AMBIENT]->CreateDescriptorSet(1, &s_ubAmbientFS, sizeof(s_ubAmbientFS), 2,
{
Sampler::input,
Sampler::nearestClampMipN
Sampler::input, // GBuffer0
Sampler::input, // GBuffer1
Sampler::input, // GBuffer2
Sampler::input, // GBuffer3
Sampler::input, // Depth
CGI::Sampler::linearClampMipN, // TerrainHeightmap
CGI::Sampler::anisoClamp // TerrainBlend
}, ShaderStageFlags::fs);
_shader[SHADER_AO]->CreateDescriptorSet(2, &s_ubAOPerMeshVS, sizeof(s_ubAOPerMeshVS), settings._limits._ds_ubAOPerMeshVSCapacity, {}, ShaderStageFlags::vs);
_shader[SHADER_AO]->CreateDescriptorSet(3, &s_ubAOPerObject, sizeof(s_ubAOPerObject), 0);
_shader[SHADER_AO]->CreatePipelineLayout();
_shader[SHADER_AMBIENT]->CreatePipelineLayout();
ShaderDesc shaderDesc("[Shaders]:DS_Compose.hlsl");
String userDefines;
if (settings._postProcessCinema)
userDefines += " CINEMA";
if (settings._postProcessBloom)
userDefines += " BLOOM";
if (settings._postProcessSSAO || settings._sceneAmbientOcclusion)
userDefines += " AO";
if (!userDefines.empty())
{
userDefines = userDefines.substr(1);
@ -158,12 +151,13 @@ void DeferredShading::Init()
_shader[SHADER_COMPOSE]->CreateDescriptorSet(0, &s_ubComposeVS, sizeof(s_ubComposeVS), 4, {}, ShaderStageFlags::vs);
_shader[SHADER_COMPOSE]->CreateDescriptorSet(1, &s_ubComposeFS, sizeof(s_ubComposeFS), 4,
{
Sampler::linearClampMipN, // GBuffer0
Sampler::linearClampMipN, // GBuffer1
Sampler::linearClampMipN, // GBuffer2|AO
Sampler::linearClampMipN, // Depth|Composed
Sampler::linearClampMipN, // AccDiff|Bloom
Sampler::linearClampMipN // AccSpec
Sampler::nearestClampMipN, // GBuffer0
Sampler::nearestClampMipN, // GBuffer1
Sampler::nearestClampMipN, // GBuffer2|Bloom
Sampler::nearestClampMipN, // Depth|Composed
Sampler::nearestClampMipN, // Ambient
Sampler::nearestClampMipN, // Diffuse
Sampler::nearestClampMipN // Specular
}, ShaderStageFlags::fs);
_shader[SHADER_COMPOSE]->CreatePipelineLayout();
@ -171,7 +165,6 @@ void DeferredShading::Init()
_shader[SHADER_REFLECTION]->CreateDescriptorSet(0, &s_ubReflectionVS, sizeof(s_ubReflectionVS), 2);
_shader[SHADER_REFLECTION]->CreateDescriptorSet(1, &s_ubReflectionFS, sizeof(s_ubReflectionFS), 2,
{
Sampler::nearestClampMipN,
Sampler::nearestClampMipN,
Sampler::nearestClampMipN
}, ShaderStageFlags::fs);
@ -181,16 +174,33 @@ void DeferredShading::Init()
_shader[SHADER_BAKE_SPRITES]->CreateDescriptorSet(0, &s_ubBakeSpritesVS, sizeof(s_ubBakeSpritesVS), 1000);
_shader[SHADER_BAKE_SPRITES]->CreateDescriptorSet(1, &s_ubBakeSpritesFS, sizeof(s_ubBakeSpritesFS), 1000,
{
Sampler::nearestClampMipN,
Sampler::nearestClampMipN,
Sampler::nearestClampMipN
Sampler::nearestClampMipN, // GBuffer0
Sampler::nearestClampMipN, // GBuffer1
Sampler::nearestClampMipN, // GBuffer2
Sampler::nearestClampMipN // GBuffer3
}, ShaderStageFlags::fs);
_shader[SHADER_BAKE_SPRITES]->CreatePipelineLayout();
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_AMBIENT], "#", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._colorAttachWriteMasks[1] = "";
pipeDesc._colorAttachWriteMasks[2] = "";
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_AMBIENT].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#Compose", _rphCompose);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._colorAttachWriteMasks[1] = "rgb";
pipeDesc._colorAttachWriteMasks[2] = "b";
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_COMPOSE].Init(pipeDesc);
@ -198,10 +208,18 @@ void DeferredShading::Init()
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_REFLECTION], "#", _rphReflection);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_REFLECTION].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_REFLECTION], "#DebugCubeMap", _rphReflection);
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_REFLECTION_DEBUG].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader[SHADER_COMPOSE], "#ToneMapping", renderer.GetRenderPassHandle_AutoWithDepth());
pipeDesc._topology = PrimitiveTopology::triangleStrip;
@ -225,7 +243,7 @@ void DeferredShading::InitGBuffers(int w, int h)
TextureDesc texDesc;
// GB0:
texDesc._clearValue = Vector4(0);
texDesc._clearValue = GetClearValueForGBuffer0();
texDesc._name = "DeferredShading.GBuffer0";
texDesc._format = Format::srgbR8G8B8A8;
texDesc._width = w;
@ -234,7 +252,7 @@ void DeferredShading::InitGBuffers(int w, int h)
_tex[TEX_GBUFFER_0].Init(texDesc);
// GB1:
texDesc._clearValue = Vector4(0, 0, 0.25f, 1);
texDesc._clearValue = GetClearValueForGBuffer1();
texDesc._name = "DeferredShading.GBuffer1";
texDesc._format = Format::unormR10G10B10A2;
texDesc._width = w;
@ -243,20 +261,30 @@ void DeferredShading::InitGBuffers(int w, int h)
_tex[TEX_GBUFFER_1].Init(texDesc);
// GB2:
texDesc._clearValue = Vector4(1 / 8.f, 0.5f, 0.5f, 0);
texDesc._clearValue = GetClearValueForGBuffer2();
texDesc._name = "DeferredShading.GBuffer2";
texDesc._format = Format::unormR8G8B8A8;
texDesc._width = w;
texDesc._height = h;
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
_tex[TEX_GBUFFER_2].Init(texDesc);
// GB3:
texDesc._clearValue = GetClearValueForGBuffer3();
texDesc._name = "DeferredShading.GBuffer3";
texDesc._format = Format::unormR8G8B8A8;
texDesc._width = w;
texDesc._height = h;
texDesc._flags = TextureDesc::Flags::colorAttachment | TextureDesc::Flags::inputAttachment;
_tex[TEX_GBUFFER_3].Init(texDesc);
}
void DeferredShading::InitByAtmosphere(TexturePtr texShadow)
{
VERUS_QREF_RENDERER;
_texShadowAtmo = texShadow;
if (texShadow)
_texAtmoShadow = texShadow;
_shader[SHADER_LIGHT]->FreeDescriptorSet(_cshLight);
_cshLight = _shader[SHADER_LIGHT]->BindDescriptorSetTextures(1,
@ -264,61 +292,49 @@ void DeferredShading::InitByAtmosphere(TexturePtr texShadow)
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_GBUFFER_3],
renderer.GetTexDepthStencil(),
_texShadowAtmo,
_texShadowAtmo
_texAtmoShadow ? _texAtmoShadow : _tex[TEX_GBUFFER_0],
_texAtmoShadow ? _texAtmoShadow : _tex[TEX_GBUFFER_1]
});
}
void DeferredShading::InitByBloom(TexturePtr tex)
{
VERUS_QREF_RENDERER;
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshToneMapping);
_cshToneMapping = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
tex,
_tex[TEX_COMPOSED_A],
_tex[TEX_LIGHT_ACC_AMBIENT],
_tex[TEX_LIGHT_ACC_DIFFUSE],
_tex[TEX_LIGHT_ACC_SPECULAR]
});
}
void DeferredShading::InitByTerrain(TexturePtr texHeightmap, TexturePtr texBlend, int mapSide)
{
VERUS_QREF_RENDERER;
if (texHeightmap)
_texTerrainHeightmap = texHeightmap;
if (texBlend)
_texTerrainBlend = texBlend;
if (mapSide > 1)
_terrainMapSide = mapSide;
_shader[SHADER_AMBIENT]->FreeDescriptorSet(_cshAmbient);
_cshAmbient = _shader[SHADER_AMBIENT]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_COMPOSED_A],
tex,
_tex[TEX_LIGHT_ACC_SPEC]
});
}
void DeferredShading::InitBySsao(TexturePtr tex)
{
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
const int scaledSwapChainWidth = settings.Scale(renderer.GetSwapChainWidth());
const int scaledSwapChainHeight = settings.Scale(renderer.GetSwapChainHeight());
_texAO = tex;
_fbhAO = renderer->CreateFramebuffer(_rphAO,
{
tex,
_tex[TEX_GBUFFER_3],
renderer.GetTexDepthStencil(),
},
scaledSwapChainWidth, scaledSwapChainHeight);
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshCompose);
_shader[SHADER_AO]->FreeDescriptorSet(_cshAO);
_cshAO = _shader[SHADER_AO]->BindDescriptorSetTextures(1,
{
renderer.GetTexDepthStencil(),
_tex[TEX_GBUFFER_1],
});
_cshCompose = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
tex,
renderer.GetTexDepthStencil(),
_tex[TEX_LIGHT_ACC_DIFF],
_tex[TEX_LIGHT_ACC_SPEC]
_texTerrainHeightmap ? _texTerrainHeightmap : _tex[TEX_GBUFFER_0],
_texTerrainBlend ? _texTerrainBlend : _tex[TEX_GBUFFER_1]
});
}
@ -339,18 +355,20 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshToneMapping);
_shader[SHADER_REFLECTION]->FreeDescriptorSet(_cshReflection);
_shader[SHADER_COMPOSE]->FreeDescriptorSet(_cshCompose);
_shader[SHADER_AMBIENT]->FreeDescriptorSet(_cshAmbient);
_shader[SHADER_LIGHT]->FreeDescriptorSet(_cshLight);
renderer->DeleteFramebuffer(_fbhReflection);
renderer->DeleteFramebuffer(_fbhExtraCompose);
renderer->DeleteFramebuffer(_fbhForwardRendering);
renderer->DeleteFramebuffer(_fbhCompose);
renderer->DeleteFramebuffer(_fbhAO);
renderer->DeleteFramebuffer(_fbh);
_tex[TEX_COMPOSED_B].Done();
_tex[TEX_COMPOSED_A].Done();
_tex[TEX_LIGHT_ACC_SPEC].Done();
_tex[TEX_LIGHT_ACC_DIFF].Done();
_tex[TEX_LIGHT_ACC_SPECULAR].Done();
_tex[TEX_LIGHT_ACC_DIFFUSE].Done();
_tex[TEX_LIGHT_ACC_AMBIENT].Done();
_tex[TEX_GBUFFER_3].Done();
_tex[TEX_GBUFFER_2].Done();
_tex[TEX_GBUFFER_1].Done();
_tex[TEX_GBUFFER_0].Done();
@ -371,10 +389,12 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
texDesc._width = scaledSwapChainWidth;
texDesc._height = scaledSwapChainHeight;
texDesc._flags = TextureDesc::Flags::colorAttachment;
texDesc._name = "DeferredShading.LightAccDiff";
_tex[TEX_LIGHT_ACC_DIFF].Init(texDesc);
texDesc._name = "DeferredShading.LightAccSpec";
_tex[TEX_LIGHT_ACC_SPEC].Init(texDesc);
texDesc._name = "DeferredShading.LightAccAmbient";
_tex[TEX_LIGHT_ACC_AMBIENT].Init(texDesc);
texDesc._name = "DeferredShading.LightAccDiffuse";
_tex[TEX_LIGHT_ACC_DIFFUSE].Init(texDesc);
texDesc._name = "DeferredShading.LightAccSpecular";
_tex[TEX_LIGHT_ACC_SPECULAR].Init(texDesc);
texDesc._name = "DeferredShading.ComposedA";
_tex[TEX_COMPOSED_A].Init(texDesc);
texDesc._name = "DeferredShading.ComposedB";
@ -385,18 +405,21 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_LIGHT_ACC_DIFF],
_tex[TEX_LIGHT_ACC_SPEC],
_tex[TEX_GBUFFER_3],
_tex[TEX_LIGHT_ACC_AMBIENT],
_tex[TEX_LIGHT_ACC_DIFFUSE],
_tex[TEX_LIGHT_ACC_SPECULAR],
renderer.GetTexDepthStencil()
},
scaledSwapChainWidth, scaledSwapChainHeight);
_fbhCompose = renderer->CreateFramebuffer(_rphCompose,
{
_tex[TEX_COMPOSED_A],
_tex[TEX_COMPOSED_B]
_tex[TEX_COMPOSED_B],
_tex[TEX_GBUFFER_3]
},
scaledSwapChainWidth, scaledSwapChainHeight);
_fbhExtraCompose = renderer->CreateFramebuffer(_rphExtraCompose,
_fbhForwardRendering = renderer->CreateFramebuffer(_rphForwardRendering,
{
_tex[TEX_COMPOSED_A],
renderer.GetTexDepthStencil()
@ -414,14 +437,14 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
renderer.GetTexDepthStencil(),
_tex[TEX_LIGHT_ACC_DIFF],
_tex[TEX_LIGHT_ACC_SPEC]
_tex[TEX_LIGHT_ACC_AMBIENT],
_tex[TEX_LIGHT_ACC_DIFFUSE],
_tex[TEX_LIGHT_ACC_SPECULAR]
});
_cshReflection = _shader[SHADER_REFLECTION]->BindDescriptorSetTextures(1,
{
_tex[TEX_GBUFFER_0],
_tex[TEX_GBUFFER_2],
_tex[TEX_LIGHT_ACC_SPEC]
_tex[TEX_GBUFFER_1],
_tex[TEX_LIGHT_ACC_SPECULAR]
});
_cshToneMapping = _shader[SHADER_COMPOSE]->BindDescriptorSetTextures(1,
{
@ -429,15 +452,18 @@ void DeferredShading::OnSwapChainResized(bool init, bool done)
_tex[TEX_GBUFFER_1],
_tex[TEX_GBUFFER_2],
_tex[TEX_COMPOSED_A],
_tex[TEX_LIGHT_ACC_DIFF],
_tex[TEX_LIGHT_ACC_SPEC]
_tex[TEX_LIGHT_ACC_AMBIENT],
_tex[TEX_LIGHT_ACC_DIFFUSE],
_tex[TEX_LIGHT_ACC_SPECULAR]
});
VERUS_FOR(i, VERUS_COUNT_OF(_cshQuad))
_cshQuad[i] = renderer.GetShaderQuad()->BindDescriptorSetTextures(1, { _tex[TEX_GBUFFER_0 + i] });
if (_texShadowAtmo)
InitByAtmosphere(_texShadowAtmo);
if (_texAtmoShadow)
InitByAtmosphere(_texAtmoShadow);
InitByTerrain(_texTerrainHeightmap, _texTerrainBlend, _terrainMapSide);
}
}
@ -460,7 +486,11 @@ void DeferredShading::ResetInstanceCount()
dl.Get(LightType::spot).ResetInstanceCount();
}
void DeferredShading::Draw(int gbuffer)
void DeferredShading::Draw(int gbuffer,
RcVector4 rMultiplexer,
RcVector4 gMultiplexer,
RcVector4 bMultiplexer,
RcVector4 aMultiplexer)
{
VERUS_QREF_RENDERER;
@ -472,6 +502,10 @@ void DeferredShading::Draw(int gbuffer)
renderer.GetUbQuadVS()._matW = Math::QuadMatrix().UniformBufferFormat();
renderer.GetUbQuadVS()._matV = Math::ToUVMatrix().UniformBufferFormat();
renderer.GetUbQuadFS()._rMultiplexer = rMultiplexer.GLM();
renderer.GetUbQuadFS()._gMultiplexer = gMultiplexer.GLM();
renderer.GetUbQuadFS()._bMultiplexer = bMultiplexer.GLM();
renderer.GetUbQuadFS()._aMultiplexer = aMultiplexer.GLM();
cb->BindPipeline(_pipe[PIPE_QUAD]);
@ -491,16 +525,24 @@ void DeferredShading::Draw(int gbuffer)
cb->BindDescriptors(shader, 1, _cshQuad[2]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(w, h, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[3]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(0, 0, static_cast<float>(renderer.GetSwapChainWidth()), static_cast<float>(renderer.GetSwapChainHeight())) });
}
else if (-2 == gbuffer)
{
cb->SetViewport({ Vector4(0, 0, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[3]);
cb->BindDescriptors(shader, 1, _cshQuad[4]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(w, 0, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[4]);
cb->BindDescriptors(shader, 1, _cshQuad[5]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(0, h, w, h) });
cb->BindDescriptors(shader, 1, _cshQuad[6]);
renderer.DrawQuad(cb.Get());
cb->SetViewport({ Vector4(0, 0, static_cast<float>(renderer.GetSwapChainWidth()), static_cast<float>(renderer.GetSwapChainHeight())) });
@ -513,48 +555,67 @@ void DeferredShading::Draw(int gbuffer)
shader->EndBindDescriptors();
}
void DeferredShading::BeginGeometryPass(bool onlySetRT, bool spriteBaking)
void DeferredShading::BeginGeometryPass()
{
VERUS_QREF_RENDERER;
TexturePtr depth = nullptr;
if (onlySetRT)
{
}
else
{
VERUS_QREF_ATMO;
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass);
_activeGeometryPass = true;
_frame = renderer.GetFrameCount();
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
_activeGeometryPass = true;
_frame = renderer.GetFrameCount();
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh,
{
_tex[TEX_GBUFFER_0]->GetClearValue(),
_tex[TEX_GBUFFER_1]->GetClearValue(),
_tex[TEX_GBUFFER_2]->GetClearValue(),
_tex[TEX_LIGHT_ACC_DIFF]->GetClearValue(),
_tex[TEX_LIGHT_ACC_SPEC]->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
});
}
renderer.GetCommandBuffer()->BeginRenderPass(_rph, _fbh,
{
_tex[TEX_GBUFFER_0]->GetClearValue(),
_tex[TEX_GBUFFER_1]->GetClearValue(),
_tex[TEX_GBUFFER_2]->GetClearValue(),
_tex[TEX_GBUFFER_3]->GetClearValue(),
_tex[TEX_LIGHT_ACC_AMBIENT]->GetClearValue(),
_tex[TEX_LIGHT_ACC_DIFFUSE]->GetClearValue(),
_tex[TEX_LIGHT_ACC_SPECULAR]->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
});
}
void DeferredShading::EndGeometryPass(bool resetRT)
void DeferredShading::EndGeometryPass()
{
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(_activeGeometryPass && !_activeLightingPass);
VERUS_RT_ASSERT(_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
_activeGeometryPass = false;
}
bool DeferredShading::BeginLightingPass()
bool DeferredShading::BeginLightingPass(bool ambient, bool terrainOcclusion)
{
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass);
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
_activeLightingPass = true;
renderer.GetCommandBuffer()->NextSubpass();
auto cb = renderer.GetCommandBuffer();
cb->NextSubpass();
if (ambient)
{
VERUS_QREF_ATMO;
VERUS_QREF_SM;
s_ubAmbientVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubAmbientVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubAmbientFS._matInvV = sm.GetCamera()->GetMatrixInvV().UniformBufferFormat();
s_ubAmbientFS._matInvP = sm.GetCamera()->GetMatrixInvP().UniformBufferFormat();
s_ubAmbientFS._ambientColorY0 = float4(atmo.GetAmbientColorY0().GLM(), 0);
s_ubAmbientFS._ambientColorY1 = float4(atmo.GetAmbientColorY1().GLM(), 0);
s_ubAmbientFS._invMapSide_minOcclusion.x = 1.f / _terrainMapSide;
s_ubAmbientFS._invMapSide_minOcclusion.y = terrainOcclusion ? 0.f : 1.f;
cb->BindPipeline(_pipe[PIPE_AMBIENT]);
_shader[SHADER_AMBIENT]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_AMBIENT], 0);
cb->BindDescriptors(_shader[SHADER_AMBIENT], 1, _cshAmbient);
_shader[SHADER_AMBIENT]->EndBindDescriptors();
renderer.DrawQuad(cb.Get());
}
_shader[SHADER_LIGHT]->BeginBindDescriptors();
if (!IsLoaded())
@ -571,6 +632,10 @@ bool DeferredShading::BeginLightingPass()
PipelineDesc pipeDesc(dl.Get(LightType::dir).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedDir", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._colorAttachWriteMasks[1] = "rgb";
pipeDesc._colorAttachWriteMasks[2] = "rgb";
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
pipeDesc.DisableDepthTest();
_pipe[PIPE_INSTANCED_DIR].Init(pipeDesc);
@ -579,6 +644,10 @@ bool DeferredShading::BeginLightingPass()
PipelineDesc pipeDesc(dl.Get(LightType::omni).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedOmni", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._colorAttachWriteMasks[1] = "rgb";
pipeDesc._colorAttachWriteMasks[2] = "rgb";
pipeDesc._rasterizationState._cullMode = CullMode::front;
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
pipeDesc._depthCompareOp = CompareOp::greater;
@ -589,21 +658,16 @@ bool DeferredShading::BeginLightingPass()
PipelineDesc pipeDesc(dl.Get(LightType::spot).GetGeometry(), _shader[SHADER_LIGHT], "#InstancedSpot", _rph, 1);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_ADD;
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._colorAttachWriteMasks[1] = "rgb";
pipeDesc._colorAttachWriteMasks[2] = "rgb";
pipeDesc._rasterizationState._cullMode = CullMode::front;
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
pipeDesc._depthCompareOp = CompareOp::greater;
pipeDesc._depthWriteEnable = false;
_pipe[PIPE_INSTANCED_SPOT].Init(pipeDesc);
}
{
PipelineDesc pipeDesc(dl.Get(LightType::omni).GetGeometry(), _shader[SHADER_AO], "#InstancedOmni", _rphAO);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_MUL;
pipeDesc._rasterizationState._cullMode = CullMode::front;
pipeDesc._vertexInputBindingsFilter = (1 << 0) | (1 << 4);
pipeDesc._depthCompareOp = CompareOp::greater;
pipeDesc._depthWriteEnable = false;
_pipe[PIPE_INSTANCED_AO].Init(pipeDesc);
}
}
return true;
@ -613,42 +677,22 @@ void DeferredShading::EndLightingPass()
{
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(!_activeGeometryPass && _activeLightingPass);
VERUS_RT_ASSERT(!_activeGeometryPass && _activeLightingPass && !_activeForwardRendering);
_activeLightingPass = false;
_shader[SHADER_LIGHT]->EndBindDescriptors();
renderer.GetCommandBuffer()->EndRenderPass();
}
void DeferredShading::BeginAmbientOcclusion()
{
VERUS_QREF_RENDERER;
auto cb = renderer.GetCommandBuffer();
// Add more dark regions to SSAO buffer:
cb->BeginRenderPass(_rphAO, _fbhAO,
{
_texAO->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
});
_shader[SHADER_AO]->BeginBindDescriptors();
}
void DeferredShading::EndAmbientOcclusion()
{
VERUS_QREF_RENDERER;
_shader[SHADER_AO]->EndBindDescriptors();
renderer.GetCommandBuffer()->EndRenderPass();
}
void DeferredShading::BeginCompose(RcVector4 bgColor)
void DeferredShading::BeginComposeAndForwardRendering(bool underwaterMask)
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_ATMO;
VERUS_QREF_WATER;
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && !_activeForwardRendering);
_activeForwardRendering = true;
const Matrix4 matInvVP = VMath::inverse(sm.GetCamera()->GetMatrixVP());
@ -656,22 +700,21 @@ void DeferredShading::BeginCompose(RcVector4 bgColor)
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubComposeFS._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
s_ubComposeFS._matInvV = sm.GetCamera()->GetMatrixInvV().UniformBufferFormat();
s_ubComposeFS._matInvVP = matInvVP.UniformBufferFormat();
s_ubComposeFS._ambientColor_exposure = float4(atmo.GetAmbientColor().GLM(), renderer.GetExposure());
s_ubComposeFS._backgroundColor = bgColor.GLM();
s_ubComposeFS._exposure_underwaterMask.x = renderer.GetExposure();
s_ubComposeFS._exposure_underwaterMask.y = underwaterMask ? 1.f : 0.f;
s_ubComposeFS._backgroundColor = _backgroundColor.GLM();
s_ubComposeFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
s_ubComposeFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
s_ubComposeFS._waterDiffColorShallow = float4(water.GetDiffuseColorShallow().GLM(), water.GetFogDensity());
s_ubComposeFS._waterDiffColorDeep = float4(water.GetDiffuseColorDeep().GLM(), water.IsUnderwater() ? 1.f : 0.f);
s_ubComposeFS._lightGlossScale.x = _lightGlossScale;
// Compose buffers, that is perform "final color = albedo * diffuse + specular" computation. Result is still HDR:
cb->BeginRenderPass(_rphCompose, _fbhCompose,
{
_tex[TEX_COMPOSED_A]->GetClearValue(),
_tex[TEX_COMPOSED_B]->GetClearValue()
_tex[TEX_COMPOSED_B]->GetClearValue(),
_tex[TEX_GBUFFER_3]->GetClearValue()
});
cb->BindPipeline(_pipe[PIPE_COMPOSE]);
@ -684,16 +727,19 @@ void DeferredShading::BeginCompose(RcVector4 bgColor)
cb->EndRenderPass();
// Begin drawing extra stuff, which is not using deferred shading, for example water (updates depth buffer) and sky:
cb->BeginRenderPass(_rphExtraCompose, _fbhExtraCompose,
cb->BeginRenderPass(_rphForwardRendering, _fbhForwardRendering,
{
_tex[TEX_COMPOSED_A]->GetClearValue(),
renderer.GetTexDepthStencil()->GetClearValue()
});
}
void DeferredShading::EndCompose()
void DeferredShading::EndComposeAndForwardRendering()
{
VERUS_QREF_RENDERER;
VERUS_RT_ASSERT(renderer.GetFrameCount() == _frame);
VERUS_RT_ASSERT(!_activeGeometryPass && !_activeLightingPass && _activeForwardRendering);
_activeForwardRendering = false;
renderer.GetCommandBuffer()->EndRenderPass();
}
@ -701,6 +747,7 @@ void DeferredShading::EndCompose()
void DeferredShading::DrawReflection()
{
VERUS_QREF_RENDERER;
VERUS_QREF_SSR;
auto cb = renderer.GetCommandBuffer();
@ -709,7 +756,7 @@ void DeferredShading::DrawReflection()
cb->BeginRenderPass(_rphReflection, _fbhReflection, { _tex[TEX_COMPOSED_A]->GetClearValue() });
cb->BindPipeline(_pipe[PIPE_REFLECTION]);
cb->BindPipeline(ssr.IsCubeMapDebugMode() ? _pipe[PIPE_REFLECTION_DEBUG] : _pipe[PIPE_REFLECTION]);
_shader[SHADER_REFLECTION]->BeginBindDescriptors();
cb->BindDescriptors(_shader[SHADER_REFLECTION], 0);
cb->BindDescriptors(_shader[SHADER_REFLECTION], 1, _cshReflection);
@ -722,17 +769,12 @@ void DeferredShading::DrawReflection()
void DeferredShading::ToneMapping()
{
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_ATMO;
auto cb = renderer.GetCommandBuffer();
s_ubComposeVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubComposeVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubComposeFS._matInvV = sm.GetCamera()->GetMatrixInvV().UniformBufferFormat();
s_ubComposeFS._ambientColor_exposure = float4(atmo.GetAmbientColor().GLM(), renderer.GetExposure());
s_ubComposeFS._fogColor = Vector4(0.5f, 0.5f, 0.5f, 0.002f).GLM();
s_ubComposeFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
s_ubComposeFS._exposure_underwaterMask.x = renderer.GetExposure();
// Convert HDR image to SDR. First multiply by exposure, then apply tone mapping curve:
cb->BindPipeline(_pipe[PIPE_TONE_MAPPING]);
@ -756,12 +798,11 @@ void DeferredShading::OnNewLightType(CommandBufferPtr cb, LightType type, bool w
VERUS_QREF_ATMO;
VERUS_QREF_SM;
s_ubPerFrame._matQuad = Math::QuadMatrix().UniformBufferFormat();
s_ubPerFrame._matToUV = Math::ToUVMatrix().UniformBufferFormat();
s_ubPerFrame._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
s_ubPerFrame._matInvV = sm.GetCamera()->GetMatrixInvV().UniformBufferFormat();
s_ubPerFrame._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubPerFrame._matInvP = Matrix4(VMath::inverse(sm.GetCamera()->GetMatrixP())).UniformBufferFormat();
s_ubPerFrame._toUV = float4(0, 0, 0, 0);
s_ubPerFrame._matInvP = sm.GetCamera()->GetMatrixInvP().UniformBufferFormat();
switch (type)
{
@ -801,33 +842,6 @@ void DeferredShading::BindDescriptorsPerMeshVS(CommandBufferPtr cb)
cb->BindDescriptors(_shader[SHADER_LIGHT], 2);
}
void DeferredShading::OnNewAOType(CommandBufferPtr cb, LightType type)
{
VERUS_QREF_SM;
s_ubAOPerFrame._matToUV = Math::ToUVMatrix().UniformBufferFormat();
s_ubAOPerFrame._matV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
s_ubAOPerFrame._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubAOPerFrame._matInvP = Matrix4(VMath::inverse(sm.GetCamera()->GetMatrixP())).UniformBufferFormat();
switch (type)
{
case LightType::omni:
{
cb->BindPipeline(_pipe[PIPE_INSTANCED_AO]);
}
break;
}
cb->BindDescriptors(_shader[SHADER_AO], 0);
cb->BindDescriptors(_shader[SHADER_AO], 1, _cshAO);
}
void DeferredShading::BindDescriptorsAOPerMeshVS(CommandBufferPtr cb)
{
cb->BindDescriptors(_shader[SHADER_AO], 2);
}
void DeferredShading::Load()
{
VERUS_QREF_HELPERS;
@ -851,14 +865,19 @@ TexturePtr DeferredShading::GetGBuffer(int index)
return _tex[index];
}
TexturePtr DeferredShading::GetLightAccDiffTexture()
TexturePtr DeferredShading::GetLightAccAmbientTexture()
{
return _tex[TEX_LIGHT_ACC_DIFF];
return _tex[TEX_LIGHT_ACC_AMBIENT];
}
TexturePtr DeferredShading::GetLightAccSpecTexture()
TexturePtr DeferredShading::GetLightAccDiffuseTexture()
{
return _tex[TEX_LIGHT_ACC_SPEC];
return _tex[TEX_LIGHT_ACC_DIFFUSE];
}
TexturePtr DeferredShading::GetLightAccSpecularTexture()
{
return _tex[TEX_LIGHT_ACC_SPECULAR];
}
TexturePtr DeferredShading::GetComposedTextureA()
@ -871,22 +890,27 @@ TexturePtr DeferredShading::GetComposedTextureB()
return _tex[TEX_COMPOSED_B];
}
Vector4 DeferredShading::GetClearValueForGBuffer0()
Vector4 DeferredShading::GetClearValueForGBuffer0(float albedo)
{
return Vector4(0.5f, 0.5f, 0.5f, 0.25f);
return Vector4(albedo, albedo, albedo, 0.5f);
}
Vector4 DeferredShading::GetClearValueForGBuffer1()
Vector4 DeferredShading::GetClearValueForGBuffer1(float normal, float motionBlur)
{
return Vector4(0.5f, 0.5f, 0.25f);
return Vector4(normal, normal, 0, motionBlur);
}
Vector4 DeferredShading::GetClearValueForGBuffer2()
Vector4 DeferredShading::GetClearValueForGBuffer2(float roughness)
{
return Vector4(0.125f, 0.5f, 0.5f, 0.125f);
return Vector4(1, roughness, 0, 0);
}
void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBufferOut[3], PBaseCommandBuffer pCB)
Vector4 DeferredShading::GetClearValueForGBuffer3(float tangent)
{
return Vector4(tangent, tangent, 0, 0);
}
void DeferredShading::BakeSprites(TexturePtr texGBufferIn[4], TexturePtr texGBufferOut[4], PBaseCommandBuffer pCB)
{
VERUS_QREF_RENDERER;
@ -902,13 +926,15 @@ void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBuf
RP::Attachment("GBuffer0", Format::srgbR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer1", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer2", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly),
RP::Attachment("GBuffer3", Format::unormR8G8B8A8).LoadOpClear().Layout(ImageLayout::fsReadOnly)
},
{
RP::Subpass("Sp0").Color(
{
RP::Ref("GBuffer0", ImageLayout::colorAttachment),
RP::Ref("GBuffer1", ImageLayout::colorAttachment),
RP::Ref("GBuffer2", ImageLayout::colorAttachment)
RP::Ref("GBuffer2", ImageLayout::colorAttachment),
RP::Ref("GBuffer3", ImageLayout::colorAttachment)
})
},
{});
@ -917,7 +943,8 @@ void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBuf
{
texGBufferOut[0],
texGBufferOut[1],
texGBufferOut[2]
texGBufferOut[2],
texGBufferOut[3]
},
w, h);
@ -925,7 +952,8 @@ void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBuf
{
texGBufferIn[0],
texGBufferIn[1],
texGBufferIn[2]
texGBufferIn[2],
texGBufferIn[3]
});
{
@ -933,6 +961,7 @@ void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBuf
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
pipeDesc._topology = PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_BAKE_SPRITES].Init(pipeDesc);
@ -945,7 +974,8 @@ void DeferredShading::BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBuf
{
texGBufferOut[0]->GetClearValue(),
texGBufferOut[1]->GetClearValue(),
texGBufferOut[2]->GetClearValue()
texGBufferOut[2]->GetClearValue(),
texGBufferOut[3]->GetClearValue()
});
pCB->BindPipeline(_pipe[PIPE_BAKE_SPRITES]);

View File

@ -16,7 +16,7 @@ namespace verus
class DeferredShading : public Object
{
#include "../Shaders/DS.inc.hlsl"
#include "../Shaders/DS_AO.inc.hlsl"
#include "../Shaders/DS_Ambient.inc.hlsl"
#include "../Shaders/DS_Compose.inc.hlsl"
#include "../Shaders/DS_Reflection.inc.hlsl"
#include "../Shaders/DS_BakeSprites.inc.hlsl"
@ -24,7 +24,7 @@ namespace verus
enum SHADER
{
SHADER_LIGHT,
SHADER_AO,
SHADER_AMBIENT,
SHADER_COMPOSE,
SHADER_REFLECTION,
SHADER_BAKE_SPRITES,
@ -36,9 +36,10 @@ namespace verus
PIPE_INSTANCED_DIR,
PIPE_INSTANCED_OMNI,
PIPE_INSTANCED_SPOT,
PIPE_INSTANCED_AO,
PIPE_AMBIENT,
PIPE_COMPOSE,
PIPE_REFLECTION,
PIPE_REFLECTION_DEBUG,
PIPE_TONE_MAPPING,
PIPE_QUAD,
PIPE_BAKE_SPRITES,
@ -47,13 +48,18 @@ namespace verus
enum TEX
{
TEX_GBUFFER_0, // Albedo, Spec.
TEX_GBUFFER_1, // RG - Normals, Emission, Motion.
TEX_GBUFFER_2, // LamScale, LamBias, Metallicity, Gloss.
TEX_LIGHT_ACC_DIFF,
TEX_LIGHT_ACC_SPEC,
TEX_GBUFFER_0, // {Albedo.rgb, SSSHue}.
TEX_GBUFFER_1, // {Normal.xy, Emission, MotionBlur}.
TEX_GBUFFER_2, // {Occlusion, Roughness, Metallic, WrapDiffuse}.
TEX_GBUFFER_3, // {Tangent.xy, AnisoSpec, RoughDiffuse}.
TEX_LIGHT_ACC_AMBIENT,
TEX_LIGHT_ACC_DIFFUSE,
TEX_LIGHT_ACC_SPECULAR,
TEX_COMPOSED_A,
TEX_COMPOSED_B,
TEX_COUNT
};
@ -63,10 +69,8 @@ namespace verus
static UB_ShadowFS s_ubShadowFS;
static UB_PerObject s_ubPerObject;
static UB_AOPerFrame s_ubAOPerFrame;
static UB_AOTexturesFS s_ubAOTexturesFS;
static UB_AOPerMeshVS s_ubAOPerMeshVS;
static UB_AOPerObject s_ubAOPerObject;
static UB_AmbientVS s_ubAmbientVS;
static UB_AmbientFS s_ubAmbientFS;
static UB_ComposeVS s_ubComposeVS;
static UB_ComposeFS s_ubComposeFS;
@ -77,38 +81,40 @@ namespace verus
static UB_BakeSpritesVS s_ubBakeSpritesVS;
static UB_BakeSpritesFS s_ubBakeSpritesFS;
Vector4 _backgroundColor = Vector4(0);
ShaderPwns<SHADER_COUNT> _shader;
PipelinePwns<PIPE_COUNT> _pipe;
TexturePwns<TEX_COUNT> _tex;
TexturePtr _texShadowAtmo;
TexturePtr _texAO;
TexturePtr _texAtmoShadow;
TexturePtr _texTerrainHeightmap;
TexturePtr _texTerrainBlend;
UINT64 _frame = 0;
RPHandle _rph;
RPHandle _rphAO;
RPHandle _rphCompose;
RPHandle _rphExtraCompose;
RPHandle _rphForwardRendering;
RPHandle _rphReflection;
RPHandle _rphBakeSprites;
FBHandle _fbh;
FBHandle _fbhAO;
FBHandle _fbhCompose;
FBHandle _fbhExtraCompose;
FBHandle _fbhForwardRendering;
FBHandle _fbhReflection;
FBHandle _fbhBakeSprites;
CSHandle _cshLight;
CSHandle _cshAO;
CSHandle _cshAmbient;
CSHandle _cshCompose;
CSHandle _cshReflection;
CSHandle _cshToneMapping;
CSHandle _cshQuad[5];
CSHandle _cshQuad[7];
CSHandle _cshBakeSprites;
float _lightGlossScale = 1;
int _terrainMapSide = 1;
bool _activeGeometryPass = false;
bool _activeLightingPass = false;
bool _activeForwardRendering = false;
bool _async_initPipe = false;
public:
@ -119,7 +125,8 @@ namespace verus
void InitGBuffers(int w, int h);
void InitByAtmosphere(TexturePtr texShadow);
void InitByBloom(TexturePtr tex);
void InitBySsao(TexturePtr tex);
void InitByTerrain(TexturePtr texHeightmap, TexturePtr texBlend, int mapSide);
void Done();
void OnSwapChainResized(bool init, bool done);
@ -127,52 +134,52 @@ namespace verus
static bool IsLoaded();
void ResetInstanceCount();
void Draw(int gbuffer);
bool IsActiveGeometryPass() const { return _activeGeometryPass; }
bool IsActiveLightingPass() const { return _activeLightingPass; }
void Draw(int gbuffer,
RcVector4 rMultiplexer = Vector4(1, 0, 0, 0),
RcVector4 gMultiplexer = Vector4(0, 1, 0, 0),
RcVector4 bMultiplexer = Vector4(0, 0, 1, 0),
RcVector4 aMultiplexer = Vector4(0, 0, 0, 1));
RPHandle GetRenderPassHandle() const { return _rph; }
RPHandle GetRenderPassHandle_ExtraCompose() const { return _rphExtraCompose; }
RPHandle GetRenderPassHandle_ForwardRendering() const { return _rphForwardRendering; }
void BeginGeometryPass(bool onlySetRT = false, bool spriteBaking = false);
void EndGeometryPass(bool resetRT = false);
bool BeginLightingPass();
// Steps:
void BeginGeometryPass();
void EndGeometryPass();
bool BeginLightingPass(bool ambient = true, bool terrainOcclusion = true);
void EndLightingPass();
void BeginAmbientOcclusion();
void EndAmbientOcclusion();
void BeginCompose(RcVector4 bgColor = Vector4(0));
void EndCompose();
void BeginComposeAndForwardRendering(bool underwaterMask = true);
void EndComposeAndForwardRendering();
void DrawReflection();
void ToneMapping();
bool IsActiveGeometryPass() const { return _activeGeometryPass; }
bool IsActiveLightingPass() const { return _activeLightingPass; }
bool IsActiveForwardRendering() const { return _activeForwardRendering; }
// Lighting:
static bool IsLightUrl(CSZ url);
void OnNewLightType(CommandBufferPtr cb, LightType type, bool wireframe = false);
void BindDescriptorsPerMeshVS(CommandBufferPtr cb);
static UB_PerMeshVS& GetUbPerMeshVS() { return s_ubPerMeshVS; }
void OnNewAOType(CommandBufferPtr cb, LightType type);
void BindDescriptorsAOPerMeshVS(CommandBufferPtr cb);
static UB_AOPerMeshVS& GetUbAOPerMeshVS() { return s_ubAOPerMeshVS; }
void Load();
TexturePtr GetGBuffer(int index);
TexturePtr GetLightAccDiffTexture();
TexturePtr GetLightAccSpecTexture();
TexturePtr GetLightAccAmbientTexture();
TexturePtr GetLightAccDiffuseTexture();
TexturePtr GetLightAccSpecularTexture();
TexturePtr GetComposedTextureA();
TexturePtr GetComposedTextureB();
static Vector4 GetClearValueForGBuffer0();
static Vector4 GetClearValueForGBuffer1();
static Vector4 GetClearValueForGBuffer2();
static Vector4 GetClearValueForGBuffer0(float albedo = 0);
static Vector4 GetClearValueForGBuffer1(float normal = 0, float motionBlur = 1);
static Vector4 GetClearValueForGBuffer2(float roughness = 0);
static Vector4 GetClearValueForGBuffer3(float tangent = 0);
void BakeSprites(TexturePtr texGBufferIn[3], TexturePtr texGBufferOut[3], PBaseCommandBuffer pCB = nullptr);
void SetBackgroundColor(RcVector4 backgroundColor) { _backgroundColor = backgroundColor; }
void BakeSprites(TexturePtr texGBufferIn[4], TexturePtr texGBufferOut[4], PBaseCommandBuffer pCB = nullptr);
void BakeSpritesCleanup();
// For Editor:
float GetLightGlossScale() const { return _lightGlossScale; }
void SetLightGlossScale(float s) { _lightGlossScale = s; }
};
VERUS_TYPEDEFS(DeferredShading);
}

View File

@ -37,14 +37,18 @@ namespace verus
floatD32,
// Compressed Texture Formats:
unormBC1,
unormBC2,
unormBC3,
unormBC7,
srgbBC1,
srgbBC2,
srgbBC3,
srgbBC7
unormBC1, // Deprecated RGBA.
unormBC2, // Deprecated RGBA.
unormBC3, // Deprecated RGBA.
unormBC4, // R.
unormBC5, // RG.
unormBC7, // RGBA.
snormBC4, // R.
snormBC5, // RG.
srgbBC1, // Deprecated RGBA.
srgbBC2, // Deprecated RGBA.
srgbBC3, // Deprecated RGBA.
srgbBC7 // RGBA.
};
}
}

View File

@ -119,15 +119,29 @@ void Renderer::Init(PRendererDelegate pDelegate, bool allowInitShaders)
_shader[SHADER_GENERATE_MIPS].Init("[Shaders]:GenerateMips.hlsl");
_shader[SHADER_GENERATE_MIPS]->CreateDescriptorSet(0, &_ubGenerateMips, sizeof(_ubGenerateMips), settings.GetLimits()._generateMips_ubCapacity,
{
Sampler::linearClampMipN,
Sampler::storage,
Sampler::storage,
Sampler::storage,
Sampler::storage
Sampler::linearClampMipN, // Texture
Sampler::storage, // Mip N
Sampler::storage, // Mip N+1
Sampler::storage, // Mip N+2
Sampler::storage // Mip N+3
},
ShaderStageFlags::cs);
_shader[SHADER_GENERATE_MIPS]->CreatePipelineLayout();
_shader[SHADER_GENERATE_CUBE_MAP_MIPS].Init("[Shaders]:GenerateCubeMapMips.hlsl");
_shader[SHADER_GENERATE_CUBE_MAP_MIPS]->CreateDescriptorSet(0, &_ubGenerateCubeMapMips, sizeof(_ubGenerateCubeMapMips), settings.GetLimits()._generateCubeMapMips_ubCapacity,
{
Sampler::linearMipN, // CubeMap
Sampler::storage, // Face +X
Sampler::storage, // Face -X
Sampler::storage, // Face +Y
Sampler::storage, // Face -Y
Sampler::storage, // Face +Z
Sampler::storage // Face -Z
},
ShaderStageFlags::cs);
_shader[SHADER_GENERATE_CUBE_MAP_MIPS]->CreatePipelineLayout();
_shader[SHADER_QUAD].Init("[Shaders]:Quad.hlsl");
_shader[SHADER_QUAD]->CreateDescriptorSet(0, &_ubQuadVS, sizeof(_ubQuadVS), settings.GetLimits()._quad_ubVSCapacity, {}, ShaderStageFlags::vs);
_shader[SHADER_QUAD]->CreateDescriptorSet(1, &_ubQuadFS, sizeof(_ubQuadFS), settings.GetLimits()._quad_ubFSCapacity, { Sampler::linearClampMipN }, ShaderStageFlags::fs);
@ -144,6 +158,11 @@ void Renderer::Init(PRendererDelegate pDelegate, bool allowInitShaders)
PipelineDesc pipeDesc(_shader[SHADER_GENERATE_MIPS], "#Exposure");
_pipe[PIPE_GENERATE_MIPS_EXPOSURE].Init(pipeDesc);
}
if (_allowInitShaders)
{
PipelineDesc pipeDesc(_shader[SHADER_GENERATE_CUBE_MAP_MIPS], "#");
_pipe[PIPE_GENERATE_CUBE_MAP_MIPS].Init(pipeDesc);
}
if (settings._displayOffscreenDraw)
{
PipelineDesc pipeDesc(_geoQuad, _shader[SHADER_QUAD], "#", _rphSwapChainWithDepth);
@ -158,7 +177,9 @@ void Renderer::Init(PRendererDelegate pDelegate, bool allowInitShaders)
ImGuiUpdateStyle();
if (_allowInitShaders)
{
_ds.Init();
}
SetExposureValue(15);
}
@ -225,18 +246,18 @@ void Renderer::Update()
const float alpha = Math::Max(0.001f, floatColor[3]);
const float actual = gray.r;
const float expScale = Math::Clamp(_exposure[1] * (1 / 15.f), 0.f, 1.f);
const float target = -0.3f + 0.6f * expScale * expScale; // Dark scene exposure compensation.
const float expScale = Math::Clamp(_exposure[1] * (1 / 16.f), 0.f, 1.f);
const float target = -0.2f + 0.6f * expScale * expScale; // Dark scene exposure compensation.
const float important = (actual - 0.5f * (1 - alpha)) / alpha;
const float delta = abs(target - important);
const float speed = delta * sqrt(delta) * 15;
const float delta = target - important;
const float speed = (delta * delta) * ((delta > 0) ? 5.f : 15.f);
if (important < target * 0.95f)
if (important < target * 0.99f)
_exposure[1] -= speed * dt;
else if (important > target * (1 / 0.95f))
else if (important > target * (1 / 0.99f))
_exposure[1] += speed * dt;
_exposure[1] = Math::Clamp(_exposure[1], 0.f, 15.f);
_exposure[1] = Math::Clamp(_exposure[1], 0.f, 16.f);
SetExposureValue(_exposure[1]);
}
}
@ -386,6 +407,7 @@ void Renderer::DrawOffscreenColor(PBaseCommandBuffer pCB, bool endRenderPass)
_ubQuadVS._matW = Math::QuadMatrix().UniformBufferFormat();
_ubQuadVS._matV = Math::ToUVMatrix().UniformBufferFormat();
ResetQuadMultiplexer();
pCB->BeginRenderPass(_rphSwapChainWithDepth, _fbhSwapChainWithDepth[_pBaseRenderer->GetSwapChainBufferIndex()], { Vector4(0), Vector4(1) });
@ -602,16 +624,31 @@ ShaderPtr Renderer::GetShaderGenerateMips() const
return _shader[SHADER_GENERATE_MIPS];
}
ShaderPtr Renderer::GetShaderGenerateCubeMapMips() const
{
return _shader[SHADER_GENERATE_CUBE_MAP_MIPS];
}
PipelinePtr Renderer::GetPipelineGenerateMips(bool exposure) const
{
return _pipe[exposure ? PIPE_GENERATE_MIPS_EXPOSURE : PIPE_GENERATE_MIPS];
}
PipelinePtr Renderer::GetPipelineGenerateCubeMapMips() const
{
return _pipe[PIPE_GENERATE_CUBE_MAP_MIPS];
}
Renderer::UB_GenerateMips& Renderer::GetUbGenerateMips()
{
return _ubGenerateMips;
}
Renderer::UB_GenerateCubeMapMips& Renderer::GetUbGenerateCubeMapMips()
{
return _ubGenerateCubeMapMips;
}
GeometryPtr Renderer::GetGeoQuad() const
{
return _geoQuad;
@ -632,10 +669,18 @@ Renderer::UB_QuadFS& Renderer::GetUbQuadFS()
return _ubQuadFS;
}
void Renderer::ResetQuadMultiplexer()
{
_ubQuadFS._rMultiplexer = float4(1, 0, 0, 0);
_ubQuadFS._gMultiplexer = float4(0, 1, 0, 0);
_ubQuadFS._bMultiplexer = float4(0, 0, 1, 0);
_ubQuadFS._aMultiplexer = float4(0, 0, 0, 1);
}
void Renderer::SetExposureValue(float ev)
{
_exposure[1] = ev;
_exposure[0] = 1.f / exp2(_exposure[1] - 1);
_exposure[0] = 1.f / exp2(_exposure[1]);
}
void Renderer::UpdateUtilization()

View File

@ -17,11 +17,13 @@ namespace verus
class Renderer : public Singleton<Renderer>, public Object
{
#include "../Shaders/GenerateMips.inc.hlsl"
#include "../Shaders/GenerateCubeMapMips.inc.hlsl"
#include "../Shaders/Quad.inc.hlsl"
enum SHADER
{
SHADER_GENERATE_MIPS,
SHADER_GENERATE_CUBE_MAP_MIPS,
SHADER_QUAD,
SHADER_COUNT
};
@ -30,6 +32,7 @@ namespace verus
{
PIPE_GENERATE_MIPS,
PIPE_GENERATE_MIPS_EXPOSURE,
PIPE_GENERATE_CUBE_MAP_MIPS,
PIPE_OFFSCREEN_COLOR,
PIPE_COUNT
};
@ -82,6 +85,7 @@ namespace verus
FBHandle _fbhOffscreenWithDepth;
CSHandle _cshOffscreenColor;
UB_GenerateMips _ubGenerateMips;
UB_GenerateCubeMapMips _ubGenerateCubeMapMips;
UB_QuadVS _ubQuadVS;
UB_QuadFS _ubQuadFS;
bool _autoExposure = true;
@ -152,14 +156,18 @@ namespace verus
// Generate mips:
ShaderPtr GetShaderGenerateMips() const;
ShaderPtr GetShaderGenerateCubeMapMips() const;
PipelinePtr GetPipelineGenerateMips(bool exposure = false) const;
PipelinePtr GetPipelineGenerateCubeMapMips() const;
UB_GenerateMips& GetUbGenerateMips();
UB_GenerateCubeMapMips& GetUbGenerateCubeMapMips();
// Quad:
GeometryPtr GetGeoQuad() const;
ShaderPtr GetShaderQuad() const;
UB_QuadVS& GetUbQuadVS();
UB_QuadFS& GetUbQuadFS();
void ResetQuadMultiplexer();
// Exposure:
bool IsAutoExposureEnabled() const { return _autoExposure; }

View File

@ -26,7 +26,7 @@ namespace verus
posZ,
negZ,
count,
all,
all, // Match texture index to cube map face when creating framebuffer.
none = -1
};
@ -130,8 +130,9 @@ namespace verus
enum class ViaType : int
{
floats,
ubytes,
shorts
halfs,
shorts,
ubytes
};
// See: https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3ddeclusage

View File

@ -6,12 +6,16 @@ using namespace verus::D;
void Log::Write(CSZ txt, std::thread::id tid, CSZ filename, UINT32 line, Severity severity)
{
if (strstr(txt, "VUID-StandaloneSpirv-Offset-04663"))
if (strstr(txt, "UNASSIGNED-BestPractices-TransitionUndefinedToReadOnly"))
return;
if (strstr(txt, "UNASSIGNED-BestPractices-vkAllocateMemory-small-allocation"))
return;
if (strstr(txt, "UNASSIGNED-BestPractices-vkBindMemory-small-dedicated-allocation"))
return;
if (strstr(txt, "UNASSIGNED-BestPractices-vkCreateDevice-physical-device-features-not-retrieved"))
return;
if (strstr(txt, "UNASSIGNED-BestPractices-vkCreateInstance-specialuse-extension-debugging"))
return;
if (strstr(txt, "UNASSIGNED-CoreValidation-Shader-InconsistentSpirv"))
return;
if (strstr(txt, "UNASSIGNED-CoreValidation-Shader-OutputNotConsumed"))

View File

@ -139,10 +139,10 @@ void Bloom::Generate()
{
ImGui::DragFloat("Bloom colorScale", &_colorScale, 0.01f);
ImGui::DragFloat("Bloom colorBias", &_colorBias, 0.01f);
ImGui::DragFloat("Bloom (god rays) maxDist", &_maxDist, 0.1f);
ImGui::DragFloat("Bloom (god rays) sunGloss", &_sunGloss, 0.1f);
ImGui::DragFloat("Bloom (god rays) wideStrength", &_wideStrength, 0.01f);
ImGui::DragFloat("Bloom (god rays) sunStrength", &_sunStrength, 0.01f);
ImGui::DragFloat("Bloom (light shafts) maxDist", &_maxDist, 0.1f);
ImGui::DragFloat("Bloom (light shafts) sunGloss", &_sunGloss, 0.1f);
ImGui::DragFloat("Bloom (light shafts) wideStrength", &_wideStrength, 0.01f);
ImGui::DragFloat("Bloom (light shafts) sunStrength", &_sunStrength, 0.01f);
ImGui::Checkbox("Bloom blur", &_blur);
ImGui::Checkbox("Bloom (light shafts) blur", &_blurLightShafts);
}
@ -151,9 +151,9 @@ void Bloom::Generate()
s_ubBloomVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubBloomVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubBloomFS._exposure.x = renderer.GetExposure();
s_ubBloomFS._colorScale_colorBias.x = _colorScale;
s_ubBloomFS._colorScale_colorBias.y = _colorBias;
s_ubBloomFS._colorScale_colorBias_exposure.x = _colorScale;
s_ubBloomFS._colorScale_colorBias_exposure.y = _colorBias;
s_ubBloomFS._colorScale_colorBias_exposure.z = renderer.GetExposure();
cb->BeginRenderPass(_rph, _fbh, { _tex[TEX_PING]->GetClearValue() });

View File

@ -36,8 +36,8 @@ namespace verus
CGI::FBHandle _fbh;
CGI::CSHandle _csh;
CGI::CSHandle _cshLightShafts;
float _colorScale = 0.8f;
float _colorBias = 1.1f;
float _colorScale = 0.7f;
float _colorBias = 1.4f;
float _maxDist = 20;
float _sunGloss = 128;
float _wideStrength = 0.2f;

View File

@ -48,28 +48,26 @@ void Blur::Init()
VERUS_QREF_RENDERER;
Vector<CSZ> vIgnoreList;
if (settings._postProcessBloom)
if (settings._postProcessSSAO)
{
_bloomHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
_bloomHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
_rphSsao = renderer->CreateSimpleRenderPass(CGI::Format::unormR8G8B8A8); // >> GBuffer2.r
}
else
{
vIgnoreList.push_back("#Ssao");
}
{
_rdsHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
_rdsHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
}
{
_dofHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
_dofHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
}
if (settings._postProcessSSAO)
if (settings._postProcessBloom)
{
_ssaoHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
_ssaoHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::unormR8);
}
else
{
vIgnoreList.push_back("#USsao");
vIgnoreList.push_back("#VSsao");
}
{
_ssrHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
_ssrHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
_bloomHandles._rphU = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
_bloomHandles._rphV = renderer->CreateSimpleRenderPass(CGI::Format::srgbR8G8B8A8);
}
_rphAntiAliasing = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
_rphMotionBlur = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
@ -101,9 +99,39 @@ void Blur::Init()
pipeDesc._shaderBranch = "#V";
_pipe[PIPE_V].Init(pipeDesc);
}
if (settings._postProcessSSAO)
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#Ssao", _rphSsao);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_MIN;
pipeDesc._colorAttachWriteMasks[0] = "r"; // >> GBuffer2.r
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_SSAO].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#ResolveDithering", _rdsHandles._rphU);
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_RESOLVE_DITHERING].Init(pipeDesc);
pipeDesc._shaderBranch = "#Sharpen";
pipeDesc._renderPassHandle = _rdsHandles._rphV;
_pipe[PIPE_SHARPEN].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#UDoF", _dofHandles._rphU);
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_DOF_U].Init(pipeDesc);
pipeDesc._shaderBranch = "#VDoF";
pipeDesc._renderPassHandle = _dofHandles._rphV;
_pipe[PIPE_DOF_V].Init(pipeDesc);
}
if (settings._postProcessBloom)
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#U", _bloomHandles._rphU);
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_BLOOM_U].Init(pipeDesc);
@ -111,44 +139,16 @@ void Blur::Init()
pipeDesc._renderPassHandle = _bloomHandles._rphV;
_pipe[PIPE_BLOOM_V].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#UDoF", _dofHandles._rphU);
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_DOF_U].Init(pipeDesc);
pipeDesc._shaderBranch = "#VDoF";
pipeDesc._renderPassHandle = _dofHandles._rphV;
_pipe[PIPE_DOF_V].Init(pipeDesc);
}
if (settings._postProcessSSAO)
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#USsao", _ssaoHandles._rphU);
pipeDesc._colorAttachWriteMasks[0] = "a";
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_SSAO_U].Init(pipeDesc);
pipeDesc._shaderBranch = "#VSsao";
pipeDesc._colorAttachWriteMasks[0] = "rgba";
pipeDesc._renderPassHandle = _ssaoHandles._rphV;
_pipe[PIPE_SSAO_V].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#USsr", _ssrHandles._rphU);
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_SSR_U].Init(pipeDesc);
pipeDesc._shaderBranch = "#VSsr";
pipeDesc._renderPassHandle = _ssrHandles._rphV;
_pipe[PIPE_SSR_V].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#AntiAliasing", _rphAntiAliasing);
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_AA].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#Motion", _rphMotionBlur);
pipeDesc._colorAttachWriteMasks[0] = "rgb";
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_MOTION_BLUR].Init(pipeDesc);
@ -160,18 +160,25 @@ void Blur::Init()
void Blur::Done()
{
VERUS_QREF_RENDERER;
renderer->DeleteFramebuffer(_fbhMotionBlur);
renderer->DeleteRenderPass(_rphMotionBlur);
renderer->DeleteFramebuffer(_fbhAntiAliasing);
renderer->DeleteRenderPass(_rphAntiAliasing);
_ssrHandles.DeleteFramebuffers();
_ssrHandles.DeleteRenderPasses();
_ssaoHandles.DeleteFramebuffers();
_ssaoHandles.DeleteRenderPasses();
_dofHandles.DeleteFramebuffers();
_dofHandles.DeleteRenderPasses();
_bloomHandles.DeleteFramebuffers();
_bloomHandles.DeleteRenderPasses();
_dofHandles.DeleteFramebuffers();
_dofHandles.DeleteRenderPasses();
_rdsHandles.DeleteFramebuffers();
_rdsHandles.DeleteRenderPasses();
renderer->DeleteFramebuffer(_fbhSsao);
renderer->DeleteRenderPass(_rphSsao);
VERUS_DONE(Blur);
}
@ -183,7 +190,6 @@ void Blur::OnSwapChainResized()
VERUS_QREF_BLOOM;
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
VERUS_QREF_SSAO;
{
_shader->FreeDescriptorSet(_cshMotionBlurExtra);
@ -194,21 +200,19 @@ void Blur::OnSwapChainResized()
_shader->FreeDescriptorSet(_cshAntiAliasing);
renderer->DeleteFramebuffer(_fbhAntiAliasing);
_shader->FreeDescriptorSet(_cshSsrExtra);
_ssrHandles.FreeDescriptorSets(_shader);
_ssrHandles.DeleteFramebuffers();
_ssaoHandles.FreeDescriptorSets(_shader);
_ssaoHandles.DeleteFramebuffers();
_bloomHandles.FreeDescriptorSets(_shader);
_bloomHandles.DeleteFramebuffers();
_shader->FreeDescriptorSet(_cshDofExtra);
_dofHandles.FreeDescriptorSets(_shader);
_dofHandles.DeleteFramebuffers();
_bloomHandles.FreeDescriptorSets(_shader);
_bloomHandles.DeleteFramebuffers();
_shader->FreeDescriptorSet(_cshRdsExtra);
_rdsHandles.FreeDescriptorSets(_shader);
_rdsHandles.DeleteFramebuffers();
_tex.Done();
_shader->FreeDescriptorSet(_cshSsao);
renderer->DeleteFramebuffer(_fbhSsao);
}
{
const int scaledSwapChainWidth = settings.Scale(renderer.GetSwapChainWidth());
@ -216,23 +220,24 @@ void Blur::OnSwapChainResized()
const int scaledSwapChainHalfWidth = scaledSwapChainWidth / 2;
const int scaledSwapChainHalfHeight = scaledSwapChainHeight / 2;
CGI::TextureDesc texDesc;
texDesc._name = "Blur.Tex";
texDesc._format = CGI::Format::srgbR8G8B8A8;
texDesc._width = scaledSwapChainWidth;
texDesc._height = scaledSwapChainHeight;
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment;
_tex.Init(texDesc);
if (settings._postProcessBloom)
if (settings._postProcessSSAO)
{
_bloomHandles._fbhU = renderer->CreateFramebuffer(_bloomHandles._rphU, { bloom.GetPongTexture() }, scaledSwapChainHalfWidth, scaledSwapChainHalfHeight);
_bloomHandles._fbhV = renderer->CreateFramebuffer(_bloomHandles._rphV, { bloom.GetTexture() }, scaledSwapChainHalfWidth, scaledSwapChainHalfHeight);
_bloomHandles._cshU = _shader->BindDescriptorSetTextures(1, { bloom.GetTexture() });
_bloomHandles._cshV = _shader->BindDescriptorSetTextures(1, { bloom.GetPongTexture() });
// GBuffer3.r >> GBuffer2.r:
_fbhSsao = renderer->CreateFramebuffer(_rphSsao, { renderer.GetDS().GetGBuffer(2) }, scaledSwapChainWidth, scaledSwapChainHeight);
_cshSsao = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetGBuffer(3) });
}
{
// ComposedA >> ComposedB >> ComposedA:
_rdsHandles._fbhU = renderer->CreateFramebuffer(_rdsHandles._rphU, { renderer.GetDS().GetComposedTextureB() }, scaledSwapChainWidth, scaledSwapChainHeight);
_rdsHandles._fbhV = renderer->CreateFramebuffer(_rdsHandles._rphV, { renderer.GetDS().GetComposedTextureA() }, scaledSwapChainWidth, scaledSwapChainHeight);
_rdsHandles._cshU = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureA() });
_rdsHandles._cshV = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureB() });
_cshRdsExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(3), renderer.GetDS().GetGBuffer(3) });
}
{
// ComposedA >> ComposedB >> ComposedA:
_dofHandles._fbhU = renderer->CreateFramebuffer(_dofHandles._rphU, { renderer.GetDS().GetComposedTextureB() }, scaledSwapChainWidth, scaledSwapChainHeight);
_dofHandles._fbhV = renderer->CreateFramebuffer(_dofHandles._rphV, { renderer.GetDS().GetComposedTextureA() }, scaledSwapChainWidth, scaledSwapChainHeight);
_dofHandles._cshU = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureA() });
@ -240,29 +245,24 @@ void Blur::OnSwapChainResized()
_cshDofExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(1), renderer.GetTexDepthStencil() });
}
if (settings._postProcessSSAO)
if (settings._postProcessBloom)
{
_ssaoHandles._fbhU = renderer->CreateFramebuffer(_ssaoHandles._rphU, { _tex }, scaledSwapChainWidth, scaledSwapChainHeight);
_ssaoHandles._fbhV = renderer->CreateFramebuffer(_ssaoHandles._rphV, { ssao.GetTexture() }, scaledSwapChainWidth, scaledSwapChainHeight);
_ssaoHandles._cshU = _shader->BindDescriptorSetTextures(1, { ssao.GetTexture() });
_ssaoHandles._cshV = _shader->BindDescriptorSetTextures(1, { _tex });
}
{
_ssrHandles._fbhU = renderer->CreateFramebuffer(_ssrHandles._rphU, { renderer.GetDS().GetLightAccDiffTexture() }, scaledSwapChainWidth, scaledSwapChainHeight);
_ssrHandles._fbhV = renderer->CreateFramebuffer(_ssrHandles._rphV, { renderer.GetDS().GetLightAccSpecTexture() }, scaledSwapChainWidth, scaledSwapChainHeight);
_ssrHandles._cshU = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetLightAccSpecTexture() });
_ssrHandles._cshV = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetLightAccDiffTexture() });
_cshSsrExtra = _shader->BindDescriptorSetTextures(2, { ssao.GetTexture(), renderer.GetDS().GetGBuffer(2) });
// Ping >> Pong >> Ping:
_bloomHandles._fbhU = renderer->CreateFramebuffer(_bloomHandles._rphU, { bloom.GetPongTexture() }, scaledSwapChainHalfWidth, scaledSwapChainHalfHeight);
_bloomHandles._fbhV = renderer->CreateFramebuffer(_bloomHandles._rphV, { bloom.GetTexture() }, scaledSwapChainHalfWidth, scaledSwapChainHalfHeight);
_bloomHandles._cshU = _shader->BindDescriptorSetTextures(1, { bloom.GetTexture() });
_bloomHandles._cshV = _shader->BindDescriptorSetTextures(1, { bloom.GetPongTexture() });
}
{
// ComposedA >> ComposedB:
_fbhAntiAliasing = renderer->CreateFramebuffer(_rphAntiAliasing, { renderer.GetDS().GetComposedTextureB() }, scaledSwapChainWidth, scaledSwapChainHeight);
_cshAntiAliasing = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureA() });
_cshAntiAliasingExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(1), renderer.GetTexDepthStencil() });
}
{
// ComposedB >> ComposedA:
_fbhMotionBlur = renderer->CreateFramebuffer(_rphMotionBlur, { renderer.GetDS().GetComposedTextureA() }, scaledSwapChainWidth, scaledSwapChainHeight);
_cshMotionBlur = _shader->BindDescriptorSetTextures(1, { renderer.GetDS().GetComposedTextureB() });
_cshMotionBlurExtra = _shader->BindDescriptorSetTextures(2, { renderer.GetDS().GetGBuffer(1), renderer.GetTexDepthStencil() });
@ -270,70 +270,56 @@ void Blur::OnSwapChainResized()
}
}
void Blur::Generate()
void Blur::GenerateForSsao()
{
}
void Blur::GenerateForBloom(bool forLightShafts)
{
VERUS_QREF_BLOOM;
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
if (bloom.IsEditMode())
{
ImGui::DragFloat("Bloom blur radius", &_bloomRadius, 0.001f);
ImGui::DragFloat("Bloom (god rays) blur radius", &_bloomLightShaftsRadius, 0.001f);
}
const float radius = forLightShafts ? _bloomLightShaftsRadius : _bloomRadius;
float samplesPerPixel = 1;
int maxSamples = 1;
switch (settings._gpuShaderQuality)
{
case App::Settings::Quality::low:
samplesPerPixel = 1 / 6.f;
maxSamples = 12 - 1;
break;
case App::Settings::Quality::medium:
samplesPerPixel = 1 / 6.f;
maxSamples = 16 - 1;
break;
case App::Settings::Quality::high:
samplesPerPixel = 1 / 4.f;
maxSamples = 24 - 1;
break;
case App::Settings::Quality::ultra:
samplesPerPixel = 1 / 4.f;
maxSamples = 32 - 1;
break;
}
auto cb = renderer.GetCommandBuffer();
s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize()).UniformBufferFormat();
UpdateUniformBuffer(radius, 0, renderer.GetSwapChainWidth(), samplesPerPixel, maxSamples);
s_ubBlurVS._matV = Math::ToUVMatrix(0, renderer.GetDS().GetGBuffer(2)->GetSize(), nullptr, 0.5f, 0.5f).UniformBufferFormat();
_shader->BeginBindDescriptors();
{
cb->BeginRenderPass(_bloomHandles._rphU, _bloomHandles._fbhU, { bloom.GetPongTexture()->GetClearValue() });
cb->BeginRenderPass(_rphSsao, _fbhSsao, { renderer.GetDS().GetGBuffer(2)->GetClearValue() });
cb->BindPipeline(_pipe[PIPE_BLOOM_U]);
cb->BindPipeline(_pipe[PIPE_SSAO]);
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _bloomHandles._cshU);
cb->BindDescriptors(_shader, 1, _cshSsao);
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
}
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize()).UniformBufferFormat();
UpdateUniformBuffer(radius * renderer.GetSwapChainAspectRatio(), 0, renderer.GetSwapChainHeight(), samplesPerPixel, maxSamples);
{
cb->BeginRenderPass(_bloomHandles._rphV, _bloomHandles._fbhV, { bloom.GetTexture()->GetClearValue() });
_shader->EndBindDescriptors();
}
cb->BindPipeline(_pipe[PIPE_BLOOM_V]);
void Blur::GenerateForResolveDitheringAndSharpen()
{
VERUS_QREF_RENDERER;
auto cb = renderer.GetCommandBuffer();
s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubBlurVS._matV = Math::ToUVMatrix().UniformBufferFormat();
_shader->BeginBindDescriptors();
{
cb->BeginRenderPass(_rdsHandles._rphU, _rdsHandles._fbhU, { renderer.GetDS().GetComposedTextureB()->GetClearValue() });
cb->BindPipeline(_pipe[PIPE_RESOLVE_DITHERING]);
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _bloomHandles._cshV);
cb->BindDescriptors(_shader, 1, _rdsHandles._cshU);
cb->BindDescriptors(_shader, 2, _cshRdsExtra);
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
}
{
cb->BeginRenderPass(_rdsHandles._rphV, _rdsHandles._fbhV, { renderer.GetDS().GetComposedTextureA()->GetClearValue() });
cb->BindPipeline(_pipe[PIPE_SHARPEN]);
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _rdsHandles._cshV);
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
@ -424,52 +410,19 @@ void Blur::GenerateForDepthOfField()
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
}
void Blur::GenerateForSsao()
{
VERUS_QREF_RENDERER;
VERUS_QREF_SSAO;
auto cb = renderer.GetCommandBuffer();
s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubBlurVS._matV = Math::ToUVMatrix(0, _tex->GetSize(), nullptr, 0.5f, 0).UniformBufferFormat();
_shader->BeginBindDescriptors();
{
cb->BeginRenderPass(_ssaoHandles._rphU, _ssaoHandles._fbhU, { _tex->GetClearValue() });
cb->BindPipeline(_pipe[PIPE_SSAO_U]);
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _ssaoHandles._cshU);
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
}
s_ubBlurVS._matV = Math::ToUVMatrix(0, _tex->GetSize(), nullptr, 0, 0.5f).UniformBufferFormat();
{
cb->BeginRenderPass(_ssaoHandles._rphV, _ssaoHandles._fbhV, { ssao.GetTexture()->GetClearValue() });
cb->BindPipeline(_pipe[PIPE_SSAO_V]);
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _ssaoHandles._cshV);
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
}
_shader->EndBindDescriptors();
}
void Blur::GenerateForSsr()
void Blur::GenerateForBloom(bool forLightShafts)
{
VERUS_QREF_BLOOM;
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
VERUS_QREF_SSR;
if (ssr.IsEditMode())
if (bloom.IsEditMode())
{
ImGui::DragFloat("SSR blur radius", &_ssrRadius, 0.001f);
ImGui::DragFloat("Bloom blur radius", &_bloomRadius, 0.001f);
ImGui::DragFloat("Bloom (god rays) blur radius", &_bloomLightShaftsRadius, 0.001f);
}
const float radius = forLightShafts ? _bloomLightShaftsRadius : _bloomRadius;
float samplesPerPixel = 1;
int maxSamples = 1;
switch (settings._gpuShaderQuality)
@ -495,30 +448,28 @@ void Blur::GenerateForSsr()
auto cb = renderer.GetCommandBuffer();
s_ubBlurVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubBlurVS._matV = Math::ToUVMatrix(0, renderer.GetDS().GetLightAccDiffTexture()->GetSize()).UniformBufferFormat();
UpdateUniformBuffer(_ssrRadius, 0, renderer.GetSwapChainWidth(), samplesPerPixel, maxSamples);
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize()).UniformBufferFormat();
UpdateUniformBuffer(radius, 0, renderer.GetSwapChainWidth(), samplesPerPixel, maxSamples);
_shader->BeginBindDescriptors();
{
cb->BeginRenderPass(_ssrHandles._rphU, _ssrHandles._fbhU, { renderer.GetDS().GetLightAccDiffTexture()->GetClearValue() });
cb->BeginRenderPass(_bloomHandles._rphU, _bloomHandles._fbhU, { bloom.GetPongTexture()->GetClearValue() });
cb->BindPipeline(_pipe[PIPE_SSR_U]);
cb->BindPipeline(_pipe[PIPE_BLOOM_U]);
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _ssrHandles._cshU);
cb->BindDescriptors(_shader, 2, _cshSsrExtra);
cb->BindDescriptors(_shader, 1, _bloomHandles._cshU);
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();
}
s_ubBlurVS._matV = Math::ToUVMatrix(0, renderer.GetDS().GetLightAccSpecTexture()->GetSize()).UniformBufferFormat();
UpdateUniformBuffer(_ssrRadius * renderer.GetSwapChainAspectRatio(), 0, renderer.GetSwapChainHeight(), samplesPerPixel, maxSamples);
s_ubBlurVS._matV = Math::ToUVMatrix(0, bloom.GetTexture()->GetSize()).UniformBufferFormat();
UpdateUniformBuffer(radius * renderer.GetSwapChainAspectRatio(), 0, renderer.GetSwapChainHeight(), samplesPerPixel, maxSamples);
{
cb->BeginRenderPass(_ssrHandles._rphV, _ssrHandles._fbhV, { renderer.GetDS().GetLightAccSpecTexture()->GetClearValue() });
cb->BeginRenderPass(_bloomHandles._rphV, _bloomHandles._fbhV, { bloom.GetTexture()->GetClearValue() });
cb->BindPipeline(_pipe[PIPE_SSR_V]);
cb->BindPipeline(_pipe[PIPE_BLOOM_V]);
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _ssrHandles._cshV);
cb->BindDescriptors(_shader, 2, _cshSsrExtra);
cb->BindDescriptors(_shader, 1, _bloomHandles._cshV);
renderer.DrawQuad(cb.Get());
cb->EndRenderPass();

View File

@ -13,16 +13,21 @@ namespace verus
{
PIPE_U,
PIPE_V,
PIPE_BLOOM_U,
PIPE_BLOOM_V,
PIPE_SSAO,
PIPE_RESOLVE_DITHERING,
PIPE_SHARPEN,
PIPE_DOF_U,
PIPE_DOF_V,
PIPE_SSAO_U,
PIPE_SSAO_V,
PIPE_SSR_U,
PIPE_SSR_V,
PIPE_BLOOM_U,
PIPE_BLOOM_V,
PIPE_AA,
PIPE_MOTION_BLUR,
PIPE_COUNT
};
@ -46,26 +51,33 @@ namespace verus
CGI::ShaderPwn _shader;
CGI::PipelinePwns<PIPE_COUNT> _pipe;
CGI::TexturePwn _tex;
Handles _bloomHandles;
CGI::RPHandle _rphSsao;
CGI::FBHandle _fbhSsao;
CGI::CSHandle _cshSsao;
Handles _rdsHandles;
CGI::CSHandle _cshRdsExtra;
Handles _dofHandles;
Handles _ssaoHandles;
Handles _ssrHandles;
CGI::CSHandle _cshDofExtra;
CGI::CSHandle _cshSsrExtra;
Handles _bloomHandles;
CGI::RPHandle _rphAntiAliasing;
CGI::FBHandle _fbhAntiAliasing;
CGI::CSHandle _cshAntiAliasing;
CGI::CSHandle _cshAntiAliasingExtra;
CGI::RPHandle _rphMotionBlur;
CGI::FBHandle _fbhMotionBlur;
CGI::CSHandle _cshMotionBlur;
CGI::CSHandle _cshMotionBlurExtra;
float _bloomRadius = 0.015f;
float _bloomLightShaftsRadius = 0.004f;
float _dofFocusDist = 10;
float _dofBlurStrength = 0.2f;
float _ssrRadius = 0.025f;
float _bloomRadius = 0.02f;
float _bloomLightShaftsRadius = 0.004f;
bool _enableDepthOfField = false;
public:
@ -77,11 +89,10 @@ namespace verus
void OnSwapChainResized();
void Generate();
void GenerateForBloom(bool forLightShafts);
void GenerateForDepthOfField();
void GenerateForSsao();
void GenerateForSsr();
void GenerateForResolveDitheringAndSharpen();
void GenerateForDepthOfField();
void GenerateForBloom(bool forLightShafts);
void GenerateForAntiAliasing();
void GenerateForMotionBlur();

View File

@ -41,7 +41,7 @@ void Cinema::Init()
_pipe.Init(pipeDesc);
}
_texFilmGrain.Init("[Textures]:FilmGrain.FX.dds");
_texFilmGrain.Init("[Textures]:FilmGrain.X.dds");
}
void Cinema::Done()

View File

@ -19,8 +19,8 @@ namespace verus
float _uOffset = 0;
float _vOffset = 0;
float _brightness = 1;
float _flickerStrength = 0.01f;
float _noiseStrength = 0.15f;
float _flickerStrength = 0.02f;
float _noiseStrength = 0.2f;
bool _editMode = false;
public:

View File

@ -187,7 +187,7 @@ void Particles::Init(CSZ url)
if (!s_pipe[PIPE_MAIN])
{
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_PA;
pipeDesc._topology = CGI::PrimitiveTopology::pointList;
pipeDesc._depthWriteEnable = false;
@ -221,7 +221,7 @@ void Particles::Init(CSZ url)
if (!s_pipe[PIPE_BILLBOARDS])
{
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#Billboards", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
CGI::PipelineDesc pipeDesc(_geo, s_shader, "#Billboards", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_PA;
pipeDesc._depthWriteEnable = false;
s_pipe[PIPE_BILLBOARDS].Init(pipeDesc);

View File

@ -25,11 +25,10 @@ void Ssao::Init()
if (!settings._postProcessSSAO)
{
VERUS_LOG_INFO("SSAO disabled");
OnSwapChainResized();
return;
}
_rph = renderer->CreateSimpleRenderPass(CGI::Format::unormR8);
_rph = renderer->CreateSimpleRenderPass(CGI::Format::unormR8G8B8A8); // >> GBuffer3.r
_shader.Init("[Shaders]:Ssao.hlsl");
_shader->CreateDescriptorSet(0, &s_ubSsaoVS, sizeof(s_ubSsaoVS), 2, {}, CGI::ShaderStageFlags::vs);
@ -37,12 +36,13 @@ void Ssao::Init()
{
CGI::Sampler::nearestMipN, // RandNormals
CGI::Sampler::nearestClampMipN, // GBuffer1
CGI::Sampler::linearClampMipN, // Depth
CGI::Sampler::nearestClampMipN, // Depth
}, CGI::ShaderStageFlags::fs);
_shader->CreatePipelineLayout();
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#", _rph);
pipeDesc._colorAttachWriteMasks[0] = "r"; // >> GBuffer3.r
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe.Init(pipeDesc);
@ -53,7 +53,7 @@ void Ssao::Init()
texDesc._format = CGI::Format::unormR8G8B8A8;
texDesc._width = 4;
texDesc._height = 4;
_tex[TEX_RAND_NORMALS].Init(texDesc);
_texRandNormals.Init(texDesc);
OnSwapChainResized();
}
@ -84,40 +84,21 @@ void Ssao::OnSwapChainResized()
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
if (!settings._postProcessSSAO)
return;
const int scaledSwapChainWidth = settings.Scale(renderer.GetSwapChainWidth());
const int scaledSwapChainHeight = settings.Scale(renderer.GetSwapChainHeight());
auto InitTex = [this, scaledSwapChainWidth, scaledSwapChainHeight]()
{
_tex[TEX_GEN_AO].Done();
VERUS_QREF_RENDERER;
CGI::TextureDesc texDesc;
texDesc._clearValue = Vector4::Replicate(1);
texDesc._name = "Ssao.GenAO";
texDesc._format = CGI::Format::unormR8;
texDesc._width = scaledSwapChainWidth;
texDesc._height = scaledSwapChainHeight;
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment;
_tex[TEX_GEN_AO].Init(texDesc);
renderer.GetDS().InitBySsao(_tex[TEX_GEN_AO]);
};
if (!settings._postProcessSSAO)
{
InitTex();
return;
}
{
_shader->FreeDescriptorSet(_csh);
renderer->DeleteFramebuffer(_fbh);
}
{
InitTex();
_fbh = renderer->CreateFramebuffer(_rph, { _tex[TEX_GEN_AO] }, scaledSwapChainWidth, scaledSwapChainHeight);
_fbh = renderer->CreateFramebuffer(_rph, { renderer.GetDS().GetGBuffer(3) }, scaledSwapChainWidth, scaledSwapChainHeight);
_csh = _shader->BindDescriptorSetTextures(1,
{
_tex[TEX_RAND_NORMALS],
_texRandNormals,
renderer.GetDS().GetGBuffer(1),
renderer.GetTexDepthStencil()
});
@ -148,7 +129,7 @@ void Ssao::Generate()
s_ubSsaoVS._matW = Math::QuadMatrix().UniformBufferFormat();
s_ubSsaoVS._matV = Math::ToUVMatrix().UniformBufferFormat();
s_ubSsaoVS._matP = Math::ToUVMatrix(0, _tex[TEX_GEN_AO]->GetSize(), &_tex[TEX_RAND_NORMALS]->GetSize()).UniformBufferFormat();
s_ubSsaoVS._matP = Math::ToUVMatrix(0, renderer.GetDS().GetGBuffer(3)->GetSize(), &_texRandNormals->GetSize()).UniformBufferFormat();
s_ubSsaoFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
s_ubSsaoFS._camScale.x = cam.GetFovScale() / cam.GetAspectRatio();
s_ubSsaoFS._camScale.y = -cam.GetFovScale();
@ -157,7 +138,7 @@ void Ssao::Generate()
s_ubSsaoFS._smallRad_largeRad_weightScale_weightBias.z = _weightScale;
s_ubSsaoFS._smallRad_largeRad_weightScale_weightBias.w = _weightBias;
cb->BeginRenderPass(_rph, _fbh, { _tex[TEX_GEN_AO]->GetClearValue() });
cb->BeginRenderPass(_rph, _fbh, { renderer.GetDS().GetGBuffer(3)->GetClearValue() });
cb->BindPipeline(_pipe);
_shader->BeginBindDescriptors();
@ -186,10 +167,5 @@ void Ssao::UpdateRandNormalsTexture()
Vector4 v4 = Vector4(v3 * 0.5f + Vector3::Replicate(0.5f), 1);
vData[i] = Convert::ColorFloatToInt32(v4.ToPointer(), false);
}
_tex[TEX_RAND_NORMALS]->UpdateSubresource(vData.data());
}
CGI::TexturePtr Ssao::GetTexture() const
{
return _tex[TEX_GEN_AO];
_texRandNormals->UpdateSubresource(vData.data());
}

View File

@ -9,28 +9,21 @@ namespace verus
{
#include "../Shaders/Ssao.inc.hlsl"
enum TEX
{
TEX_GEN_AO,
TEX_RAND_NORMALS,
TEX_COUNT
};
static UB_SsaoVS s_ubSsaoVS;
static UB_SsaoFS s_ubSsaoFS;
CGI::ShaderPwn _shader;
CGI::PipelinePwn _pipe;
CGI::TexturePwns<TEX_COUNT> _tex;
CGI::RPHandle _rph;
CGI::FBHandle _fbh;
CGI::CSHandle _csh;
float _smallRad = 0.03f;
float _largeRad = 0.07f;
float _weightScale = 10;
float _weightBias = 2.5f;
bool _blur = true;
bool _editMode = false;
CGI::ShaderPwn _shader;
CGI::PipelinePwn _pipe;
CGI::TexturePwn _texRandNormals;
CGI::RPHandle _rph;
CGI::FBHandle _fbh;
CGI::CSHandle _csh;
float _smallRad = 0.03f;
float _largeRad = 0.07f;
float _weightScale = 10;
float _weightBias = 2.5f;
bool _blur = true;
bool _editMode = false;
public:
Ssao();
@ -46,8 +39,6 @@ namespace verus
void UpdateRandNormalsTexture();
CGI::TexturePtr GetTexture() const;
bool IsEditMode() const { return _editMode; }
void ToggleEditMode() { _editMode = !_editMode; }
};

View File

@ -22,19 +22,7 @@ void Ssr::Init()
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
_rph = renderer->CreateRenderPass(
{
CGI::RP::Attachment("Color", CGI::Format::floatR11G11B10).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly),
CGI::RP::Attachment("Alpha", CGI::Format::unormR8).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly)
},
{
CGI::RP::Subpass("Sp0").Color(
{
CGI::RP::Ref("Color", CGI::ImageLayout::colorAttachment),
CGI::RP::Ref("Alpha", CGI::ImageLayout::colorAttachment)
})
},
{});
_rph = renderer->CreateSimpleRenderPass(CGI::Format::floatR11G11B10);
CGI::ShaderDesc shaderDesc("[Shaders]:Ssr.hlsl");
if (settings._postProcessSSR)
@ -43,20 +31,27 @@ void Ssr::Init()
_shader->CreateDescriptorSet(0, &s_ubSsrVS, sizeof(s_ubSsrVS), 2, {}, CGI::ShaderStageFlags::vs);
_shader->CreateDescriptorSet(1, &s_ubSsrFS, sizeof(s_ubSsrFS), 2,
{
CGI::Sampler::linearClampMipN, // Color
CGI::Sampler::nearestClampMipN, // Normal
CGI::Sampler::nearestClampMipN, // GBuffer0
CGI::Sampler::nearestClampMipN, // GBuffer1
CGI::Sampler::nearestClampMipN, // GBuffer2
CGI::Sampler::nearestClampMipN, // GBuffer3
CGI::Sampler::linearClampMipN, // Scene
CGI::Sampler::linearClampMipN, // Depth
CGI::Sampler::linearClampMipN // EnvMap
CGI::Sampler::linearClampMipL // Image
}, CGI::ShaderStageFlags::fs);
_shader->CreatePipelineLayout();
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#", _rph);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe.Init(pipeDesc);
_pipe[PIPE_MAIN].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(renderer.GetGeoQuad(), _shader, "#DebugCubeMap", _rph);
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
pipeDesc.DisableDepthTest();
_pipe[PIPE_DEBUG_CUBE_MAP].Init(pipeDesc);
}
OnSwapChainResized();
@ -77,8 +72,6 @@ void Ssr::OnSwapChainResized()
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
VERUS_QREF_SSAO;
VERUS_QREF_ATMO;
{
_shader->FreeDescriptorSet(_csh);
@ -90,47 +83,44 @@ void Ssr::OnSwapChainResized()
_fbh = renderer->CreateFramebuffer(_rph,
{
renderer.GetDS().GetLightAccSpecTexture(),
ssao.GetTexture()
renderer.GetDS().GetLightAccSpecularTexture()
},
scaledSwapChainWidth, scaledSwapChainHeight);
if (atmo.GetCubeMapBaker().GetColorTexture())
{
_csh = _shader->BindDescriptorSetTextures(1,
{
renderer.GetDS().GetComposedTextureA(),
renderer.GetDS().GetGBuffer(1),
renderer.GetTexDepthStencil(),
atmo.GetCubeMapBaker().GetColorTexture()
});
}
BindDescriptorSetTextures();
}
}
bool Ssr::BindDescriptorSetTextures()
{
VERUS_QREF_ATMO;
VERUS_QREF_RENDERER;
if (atmo.GetCubeMapBaker().GetColorTexture())
{
_csh = _shader->BindDescriptorSetTextures(1,
{
renderer.GetDS().GetGBuffer(0),
renderer.GetDS().GetGBuffer(1),
renderer.GetDS().GetGBuffer(2),
renderer.GetDS().GetGBuffer(3),
renderer.GetDS().GetComposedTextureA(),
renderer.GetTexDepthStencil(),
atmo.GetCubeMapBaker().GetColorTexture()
});
return true;
}
return false;
}
void Ssr::Generate()
{
VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_ATMO;
VERUS_QREF_RENDERER;
VERUS_QREF_SM;
VERUS_QREF_SSAO;
VERUS_QREF_ATMO;
if (!settings._postProcessSSR)
return;
if (!_csh.IsSet())
{
if (atmo.GetCubeMapBaker().GetColorTexture())
{
_csh = _shader->BindDescriptorSetTextures(1,
{
renderer.GetDS().GetComposedTextureA(),
renderer.GetDS().GetGBuffer(1),
renderer.GetTexDepthStencil(),
atmo.GetCubeMapBaker().GetColorTexture()
});
}
else
if (!BindDescriptorSetTextures())
return;
}
@ -140,7 +130,6 @@ void Ssr::Generate()
ImGui::DragFloat("SSR depthBias", &_depthBias, 0.001f);
ImGui::DragFloat("SSR thickness", &_thickness, 0.001f);
ImGui::DragFloat("SSR equalizeDist", &_equalizeDist, 0.01f);
ImGui::Checkbox("SSR blur", &_blur);
}
Scene::RCamera cam = *sm.GetCamera();
@ -154,6 +143,7 @@ void Ssr::Generate()
s_ubSsrFS._matInvV = cam.GetMatrixInvV().UniformBufferFormat();
s_ubSsrFS._matPTex = matPTex.UniformBufferFormat();
s_ubSsrFS._matInvP = cam.GetMatrixInvP().UniformBufferFormat();
s_ubSsrFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
s_ubSsrFS._zNearFarEx = sm.GetCamera()->GetZNearFarEx().GLM();
s_ubSsrFS._radius_depthBias_thickness_equalizeDist.x = _radius;
s_ubSsrFS._radius_depthBias_thickness_equalizeDist.y = _depthBias;
@ -161,13 +151,9 @@ void Ssr::Generate()
s_ubSsrFS._radius_depthBias_thickness_equalizeDist.w = _equalizeDist;
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilAttachment, CGI::ImageLayout::depthStencilReadOnly, 0);
cb->BeginRenderPass(_rph, _fbh,
{
renderer.GetDS().GetLightAccSpecTexture()->GetClearValue(),
ssao.GetTexture()->GetClearValue()
});
cb->BeginRenderPass(_rph, _fbh, { renderer.GetDS().GetLightAccSpecularTexture()->GetClearValue() });
cb->BindPipeline(_pipe);
cb->BindPipeline(_cubeMapDebugMode ? _pipe[PIPE_DEBUG_CUBE_MAP] : _pipe[PIPE_MAIN]);
_shader->BeginBindDescriptors();
cb->BindDescriptors(_shader, 0);
cb->BindDescriptors(_shader, 1, _csh);
@ -176,7 +162,4 @@ void Ssr::Generate()
cb->EndRenderPass();
cb->PipelineImageMemoryBarrier(renderer.GetTexDepthStencil(), CGI::ImageLayout::depthStencilReadOnly, CGI::ImageLayout::depthStencilAttachment, 0);
if (_blur)
Blur::I().GenerateForSsr();
}

View File

@ -9,20 +9,27 @@ namespace verus
{
#include "../Shaders/Ssr.inc.hlsl"
enum PIPE
{
PIPE_MAIN,
PIPE_DEBUG_CUBE_MAP,
PIPE_COUNT
};
static UB_SsrVS s_ubSsrVS;
static UB_SsrFS s_ubSsrFS;
CGI::ShaderPwn _shader;
CGI::PipelinePwn _pipe;
CGI::RPHandle _rph;
CGI::FBHandle _fbh;
CGI::CSHandle _csh;
float _radius = 2.5f;
float _depthBias = 0.03f;
float _thickness = 0.25f;
float _equalizeDist = 12;
bool _blur = true;
bool _editMode = false;
CGI::ShaderPwn _shader;
CGI::PipelinePwns<PIPE_COUNT> _pipe;
CGI::RPHandle _rph;
CGI::FBHandle _fbh;
CGI::CSHandle _csh;
float _radius = 2.2f;
float _depthBias = 0.03f;
float _thickness = 0.3f;
float _equalizeDist = 20;
bool _cubeMapDebugMode = false;
bool _editMode = false;
public:
Ssr();
@ -33,8 +40,13 @@ namespace verus
void OnSwapChainResized();
bool BindDescriptorSetTextures();
void Generate();
bool IsCubeMapDebugMode() const { return _cubeMapDebugMode; }
void ToggleCubeMapDebugMode() { _cubeMapDebugMode = !_cubeMapDebugMode; }
bool IsEditMode() const { return _editMode; }
void ToggleEditMode() { _editMode = !_editMode; }
};

View File

@ -78,8 +78,11 @@ void ViewManager::Done()
_cursor.Done();
_shader->FreeDescriptorSet(_cshDebug);
_shader->FreeDescriptorSet(_cshDefault);
if (_shader)
{
_shader->FreeDescriptorSet(_cshDebug);
_shader->FreeDescriptorSet(_cshDefault);
}
VERUS_DONE(ViewManager);
}

View File

@ -102,7 +102,11 @@ void BaseGame::Initialize(VERUS_MAIN_DEFAULT_ARGS, App::Window::RcDesc windowDes
Utils::TestAll();
#endif
// Window and renderer:
_window.Init(updatedWindowDesc);
SDL_GetWindowSize(_window.GetSDL(),
&settings._displaySizeWidth,
&settings._displaySizeHeight); // Display size, window size and swap chain size must match.
CGI::Renderer::I().SetMainWindow(&_window);
_engineInit.Init(new MyRendererDelegate(this));

View File

@ -62,6 +62,16 @@ UINT32 Convert::Uint4x4ToUint8x4(UINT16 in, bool scaleTo255)
return (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3] << 0);
}
half Convert::FloatToHalf(float f)
{
return glm::packHalf1x16(f);
}
float Convert::HalfToFloat(half h)
{
return glm::unpackHalf1x16(h);
}
float Convert::SRGBToLinear(float color)
{
return color < 0.04045f ? color * (1 / 12.92f) : pow((color + 0.055f) * (1 / 1.055f), 2.4f);
@ -128,6 +138,8 @@ UINT32 Convert::ColorFloatToInt32(const float* in, bool sRGB)
void Convert::ColorTextToFloat4(CSZ sz, float* out, bool sRGB)
{
if (sz && '0' == sz[0] && 'x' == sz[1])
sz += 2;
int color[4] = {};
if (!sz)
{
@ -170,8 +182,13 @@ void Convert::ColorTextToFloat4(CSZ sz, float* out, bool sRGB)
UINT32 Convert::ColorTextToInt32(CSZ sz)
{
if (sz && '0' == sz[0] && 'x' == sz[1])
sz += 2;
int color[4] = {};
if (6 == strlen(sz) && !strchr(sz, ' '))
if (!sz)
{
}
else if (6 == strlen(sz) && !strchr(sz, ' '))
{
color[0] = Str::ByteFromHex(sz + 0);
color[1] = Str::ByteFromHex(sz + 2);

View File

@ -41,6 +41,10 @@ namespace verus
static UINT16 Uint8x4ToUint4x4(UINT32 in);
static UINT32 Uint4x4ToUint8x4(UINT16 in, bool scaleTo255 = false);
// Half:
static half FloatToHalf(float f);
static float HalfToFloat(half h);
// Colors:
static float SRGBToLinear(float color);
static float LinearToSRGB(float color);

View File

@ -89,3 +89,5 @@
#define VERUS_COLOR_BLEND_MAD "s*(dc)+d*(sa)"
#define VERUS_COLOR_BLEND_FILTER "s*(0)+d*(sc)"
#define VERUS_COLOR_BLEND_TINTED_GLASS "s*(sc)+d*(1-sc)"
#define VERUS_COLOR_BLEND_MIN "min(s, d)"
#define VERUS_COLOR_BLEND_MAX "max(s, d)"

View File

@ -232,6 +232,10 @@ void Str::ReplaceFilename(RString pathname, CSZ filename)
const size_t count = pathname.length() - pos;
pathname.replace(pos + 1, count, filename);
}
else
{
pathname = filename;
}
}
void Str::ReplaceExtension(RString pathname, CSZ ext)
@ -262,21 +266,30 @@ String Str::ToPakFriendlyUrl(CSZ url)
glm::vec2 Str::FromStringVec2(CSZ s)
{
glm::vec2 v;
sscanf(s, "%f %f", &v.x, &v.y);
if ('[' == *s)
sscanf(s, "[%f, %f]", &v.x, &v.y);
else
sscanf(s, "%f %f", &v.x, &v.y);
return v;
}
glm::vec3 Str::FromStringVec3(CSZ s)
{
glm::vec3 v;
sscanf(s, "%f %f %f", &v.x, &v.y, &v.z);
if ('[' == *s)
sscanf(s, "[%f, %f, %f]", &v.x, &v.y, &v.z);
else
sscanf(s, "%f %f %f", &v.x, &v.y, &v.z);
return v;
}
glm::vec4 Str::FromStringVec4(CSZ s)
{
glm::vec4 v;
sscanf(s, "%f %f %f %f", &v.x, &v.y, &v.z, &v.w);
if ('[' == *s)
sscanf(s, "[%f, %f, %f, %f]", &v.x, &v.y, &v.z, &v.w);
else
sscanf(s, "%f %f %f %f", &v.x, &v.y, &v.z, &v.w);
return v;
}
@ -294,24 +307,24 @@ String Str::ToString(float f)
return buffer;
}
String Str::ToString(const glm::vec2& v)
String Str::ToString(const glm::vec2& v, bool brackets)
{
char buffer[40];
sprintf_s(buffer, "%g %g", v.x, v.y);
sprintf_s(buffer, brackets ? "[%g, %g]" : "%g %g", v.x, v.y);
return buffer;
}
String Str::ToString(const glm::vec3& v)
String Str::ToString(const glm::vec3& v, bool brackets)
{
char buffer[60];
sprintf_s(buffer, "%g %g %g", v.x, v.y, v.z);
sprintf_s(buffer, brackets ? "[%g, %g, %g]" : "%g %g %g", v.x, v.y, v.z);
return buffer;
}
String Str::ToString(const glm::vec4& v)
String Str::ToString(const glm::vec4& v, bool brackets)
{
char buffer[80];
sprintf_s(buffer, "%g %g %g %g", v.x, v.y, v.z, v.w);
sprintf_s(buffer, brackets ? "[%g, %g, %g, %g]" : "%g %g %g %g", v.x, v.y, v.z, v.w);
return buffer;
}
@ -322,11 +335,11 @@ glm::vec4 Str::FromColorString(CSZ sz, bool sRGB)
return glm::make_vec4(rgba);
}
String Str::ToColorString(const glm::vec4& v, bool sRGB)
String Str::ToColorString(const glm::vec4& v, bool sRGB, bool hexPrefix)
{
const UINT32 color = Convert::ColorFloatToInt32(glm::value_ptr(v), sRGB);
char txt[20];
sprintf_s(txt, "%02X%02X%02X%02X",
sprintf_s(txt, hexPrefix ? "0x%02X%02X%02X%02X" : "%02X%02X%02X%02X",
(color >> 0) & 0xFF,
(color >> 8) & 0xFF,
(color >> 16) & 0xFF,

View File

@ -58,11 +58,11 @@ namespace verus
static glm::vec4 FromStringVec4(CSZ s);
static String ToString(int i);
static String ToString(float f);
static String ToString(const glm::vec2& v);
static String ToString(const glm::vec3& v);
static String ToString(const glm::vec4& v);
static String ToString(const glm::vec2& v, bool brackets = false);
static String ToString(const glm::vec3& v, bool brackets = false);
static String ToString(const glm::vec4& v, bool brackets = false);
static glm::vec4 FromColorString(CSZ sz, bool sRGB = true);
static String ToColorString(const glm::vec4& v, bool sRGB = true);
static String ToColorString(const glm::vec4& v, bool sRGB = true, bool hexPrefix = false);
// XML:
static String XmlEscape(CSZ s);

View File

@ -30,10 +30,21 @@ namespace verus
typedef const char* CSZ;
typedef wchar_t* WSZ;
typedef const wchar_t* CWSZ;
typedef std::string String;
typedef std::wstring WideString;
typedef std::stringstream StringStream;
typedef glm::quat Quaternion;
typedef glm::quat Quaternion;
typedef glm::ivec2 int2;
typedef glm::ivec3 int3;
typedef glm::ivec4 int4;
typedef glm::vec2 float2;
typedef glm::vec3 float3;
typedef glm::vec4 float4;
typedef glm::mat4 matrix;
typedef glm::mat3x4 mataff;
typedef UINT16 half;
VERUS_TYPEDEFS(String);
VERUS_TYPEDEFS(WideString);

View File

@ -109,6 +109,61 @@ void Utils::CopyIntToByte4(const int src[4], BYTE dest[4])
dest[i] = src[i];
}
void Utils::ComputeEdgePadding(BYTE* pData, int dataPixelStride, const BYTE* pAlpha, int alphaPixelStride, int width, int height, int radius, int channelCount)
{
channelCount = Math::Min(channelCount, dataPixelStride); // Assume one byte per channel.
VERUS_RT_ASSERT(channelCount >= 1 && channelCount <= 4);
if (!radius)
radius = Math::Clamp((width + height) / 256, 1, 16);
const int radiusSq = radius * radius;
VERUS_P_FOR(i, height)
{
const int rowOffset = i * width;
VERUS_FOR(j, width)
{
const BYTE alpha = pAlpha[alphaPixelStride * (rowOffset + j)];
if (alpha)
continue;
BYTE* pDataChannels = &pData[dataPixelStride * (rowOffset + j)];
int minRadiusSq = INT_MAX;
BYTE color[4] = {};
// Kernel:
for (int di = -radius; di <= radius; ++di)
{
const int ki = i + di;
if (ki < 0 || ki >= height)
continue;
for (int dj = -radius; dj <= radius; ++dj)
{
const int kj = j + dj;
if (kj < 0 || kj >= width)
continue;
if (!di && !dj)
continue; // Skip origin.
const int lenSq = di * di + dj * dj;
if (lenSq > radiusSq)
continue;
const BYTE kernelAlpha = pAlpha[alphaPixelStride * (ki * width + kj)];
if (!kernelAlpha)
continue;
if (lenSq < minRadiusSq)
{
minRadiusSq = lenSq;
BYTE* pKernelChannels = &pData[dataPixelStride * (ki * width + kj)];
memcpy(color, pKernelChannels, channelCount);
}
}
}
if (minRadiusSq != INT_MAX)
memcpy(pDataChannels, color, channelCount);
}
});
}
void Utils::TestAll()
{
Convert::Test();

View File

@ -65,6 +65,9 @@ namespace verus
static void CopyByteToInt4(const BYTE src[4], int dest[4]);
static void CopyIntToByte4(const int src[4], BYTE dest[4]);
static void ComputeEdgePadding(BYTE* pData, int dataPixelStride, const BYTE* pAlpha, int alphaPixelStride,
int width, int height, int radius = 0, int channelCount = 3);
static void TestAll();
template<typename T>

View File

@ -38,6 +38,7 @@ void Async::Load(CSZ url, PAsyncDelegate pDelegate, RcTaskDesc desc)
{
VERUS_RT_ASSERT(IsInitialized());
VERUS_RT_ASSERT(!_inUpdate); // Not allowed to call Load() in Update().
VERUS_RT_ASSERT(url && *url);
// If the queue is full we must block until something gets processed:
bool full = false;

View File

@ -52,9 +52,33 @@ bool DDSHeader::IsBC3() const
return (_pixelFormat._flags & PixelFormatFlags::fourCC) && (FourCC::dxt5 == _pixelFormat._fourCC);
}
bool DDSHeader::IsBC4U() const
{
return (_pixelFormat._flags & PixelFormatFlags::fourCC) && (FourCC::bc4u == _pixelFormat._fourCC);
}
bool DDSHeader::IsBC4S() const
{
return (_pixelFormat._flags & PixelFormatFlags::fourCC) && (FourCC::bc4s == _pixelFormat._fourCC);
}
bool DDSHeader::IsBC5U() const
{
return (_pixelFormat._flags & PixelFormatFlags::fourCC) && (FourCC::bc5u == _pixelFormat._fourCC);
}
bool DDSHeader::IsBC5S() const
{
return (_pixelFormat._flags & PixelFormatFlags::fourCC) && (FourCC::bc5s == _pixelFormat._fourCC);
}
bool DDSHeader::IsBC() const
{
return IsBC1() || IsBC2() || IsBC3() || IsDXT10();
return
IsBC1() || IsBC2() || IsBC3() ||
IsBC4U() || IsBC4S() ||
IsBC5U() || IsBC5S() ||
IsDXT10();
}
bool DDSHeader::IsBGRA8() const

View File

@ -100,6 +100,10 @@ namespace verus
bool IsBC1() const;
bool IsBC2() const;
bool IsBC3() const;
bool IsBC4U() const;
bool IsBC4S() const;
bool IsBC5U() const;
bool IsBC5S() const;
bool IsBC() const;
bool IsBGRA8() const;
bool IsBGR8() const;
@ -108,6 +112,7 @@ namespace verus
int GetPartCount() const;
int SkipParts(int skipCount);
};
VERUS_TYPEDEFS(DDSHeader);
struct DDSHeaderDXT10
{
@ -135,5 +140,6 @@ namespace verus
bool IsBC7() const;
};
VERUS_TYPEDEFS(DDSHeaderDXT10);
}
}

View File

@ -120,8 +120,8 @@ void FileSystem::PreloadDefaultCache()
".primary",
".rig",
".txt",
".vml",
".xml",
".xmt",
".xwa",
".xwx",
nullptr
@ -158,32 +158,32 @@ void FileSystem::LoadResource(CSZ url, Vector<BYTE>& vData, RcLoadDesc desc)
void FileSystem::LoadResourceFromFile(CSZ url, Vector<BYTE>& vData, RcLoadDesc desc)
{
String strUrl(url), projectPathname(url);
String primaryUrl(url), secondaryUrl(url);
const bool shader = Str::StartsWith(url, s_shaderPAK);
const size_t pakPos = FindPosForPAK(url);
if (pakPos != String::npos)
{
if (shader)
{
strUrl.replace(0, strlen(s_shaderPAK), "/");
projectPathname = String(_C(Utils::I().GetProjectPath())) + strUrl;
primaryUrl.replace(0, strlen(s_shaderPAK), "/");
secondaryUrl = String(_C(Utils::I().GetProjectPath())) + primaryUrl;
StringStream ss;
ss << _C(Utils::I().GetShaderPath()) << strUrl;
strUrl = ss.str();
ss << _C(Utils::I().GetShaderPath()) << primaryUrl;
primaryUrl = ss.str();
}
else
{
String folder = strUrl.substr(1, pakPos - 1);
const String name = strUrl.substr(pakPos + 2);
projectPathname = String(_C(Utils::I().GetProjectPath())) + s_dataFolder + folder + "/" + name;
const String folder = primaryUrl.substr(1, pakPos - 1);
const String name = primaryUrl.substr(pakPos + 2);
primaryUrl = String(_C(Utils::I().GetProjectPath())) + s_dataFolder + folder + "/" + name;
StringStream ss;
ss << _C(Utils::I().GetModulePath()) << s_dataFolder << folder << "/" << name;
strUrl = ss.str();
secondaryUrl = ss.str();
}
}
File file;
if (file.Open(_C(strUrl)) || file.Open(_C(projectPathname)))
if (file.Open(_C(primaryUrl)) || file.Open(_C(secondaryUrl)))
{
const INT64 size = file.GetSize();
if (size >= 0)
@ -201,7 +201,7 @@ void FileSystem::LoadResourceFromFile(CSZ url, Vector<BYTE>& vData, RcLoadDesc d
}
}
else if (desc._mandatory)
throw VERUS_RUNTIME_ERROR << "LoadResourceFromFile(); File not found: " << url << " (" << strUrl << ")";
throw VERUS_RUNTIME_ERROR << "LoadResourceFromFile(); File not found: " << url << " (" << primaryUrl << ")";
}
void FileSystem::LoadResourceFromCache(CSZ url, Vector<BYTE>& vData, bool mandatory)
@ -473,9 +473,9 @@ String FileSystem::ReplaceFilename(CSZ pathname, CSZ filename)
return filename;
}
void FileSystem::SaveImage(CSZ pathname, const UINT32* p, int w, int h, ImageFormat format, int param)
void FileSystem::SaveImage(CSZ pathname, const void* p, int w, int h, ImageFormat format, int pixelStride, int param)
{
Vector<BYTE> v(w * h * 8);
Vector<BYTE> v(pixelStride * (w * h) * 2); // Assume this size will be enough for compressed image.
MutableBlob context(v.data());
if (ImageFormat::extension == format)
@ -500,19 +500,19 @@ void FileSystem::SaveImage(CSZ pathname, const UINT32* p, int w, int h, ImageFor
{
case ImageFormat::png:
{
if (!stbi_write_png_to_func(WriteFunc, &context, w, h, 4, p, param ? param : w * 4))
if (!stbi_write_png_to_func(WriteFunc, &context, w, h, pixelStride, p, param ? param : w * pixelStride))
throw VERUS_RUNTIME_ERROR << "stbi_write_png_to_func()";
}
break;
case ImageFormat::tga:
{
if (!stbi_write_tga_to_func(WriteFunc, &context, w, h, 4, p))
if (!stbi_write_tga_to_func(WriteFunc, &context, w, h, pixelStride, p))
throw VERUS_RUNTIME_ERROR << "stbi_write_tga_to_func()";
}
break;
case ImageFormat::jpg:
{
if (!stbi_write_jpg_to_func(WriteFunc, &context, w, h, 4, p, param ? param : 90))
if (!stbi_write_jpg_to_func(WriteFunc, &context, w, h, pixelStride, p, param ? param : 90))
throw VERUS_RUNTIME_ERROR << "stbi_write_jpg_to_func()";
}
break;
@ -528,17 +528,19 @@ void FileSystem::SaveImage(CSZ pathname, const UINT32* p, int w, int h, ImageFor
throw VERUS_RUNTIME_ERROR << "SaveImage(); Open()";
}
void FileSystem::SaveDDS(CSZ pathname, const UINT32* p, int w, int h, int d)
void FileSystem::SaveDDS(CSZ pathname, const void* p, int w, int h, int d)
{
IO::File file;
if (!file.Open(pathname, "wb"))
throw VERUS_RUNTIME_ERROR << "SaveDDS(); Open()";
const int pixelStride = 4;
DDSHeader header;
header._flags |= DDSHeader::Flags::linearSize;
header._height = h;
header._width = w;
header._pitchOrLinearSize = w * h * 4 * Math::Max(1, abs(d));
header._pitchOrLinearSize = pixelStride * (w * h * Math::Max(1, abs(d)));
header._depth = abs(d);
header._pixelFormat._flags |= DDSHeader::PixelFormatFlags::alphaPixels | DDSHeader::PixelFormatFlags::rgb;
header._pixelFormat._rgbBitCount = 32;
@ -591,7 +593,7 @@ void Image::Init(CSZ url)
{
VERUS_INIT();
FileSystem::LoadResourceFromFile(url, _vData);
_p = stbi_load_from_memory(_vData.data(), Utils::Cast32(_vData.size()), &_width, &_height, &_bytesPerPixel, 0);
_p = stbi_load_from_memory(_vData.data(), Utils::Cast32(_vData.size()), &_width, &_height, &_pixelStride, 0);
}
void Image::Done()

View File

@ -66,8 +66,8 @@ namespace verus
static String ReplaceFilename(CSZ pathname, CSZ filename);
// Save data:
static void SaveImage /**/(CSZ pathname, const UINT32* p, int w, int h, ImageFormat format = ImageFormat::tga, int param = 0);
static void SaveDDS /**/(CSZ pathname, const UINT32* p, int w, int h, int d = 0);
static void SaveImage /**/(CSZ pathname, const void* p, int w, int h, ImageFormat format = ImageFormat::tga, int pixelStride = sizeof(UINT32), int param = 0);
static void SaveDDS /**/(CSZ pathname, const void* p, int w, int h, int d = 0);
static void SaveString/**/(CSZ pathname, CSZ s);
};
VERUS_TYPEDEFS(FileSystem);
@ -79,7 +79,7 @@ namespace verus
BYTE* _p = nullptr;
int _width = 0;
int _height = 0;
int _bytesPerPixel = 0;
int _pixelStride = 0;
Image();
~Image();

View File

@ -416,6 +416,13 @@ int Math::ComputeMipLevels(int w, int h, int d)
return 1 + static_cast<int>(floor(log2(Max(Max(w, h), d))));
}
BYTE Math::CombineOcclusion(BYTE a, BYTE b)
{
const BYTE ab = a * b / 0xFF;
const BYTE mn = Math::Min(a, b);
return (ab + mn + mn) / 3;
}
Transform3 Math::QuadMatrix(float x, float y, float w, float h)
{
const Transform3 matT = Transform3::translation(Vector3(x * 2 - 1, y * -2 + 1));
@ -686,4 +693,23 @@ void Math::Test()
point /= point.getW();
VERUS_RT_ASSERT(glm::epsilonEqual<float>(point.getZ(), 1.f, e));
}
// Z VS W:
{
const float zn = 3;
const float zf = 20;
const Point3 p1(0, 0, 7);
const Matrix4 matV = Matrix4::lookAt(Point3(0, 0, 2), p1, Vector3(0, 1, 0)); // 5 meters away from p1.
const Matrix4 matP = Matrix4::MakePerspective(VERUS_PI * 0.25f, 4 / 3.f, zn, zf);
const Matrix4 matVP = matP * matV;
const Vector4 p2 = matV * p1;
const Vector4 p3 = matVP * p1;
VERUS_RT_ASSERT(glm::epsilonEqual<float>(p2.getZ(), -5.f, e)); // In V space Z is negative.
VERUS_RT_ASSERT(glm::epsilonEqual<float>(p3.getW(), 5.f, e)); // In VP space Z turns to positive W.
const float unormDepth = p3.getZ() / p3.getW();
const float a = zf * zn / (zn - zf);
const float b = zf / (zf - zn);
const float linearDepth = a / (unormDepth - b);
VERUS_RT_ASSERT(glm::epsilonEqual(linearDepth, 5.f, e)); // Linear depth starts from the eye.
}
}

View File

@ -70,15 +70,6 @@ namespace verus
count
};
typedef glm::ivec2 int2;
typedef glm::ivec3 int3;
typedef glm::ivec4 int4;
typedef glm::vec2 float2;
typedef glm::vec3 float3;
typedef glm::vec4 float4;
typedef glm::mat4 matrix;
typedef glm::mat3x4 mataff;
namespace VMath = Vectormath::SSE;
}
@ -155,6 +146,8 @@ namespace verus
int ComputeMipLevels(int w, int h, int d = 1);
BYTE CombineOcclusion(BYTE a, BYTE b);
// Matrices:
Transform3 QuadMatrix(float x = 0, float y = 0, float w = 1, float h = 1);
Transform3 ToUVMatrix(float zOffset = 0, RcVector4 texSize = Vector4(0), PcVector4 pTileSize = nullptr, float uOffset = 0, float vOffset = 0);

View File

@ -44,13 +44,14 @@ void Atmosphere::Init()
_cubeMapBaker.Init(512);
_shadowMapBaker.Init(4096);
renderer.GetDS().InitByAtmosphere(_shadowMapBaker.GetTexture());
renderer.GetDS().InitByAtmosphere(_shadowMapBaker.GetTexture());
bloom.InitByAtmosphere(_shadowMapBaker.GetTexture());
CreateCelestialBodyMesh();
{
CGI::PipelineDesc pipeDesc(_geo, _shader, "#Sun", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
CGI::PipelineDesc pipeDesc(_geo, _shader, "#Sun", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
@ -59,7 +60,7 @@ void Atmosphere::Init()
_pipe[PIPE_SUN].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(_geo, _shader, "#Moon", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
CGI::PipelineDesc pipeDesc(_geo, _shader, "#Moon", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
pipeDesc._topology = CGI::PrimitiveTopology::triangleStrip;
@ -104,11 +105,10 @@ void Atmosphere::UpdateSun(float time)
{
_night = true;
_sun._dirTo = _sun._matTilt * Matrix3::rotationZ(quantTime * VERUS_2PI) * Vector3(0, 1, 0);
_sun._color = glm::saturation(0.25f, _sun._color.GLM()) * 0.2f;
}
// Reduce light's intensity when near horizon:
_sun._alpha = Math::Clamp<float>(abs(_sun._dirTo.getY()) * 4, 0, 1);
_sun._alpha = Math::Clamp<float>(abs(_sun._dirTo.getY()) * 4, 0, 1) * (_night ? 0.25f : 1.f);
_sun._color *= _sun._alpha;
if (_sun._light)
@ -178,7 +178,7 @@ void Atmosphere::Update()
_async_loaded = true;
{
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Sky", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Sky", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
pipeDesc._vertexInputBindingsFilter = (1 << 0);
pipeDesc._depthWriteEnable = false;
pipeDesc._depthCompareOp = CGI::CompareOp::lessOrEqual;
@ -188,7 +188,7 @@ void Atmosphere::Update()
_pipe[PIPE_SKY_REFLECTION].Init(pipeDesc);
}
{
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Clouds", renderer.GetDS().GetRenderPassHandle_ExtraCompose());
CGI::PipelineDesc pipeDesc(_skyDome.GetGeometry(), _shader, "#Clouds", renderer.GetDS().GetRenderPassHandle_ForwardRendering());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ALPHA;
pipeDesc._vertexInputBindingsFilter = (1 << 0);
pipeDesc._depthWriteEnable = false;
@ -216,43 +216,31 @@ void Atmosphere::Update()
_clouds._cloudiness.Update();
const float cloudinessStrength = _clouds._cloudiness * sqrt(_clouds._cloudiness);
const float cloudScaleAmb = 1 - 0.6f * cloudinessStrength;
const float cloudScaleFog = 1 - 0.9f * cloudinessStrength;
const float cloudScaleSun = 1 - 0.999f * cloudinessStrength;
const float cloudinessSq = _clouds._cloudiness * _clouds._cloudiness;
const float cloudScaleAmb = 1 - 0.9f * _clouds._cloudiness;
const float cloudScaleSun = 1 - 0.9999f * cloudinessSq;
const int count = 1;
std::stringstream ssDebug;
VERUS_FOR(i, count)
{
const float time = (count > 1) ? (i / 256.f) : _time;
_ambientMagnitude = GetMagnitude(time, 20000, 5000, 1000) * cloudScaleAmb;
float color[3];
SampleSkyColor(208, color, 1); _ambientColor = Vector3::MakeFromPointer(color) * (GetMagnitude(time, 64000, 16000, 4000) * cloudScaleAmb);
SampleSkyColor(100, color, 1); _fog._color = Vector3::MakeFromPointer(color) * (GetMagnitude(time, 32000, 5000, 300) * cloudScaleFog);
SampleSkyColor(240, color, 1); _sun._color = Vector3::MakeFromPointer(color) * (GetMagnitude(time, 90000, 60000, 600) * cloudScaleSun);
SampleSkyColor(time, 200, color); _ambientColorY1 = Vector3::MakeFromPointer(color) * _ambientMagnitude;
SampleSkyColor(time, 216, color); _ambientColorY0 = Vector3::MakeFromPointer(color) * _ambientMagnitude;
SampleSkyColor(time, 232, color); _ambientColor = Vector3::MakeFromPointer(color) * _ambientMagnitude;
SampleSkyColor(time, 248, color); _sun._color = Vector3::MakeFromPointer(color) * (GetMagnitude(time, 40000, 20000, 1000) * cloudScaleSun * cloudScaleSun);
if (count > 1)
ssDebug << static_cast<int>(glm::saturation(0.f, _ambientColor.GLM()).x) << ", ";
}
const String debug = ssDebug.str();
// <Cloudiness>
glm::vec3 ambientColor = _ambientColor.GLM();
glm::vec3 fogColor = _fog._color.GLM();
_ambientColor = glm::saturation(0.7f - 0.3f * _clouds._cloudiness, ambientColor);
_fog._color = glm::saturation(0.8f - 0.2f * _clouds._cloudiness, fogColor);
_fog._density[0] = _fog._density[1] * (1 + 9 * _clouds._cloudiness * _clouds._cloudiness);
_ambientColor = glm::saturation(1 - 0.3f * _clouds._cloudiness, _ambientColor.GLM());
_ambientColorY0 = glm::saturation(1 - 0.3f * _clouds._cloudiness, _ambientColorY0.GLM());
_ambientColorY1 = glm::saturation(1 - 0.3f * _clouds._cloudiness, _ambientColorY1.GLM());
// </Cloudiness>
#ifdef _DEBUG
if (abs(_time - 0.5f) < 0.01f && glm::epsilonEqual(static_cast<float>(_clouds._cloudiness), 0.25f, 0.05f))
{
const glm::vec3 grayAmbient = glm::saturation(0.f, _ambientColor.GLM());
const glm::vec3 grayFog = glm::saturation(0.f, _fog._color.GLM());
const glm::vec3 graySun = glm::saturation(0.f, _sun._color.GLM());
//VERUS_RT_ASSERT(glm::epsilonEqual<float>(grayAmbient.x, 4000, 400));
//VERUS_RT_ASSERT(glm::epsilonEqual<float>(graySun.x, 16000, 1600));
}
#endif
// <Clouds>
const Vector4 phaseV(_wind._baseVelocity.getX(), _wind._baseVelocity.getZ());
_clouds._phaseA = Vector4(_clouds._phaseA - phaseV * (dt * _clouds._speedPhaseA * 0.05f)).Mod(1);
@ -260,6 +248,12 @@ void Atmosphere::Update()
// </Clouds>
UpdateSun(_time);
// <Fog>
_fog._color = VMath::lerp(0.1f, _ambientColor, _sun._color);
_fog._color = glm::saturation(0.9f - 0.4f * cloudinessSq, _fog._color.GLM());
_fog._density[0] = _fog._density[1] * (1 + 9 * cloudinessSq);
// </Fog>
}
void Atmosphere::DrawSky(bool reflection)
@ -282,8 +276,8 @@ void Atmosphere::DrawSky(bool reflection)
s_ubPerFrame._time_cloudiness.x = _time;
s_ubPerFrame._time_cloudiness.y = _clouds._cloudiness;
s_ubPerFrame._ambientColor = float4(_ambientColor.GLM(), 0);
s_ubPerFrame._fogColor = float4(_fog._color.GLM(), 0);
s_ubPerFrame._ambientColor = float4(_ambientColor.GLM(), _ambientMagnitude);
s_ubPerFrame._fogColor = float4(_fog._color.GLM(), _fog._density[0]);
s_ubPerFrame._dirToSun = float4(_sun._dirTo.GLM(), 0);
s_ubPerFrame._sunColor = float4(_sun._color.GLM(), _sun._alpha);
s_ubPerFrame._phaseAB = float4(
@ -363,11 +357,11 @@ void Atmosphere::DrawSky(bool reflection)
// </Clouds>
}
void Atmosphere::SampleSkyColor(int level, float* pOut, float scale)
void Atmosphere::SampleSkyColor(float time, int level, float* pOut)
{
if (!_texSky.IsLoaded())
return;
const float texCoord = _time * 256;
const float texCoord = time * 256;
const int intPartA = static_cast<int>(texCoord) & 0xFF;
const int intPartB = (intPartA + 1) & 0xFF;
const float fractPart = texCoord - intPartA;
@ -386,7 +380,7 @@ void Atmosphere::SampleSkyColor(int level, float* pOut, float scale)
LoadFromSky(rgbB, offsetB);
VERUS_FOR(i, 3)
pOut[i] = Math::Clamp<float>(Math::Lerp(rgbA[i], rgbB[i], fractPart) * 0.5f * scale, 0, 1);
pOut[i] = Math::Lerp(rgbA[i], rgbB[i], fractPart);
}
float Atmosphere::GetMagnitude(float time, float noon, float dusk, float midnight)
@ -443,6 +437,12 @@ void Atmosphere::OnSceneResetInitSunLight()
_sun._light->SetTransient();
}
void Atmosphere::SetLatitude(float lat)
{
_sun._latitude = lat;
_sun._matTilt = Matrix3::rotationX(_sun._latitude);
}
RcMatrix3 Atmosphere::GetPlantBendingMatrix() const
{
return _wind._matPlantBending;

View File

@ -61,7 +61,7 @@ namespace verus
Vector3 _color = Vector3(0);
LightPwn _light;
float _alpha = 1;
float _latitude = 0.7f;
float _latitude = VERUS_PI * 0.25f;
};
struct Wind
@ -89,12 +89,15 @@ namespace verus
Sun _sun;
Wind _wind;
Vector3 _ambientColor = Vector3(0);
Vector3 _ambientColorY0 = Vector3(0);
Vector3 _ambientColorY1 = Vector3(0);
CubeMapBaker _cubeMapBaker;
CascadedShadowMapBaker _shadowMapBaker;
Mesh _skyDome;
CGI::TextureRAM _texSky;
float _time = 0.5f;
float _timeSpeed = 1 / 300.f;
float _ambientMagnitude = 1;
CGI::CSHandle _cshSkyFS;
CGI::CSHandle _cshSunFS;
CGI::CSHandle _cshMoonFS;
@ -121,7 +124,7 @@ namespace verus
void Update();
void DrawSky(bool reflection = false);
void SampleSkyColor(int level, float* pOut, float scale);
void SampleSkyColor(float time, int level, float* pOut);
static float GetMagnitude(float time, float noon, float dusk, float midnight);
// Time:
@ -130,7 +133,10 @@ namespace verus
float GetTimeSpeed() const { return _timeSpeed; }
void SetTimeSpeed(float x) { _timeSpeed = x; }
float GetAmbientMagnitude() const { return _ambientMagnitude; }
RcVector3 GetAmbientColor() const { return _ambientColor; }
RcVector3 GetAmbientColorY0() const { return _ambientColorY0; }
RcVector3 GetAmbientColorY1() const { return _ambientColorY1; }
// Clouds:
Anim::Elastic<float>& GetCloudiness() { return _clouds._cloudiness; }
@ -147,6 +153,7 @@ namespace verus
RcVector3 GetSunColor() const;
float GetSunAlpha() const;
void OnSceneResetInitSunLight();
void SetLatitude(float lat);
// Wind:
RcMatrix3 GetPlantBendingMatrix() const;

View File

@ -124,7 +124,7 @@ namespace verus
Math::Bounds GetBounds() const;
template<typename T>
void ForEachVertex(const T& fn) const
void ForEachVertex(const T& fn, bool boneIndices = false) const
{
VERUS_FOR(i, _vertCount)
{
@ -133,8 +133,28 @@ namespace verus
DequantizeUsingDeq3D(_vBinding0[i]._pos, _posDeq, pos);
DequantizeNrm(_vBinding0[i]._nrm, nrm);
DequantizeUsingDeq2D(_vBinding0[i]._tc0, _tc0Deq, tc);
if (Continue::no == fn(i, pos, nrm, tc))
break;
if (_vBinding1.empty() || !boneIndices)
{
if (Continue::no == fn(i, pos, nrm, tc))
break;
}
else
{
bool done = false;
VERUS_FOR(j, 4)
{
if (_vBinding1[i]._bw[j] > 0)
{
if (Continue::no == fn(_vBinding1[i]._bi[j], pos, nrm, tc))
{
done = true;
break;
}
}
}
if (done)
break;
}
}
}

View File

@ -39,7 +39,8 @@ void CubeMapBaker::Init(int side)
texDesc._format = CGI::Format::floatR11G11B10;
texDesc._width = _side;
texDesc._height = _side;
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::cubeMap;
texDesc._mipLevels = 0;
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::generateMips | CGI::TextureDesc::Flags::cubeMap;
_tex[TEX_COLOR].Init(texDesc);
texDesc.Reset();
texDesc._name = "CubeMapBaker.DepthTex";

View File

@ -592,7 +592,7 @@ void EditorTerrain::SplatFromFile(CSZ url, int layer)
{
VERUS_FOR(j, _mapSide)
{
const BYTE value = image._p[((i << _mapShift) + j) * image._bytesPerPixel];
const BYTE value = image._p[image._pixelStride * ((i << _mapShift) + j)];
const int ij[] = { i, j };
SplatTileAtEx(ij, layer, value / 255.f);
}

View File

@ -35,6 +35,7 @@ void Forest::InitStatic()
s_shader[SHADER_MAIN]->CreateDescriptorSet(0, &s_ubForestVS, sizeof(s_ubForestVS), 100, {}, CGI::ShaderStageFlags::vs);
s_shader[SHADER_MAIN]->CreateDescriptorSet(1, &s_ubForestFS, sizeof(s_ubForestFS), 100,
{
CGI::Sampler::linearMipL,
CGI::Sampler::linearMipL,
CGI::Sampler::linearMipL,
CGI::Sampler::linearMipL
@ -77,12 +78,12 @@ void Forest::Init(PTerrain pTerrain, CSZ url)
Scatter::TypeDesc(SCATTER_TYPE_5, 5),
Scatter::TypeDesc(SCATTER_TYPE_3, 3)
};
_scatter.Init(32, SCATTER_TYPE_COUNT, id, 19201);
_scatter.Init(s_scatterSide, SCATTER_TYPE_COUNT, id, 19201);
_scatter.SetDelegate(this);
_scatter.SetMaxDist(_maxDist * 1.25f);
_vPlants.reserve(16);
_vLayerPlants.reserve(16);
_vLayerData.reserve(16);
_vDrawPlants.resize(_capacity);
_vCollisionPool.Resize(1000);
@ -196,12 +197,12 @@ void Forest::Update()
// Time to get the size of this mesh.
plant._maxSize = plant.GetSize() * plant._maxScale;
BakeChunks(plant);
UpdateOcclusion(plant);
if (plant._maxSize > _maxSizeAll)
{
_maxSizeAll = plant._maxSize;
_pTerrain->FattenQuadtreeNodesBy(_maxSizeAll);
}
plant._aoSize = plant._mesh.GetBounds().GetAverageSize() * 1.5f;
}
if (!plant._tex[0] && plant._mesh.IsLoaded() && plant._material->IsLoaded())
@ -211,13 +212,15 @@ void Forest::Update()
{
if (plant._tex[Plant::TEX_GBUFFER_0] && plant._tex[Plant::TEX_GBUFFER_0]->IsLoaded() &&
plant._tex[Plant::TEX_GBUFFER_1] && plant._tex[Plant::TEX_GBUFFER_1]->IsLoaded() &&
plant._tex[Plant::TEX_GBUFFER_2] && plant._tex[Plant::TEX_GBUFFER_2]->IsLoaded())
plant._tex[Plant::TEX_GBUFFER_2] && plant._tex[Plant::TEX_GBUFFER_2]->IsLoaded() &&
plant._tex[Plant::TEX_GBUFFER_3] && plant._tex[Plant::TEX_GBUFFER_3]->IsLoaded())
{
plant._csh = s_shader[SHADER_MAIN]->BindDescriptorSetTextures(1,
{
plant._tex[Plant::TEX_GBUFFER_0],
plant._tex[Plant::TEX_GBUFFER_1],
plant._tex[Plant::TEX_GBUFFER_2]
plant._tex[Plant::TEX_GBUFFER_2],
plant._tex[Plant::TEX_GBUFFER_3]
});
VERUS_QREF_ATMO;
plant._cshSimple = s_shader[SHADER_SIMPLE]->BindDescriptorSetTextures(1,
@ -244,6 +247,8 @@ void Forest::Update()
}
if (allLoaded)
{
_pTerrain->UpdateOcclusion(this);
int vertCount = 0;
for (auto& plant : _vPlants)
{
@ -277,7 +282,7 @@ void Forest::Update()
const CGI::VertexInputAttrDesc viaDesc[] =
{
{0, offsetof(Vertex, _pos), CGI::ViaType::floats, 3, CGI::ViaUsage::position, 0},
{0, offsetof(Vertex, _tc), CGI::ViaType::shorts, 2, CGI::ViaUsage::texCoord, 0},
{0, offsetof(Vertex, _tc), CGI::ViaType::halfs, 2, CGI::ViaUsage::texCoord, 0},
CGI::VertexInputAttrDesc::End()
};
geoDesc._pVertexInputAttrDesc = viaDesc;
@ -296,6 +301,7 @@ void Forest::Update()
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
pipeDesc._topology = CGI::PrimitiveTopology::pointList;
_pipe[PIPE_MAIN].Init(pipeDesc);
}
@ -492,7 +498,7 @@ void Forest::DrawSprites()
s_ubForestVS._matWVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubForestVS._viewportSize = cb->GetViewportSize().GLM();
s_ubForestVS._eyePos = float4(sm.GetCamera()->GetEyePosition().GLM(), 0);
s_ubForestVS._eyePosScreen = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
s_ubForestVS._mainCameraEyePos = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
cb->BindPipeline(_pipe[drawingDepth ? PIPE_DEPTH : PIPE_MAIN]);
cb->BindVertexBuffers(_geo);
@ -512,72 +518,7 @@ void Forest::DrawSprites()
s_shader[SHADER_MAIN]->EndBindDescriptors();
}
void Forest::DrawAO()
{
if (!_visibleCount)
return;
VERUS_QREF_HELPERS;
VERUS_QREF_RENDERER;
CGI::LightType type = CGI::LightType::none;
PMesh pMesh = nullptr;
auto& ds = renderer.GetDS();
auto cb = renderer.GetCommandBuffer();
auto DrawMesh = [cb](PMesh pMesh)
{
if (pMesh && !pMesh->IsInstanceBufferEmpty(true))
{
pMesh->UpdateInstanceBuffer();
cb->DrawIndexed(pMesh->GetIndexCount(), pMesh->GetInstanceCount(true), 0, 0, pMesh->GetFirstInstance());
}
};
for (int i = 0; i <= _visibleCount; ++i)
{
if (i == _visibleCount) // The end?
{
DrawMesh(pMesh);
break;
}
RcDrawPlant drawPlant = _vDrawPlants[i];
RPlant plant = _vPlants[drawPlant._plantIndex];
const CGI::LightType nextType = CGI::LightType::omni;
if (nextType != type)
{
DrawMesh(pMesh);
type = nextType;
ds.OnNewAOType(cb, type);
pMesh = (type != CGI::LightType::none) ? &helpers.GetDeferredLights().Get(type) : nullptr;
if (pMesh)
{
pMesh->MarkFirstInstance();
pMesh->BindGeo(cb, (1 << 0) | (1 << 4));
pMesh->CopyPosDeqScale(&ds.GetUbAOPerMeshVS()._posDeqScale.x);
pMesh->CopyPosDeqBias(&ds.GetUbAOPerMeshVS()._posDeqBias.x);
ds.BindDescriptorsAOPerMeshVS(cb);
}
}
if (pMesh)
{
const float size = drawPlant._scale * plant._aoSize;
const Transform3 matW = VMath::appendScale(Transform3(Matrix3::identity(),
Vector3(drawPlant._pos + drawPlant._pushBack + Vector3(0, size * 0.25f, 0))), Vector3::Replicate(size));
pMesh->PushInstance(matW, Vector4::Replicate(1));
}
}
}
void Forest::DrawSimple(DrawSimpleMode mode)
void Forest::DrawSimple(DrawSimpleMode mode, CGI::CubeMapFace cubeMapFace)
{
if (!_geo)
return;
@ -587,18 +528,53 @@ void Forest::DrawSimple(DrawSimpleMode mode)
VERUS_QREF_SM;
VERUS_QREF_WATER;
const float clipDistanceOffset = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? static_cast<float>(USHRT_MAX) : 0.f;
const float pointSpriteScaleY = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? 1.f : -1.f;
const float clipDistanceOffset = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? static_cast<float>(USHRT_MAX) : -4.f;
const float pointSpriteFlipY = (water.IsUnderwater() || DrawSimpleMode::envMap == mode) ? 1.f : -1.f;
Vector3 normalFlip(1, 1, 1);
Vector3 tcFlip(1, 1, 0);
if (DrawSimpleMode::envMap == mode)
{
switch (cubeMapFace)
{
case CGI::CubeMapFace::posX:
case CGI::CubeMapFace::negX:
{
normalFlip = Vector3(-1, 1, -1);
tcFlip = Vector3(-1, 1, 0);
}
break;
case CGI::CubeMapFace::posY:
case CGI::CubeMapFace::negY:
{
normalFlip = Vector3(1, 1, -1);
tcFlip = Vector3(1, -1, 0);
}
break;
case CGI::CubeMapFace::posZ:
case CGI::CubeMapFace::negZ:
{
normalFlip = Vector3(-1, 1, -1);
tcFlip = Vector3(-1, 1, 0);
}
break;
}
}
else
{
normalFlip = Vector3(1, -1, 1);
}
auto cb = renderer.GetCommandBuffer();
s_ubSimpleForestVS._matP = sm.GetCamera()->GetMatrixP().UniformBufferFormat();
s_ubSimpleForestVS._matWVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubSimpleForestVS._viewportSize = renderer.GetCommandBuffer()->GetViewportSize().GLM();
s_ubSimpleForestVS._viewportSize = cb->GetViewportSize().GLM();
s_ubSimpleForestVS._eyePos_clipDistanceOffset = float4(sm.GetCamera()->GetEyePosition().GLM(), clipDistanceOffset);
s_ubSimpleForestVS._eyePosScreen = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
s_ubSimpleForestVS._pointSpriteScale = float4(1, pointSpriteScaleY, 0, 0);
s_ubSimpleForestVS._mainCameraEyePos_pointSpriteFlipY = float4(sm.GetMainCamera()->GetEyePosition().GLM(), pointSpriteFlipY);
s_ubSimpleForestFS._matInvV = sm.GetCamera()->GetMatrixInvV().UniformBufferFormat();
s_ubSimpleForestFS._normalFlip = float4(normalFlip.GLM(), 0);
s_ubSimpleForestFS._tcFlip = float4(tcFlip.GLM(), 0);
s_ubSimpleForestFS._ambientColor = float4(atmo.GetAmbientColor().GLM(), 0);
s_ubSimpleForestFS._fogColor = Vector4(atmo.GetFogColor(), atmo.GetFogDensity()).GLM();
s_ubSimpleForestFS._dirToSun = float4(atmo.GetDirToSun().GLM(), 0);
@ -669,9 +645,9 @@ void Forest::UpdateCollision(const Vector<Vector4>& vZones)
VERUS_QREF_SM;
const int layer = _pTerrain->GetMainLayerAt(ij);
if (layer >= _vLayerPlants.size())
if (layer >= _vLayerData.size())
continue;
const int plantIndex = _vLayerPlants[layer]._plants[type];
const int plantIndex = _vLayerData[layer]._plants[type];
if (plantIndex < 0)
continue;
RPlant plant = _vPlants[plantIndex];
@ -700,7 +676,7 @@ void Forest::UpdateCollision(const Vector<Vector4>& vZones)
Scatter::RcInstance instance = _scatter.GetInstanceAt(ij);
const int type = instance._type;
const int layer = _pTerrain->GetMainLayerAt(ij);
const int plantIndex = _vLayerPlants[layer]._plants[type];
const int plantIndex = _vLayerData[layer]._plants[type];
RPlant plant = _vPlants[plantIndex];
const float h = _pTerrain->GetHeightAt(ij);
@ -775,8 +751,8 @@ float Forest::GetMinHeight(const int ij[2], float h) const
void Forest::SetLayer(int layer, RcLayerDesc desc)
{
if (_vLayerPlants.size() < layer + 1)
_vLayerPlants.resize(layer + 1);
if (_vLayerData.size() < layer + 1)
_vLayerData.resize(layer + 1);
Random random(2247 + layer);
@ -788,11 +764,11 @@ void Forest::SetLayer(int layer, RcLayerDesc desc)
const int plantIndex = FindPlant(plantDesc._url);
if (plantIndex >= 0)
{
_vLayerPlants[layer]._plants[type] = plantIndex;
_vLayerData[layer]._plants[type] = plantIndex;
}
else // Add new plant?
{
_vLayerPlants[layer]._plants[type] = Utils::Cast32(_vPlants.size());
_vLayerData[layer]._plants[type] = Utils::Cast32(_vPlants.size());
_vPlants.resize(_vPlants.size() + 1);
RPlant plant = _vPlants[_vPlants.size() - 1];
plant._url = plantDesc._url;
@ -843,7 +819,7 @@ void Forest::BakeChunks(RPlant plant)
const int ij[] = { iOffset + i, jOffset + j };
const int layer = _pTerrain->GetMainLayerAt(ij);
if (layer >= _vLayerPlants.size())
if (layer >= _vLayerData.size())
continue;
if (_pTerrain->GetNormalAt(ij)[1] < plant._allowedNormal)
@ -851,8 +827,8 @@ void Forest::BakeChunks(RPlant plant)
VERUS_FOR(type, SCATTER_TYPE_COUNT)
{
const int index = _vLayerPlants[layer]._plants[type];
if (index >= 0 && &plant == &_vPlants[index])
const int plantIndex = _vLayerData[layer]._plants[type];
if (plantIndex >= 0 && &plant == &_vPlants[plantIndex])
{
Scatter::RcInstance instance = _scatter.GetInstanceAt(ij);
if (type == instance._type)
@ -872,8 +848,8 @@ void Forest::BakeChunks(RPlant plant)
Vertex v;
v._pos = pos.GLM();
v._tc[0] = Math::Clamp<int>(static_cast<int>(psize * 500), 0, SHRT_MAX);
v._tc[1] = Math::Clamp<int>(static_cast<int>(instance._angle * SHRT_MAX / VERUS_2PI), 0, SHRT_MAX);
v._tc[0] = Convert::FloatToHalf(psize);
v._tc[1] = Convert::FloatToHalf(instance._angle / VERUS_2PI);
v._pos.y += psize * 0.5f / _margin - psize * 0.05f;
if (!bc._vSprites.capacity())
bc._vSprites.reserve(256);
@ -897,11 +873,67 @@ void Forest::BakeChunks(RPlant plant)
}
}
void Forest::UpdateOcclusion(RPlant plant)
{
VERUS_FOR(layer, _vLayerData.size())
{
VERUS_FOR(type, SCATTER_TYPE_COUNT)
{
const int plantIndex = _vLayerData[layer]._plants[type];
if (plantIndex >= 0 && &plant == &_vPlants[plantIndex])
{
VERUS_FOR(i, s_scatterSide)
{
VERUS_FOR(j, s_scatterSide)
{
const int ij[] = { i, j };
Scatter::RcInstance instance = _scatter.GetInstanceAt(ij);
if (type == instance._type)
{
const float scale = plant._vScales[instance._rand % plant._vScales.size()];
const float size = plant.GetSize() * scale;
AddOcclusionAt(ij, layer, 3 + static_cast<int>(size + 0.5f));
}
}
}
}
}
}
}
void Forest::AddOcclusionAt(const int ij[2], int layer, int radius)
{
radius = Math::Clamp(radius, 1, 15);
const int mask = s_scatterSide - 1;
const int radiusSq = radius * radius;
for (int di = -radius; di <= radius; ++di)
{
const int ki = ij[0] + di;
const int mi = (ki + s_scatterSide) & mask;
for (int dj = -radius; dj <= radius; ++dj)
{
const int kj = ij[1] + dj;
const int mj = (kj + s_scatterSide) & mask;
const int lenSq = di * di + dj * dj;
if (lenSq > radiusSq)
continue;
const float a = static_cast<float>(lenSq) / radiusSq;
const float b = 0xFF * pow(a, 0.3f);
const float c = Math::Clamp(b, 128.f - radius * radius, 255.f);
const BYTE value = static_cast<BYTE>(c);
BYTE& dst = _vLayerData[layer]._occlusion[mi * s_scatterSide + mj];
dst = Math::CombineOcclusion(dst, value);
}
}
}
bool Forest::LoadSprite(RPlant plant)
{
int count = 0;
const CSZ ext[] = { "", ".FX", ".FX" };
VERUS_FOR(i, 3)
const CSZ ext[] = { "", ".X", ".X", ".X" };
VERUS_FOR(i, 4)
{
String pathname = _C(plant._mesh.GetUrl());
char filename[20];
@ -916,7 +948,7 @@ bool Forest::LoadSprite(RPlant plant)
plant._tex[i].Init(_C(pathname));
}
}
return 3 == count;
return 4 == count;
}
void Forest::BakeSprite(RPlant plant, CSZ url)
@ -932,7 +964,7 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
cb.InitOneTimeSubmit();
const int frameSide = 512;
const int framePad = 16;
const int framePad = 4;
const int frameCountH = 16;
const int frameCountV = 16;
const int texWidth = frameCountH * frameSide;
@ -945,6 +977,7 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
CGI::RP::Attachment("GBuffer0", CGI::Format::srgbR8G8B8A8).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly),
CGI::RP::Attachment("GBuffer1", CGI::Format::unormR10G10B10A2).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly),
CGI::RP::Attachment("GBuffer2", CGI::Format::unormR8G8B8A8).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly),
CGI::RP::Attachment("GBuffer3", CGI::Format::unormR8G8B8A8).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly),
CGI::RP::Attachment("Depth", CGI::Format::unormD24uintS8).LoadOpClear().Layout(CGI::ImageLayout::depthStencilAttachment),
},
{
@ -952,26 +985,41 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
{
CGI::RP::Ref("GBuffer0", CGI::ImageLayout::colorAttachment),
CGI::RP::Ref("GBuffer1", CGI::ImageLayout::colorAttachment),
CGI::RP::Ref("GBuffer2", CGI::ImageLayout::colorAttachment)
CGI::RP::Ref("GBuffer2", CGI::ImageLayout::colorAttachment),
CGI::RP::Ref("GBuffer3", CGI::ImageLayout::colorAttachment)
}).DepthStencil(CGI::RP::Ref("Depth", CGI::ImageLayout::depthStencilAttachment))
},
{});
CGI::TexturePwn texGB[3], texDepth;
if (!_pipe[PIPE_MESH_BAKE])
{
CGI::PipelineDesc pipeDesc(plant._mesh.GetGeometry(), Scene::Mesh::GetShader(), "#", rph);
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
pipeDesc._vertexInputBindingsFilter = plant._mesh.GetBindingsMask();
_pipe[PIPE_MESH_BAKE].Init(pipeDesc);
}
CGI::TexturePwn texGB[4], texDepth;
CGI::TextureDesc texDesc;
texDesc._width = texWidth;
texDesc._height = texHeight;
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment;
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer0();
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer0(0.5f);
texDesc._format = CGI::Format::srgbR8G8B8A8;
texGB[0].Init(texDesc);
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer1();
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer1(0.5f, 0);
texDesc._format = CGI::Format::unormR10G10B10A2;
texGB[1].Init(texDesc);
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer2();
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer2(0.5f);
texDesc._format = CGI::Format::unormR8G8B8A8;
texGB[2].Init(texDesc);
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer3(0.5f);
texDesc._format = CGI::Format::unormR8G8B8A8;
texGB[3].Init(texDesc);
texDesc.Reset();
texDesc._clearValue = Vector4(1);
texDesc._format = CGI::Format::unormD24uintS8;
@ -984,6 +1032,7 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
texGB[0],
texGB[1],
texGB[2],
texGB[3],
texDepth
},
texWidth,
@ -994,13 +1043,14 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
texGB[0]->GetClearValue(),
texGB[1]->GetClearValue(),
texGB[2]->GetClearValue(),
texGB[3]->GetClearValue(),
texDepth->GetClearValue()
});
plant._mesh.BindPipeline(cb, false);
cb->BindPipeline(_pipe[PIPE_MESH_BAKE]);
plant._mesh.BindGeo(cb);
Mesh::GetShader()->BeginBindDescriptors();
plant._material->UpdateMeshUniformBuffer();
plant._material->UpdateMeshUniformBuffer(1, false);
cb->BindDescriptors(Scene::Mesh::GetShader(), 1, plant._material->GetComplexSetHandle());
plant._mesh.UpdateUniformBufferPerMeshVS();
cb->BindDescriptors(Scene::Mesh::GetShader(), 2);
@ -1048,7 +1098,7 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
cb->EndRenderPass();
CGI::TexturePwn texFinalGB[3];
CGI::TexturePwn texFinalGB[4];
texDesc.Reset();
texDesc._width = texWidth;
texDesc._height = texHeight;
@ -1056,19 +1106,22 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
texDesc._flags = CGI::TextureDesc::Flags::colorAttachment | CGI::TextureDesc::Flags::generateMips;
texDesc._readbackMip = 2;
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer0();
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer0(0.5f);
texDesc._format = CGI::Format::srgbR8G8B8A8;
texFinalGB[0].Init(texDesc);
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer1();
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer1(0.5f, 0);
texDesc._format = CGI::Format::unormR8G8B8A8;
texFinalGB[1].Init(texDesc);
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer2();
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer2(0.5f);
texDesc._format = CGI::Format::unormR8G8B8A8;
texFinalGB[2].Init(texDesc);
texDesc._clearValue = CGI::DeferredShading::GetClearValueForGBuffer3(0.5f);
texDesc._format = CGI::Format::unormR8G8B8A8;
texFinalGB[3].Init(texDesc);
renderer.GetDS().BakeSprites(texGB, texFinalGB, cb.Get());
VERUS_FOR(i, 3)
VERUS_FOR(i, 4)
{
texFinalGB[i]->GenerateMips(cb.Get());
texFinalGB[i]->ReadbackSubresource(nullptr, true, cb.Get());
@ -1080,8 +1133,8 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
const int mipHeight = texHeight / 4;
Vector<UINT32> vData;
vData.resize(mipWidth * mipHeight);
const CSZ ext[] = { "", ".FX", ".FX" };
VERUS_FOR(i, 3)
const CSZ ext[] = { "", ".X", ".X", ".X" };
VERUS_FOR(i, 4)
{
texFinalGB[i]->ReadbackSubresource(vData.data(), false);
@ -1098,6 +1151,7 @@ void Forest::BakeSprite(RPlant plant, CSZ url)
renderer->DeleteFramebuffer(fbh);
renderer->DeleteRenderPass(rph);
renderer->DeleteCommandBuffer(cb.Detach());
_pipe[PIPE_MESH_BAKE].Done();
}
bool Forest::BakeSprites(CSZ url)
@ -1120,9 +1174,9 @@ void Forest::Scatter_AddInstance(const int ij[2], int type, float x, float z, fl
VERUS_QREF_SM;
const int layer = _pTerrain->GetMainLayerAt(ij);
if (layer >= _vLayerPlants.size())
if (layer >= _vLayerData.size())
return;
const int plantIndex = _vLayerPlants[layer]._plants[type];
const int plantIndex = _vLayerData[layer]._plants[type];
if (plantIndex < 0)
return;
@ -1179,3 +1233,13 @@ Continue Forest::Octree_ProcessNode(void* pToken, void* pUser)
pBakedChunk->_visible = sm.GetMainCamera()->GetFrustum().ContainsAabb(pBakedChunk->_bounds) != Relation::outside;
return Continue::yes;
}
BYTE Forest::GetOcclusionAt(const int ij[2], int layer) const
{
if (layer >= _vLayerData.size())
return 0xFF;
const int mask = s_scatterSide - 1;
const int i = ij[0] & mask;
const int j = ij[1] & mask;
return _vLayerData[layer]._occlusion[i * s_scatterSide + j];
}

View File

@ -23,6 +23,7 @@ namespace verus
PIPE_DEPTH,
PIPE_SIMPLE_ENV_MAP,
PIPE_SIMPLE_PLANAR_REF,
PIPE_MESH_BAKE,
PIPE_COUNT
};
@ -40,11 +41,13 @@ namespace verus
SCATTER_TYPE_COUNT
};
static const int s_scatterSide = 32;
private:
struct Vertex
{
glm::vec3 _pos;
short _tc[2]; // psize, angle.
half _tc[2]; // {psize, angle}
};
VERUS_TYPEDEFS(Vertex);
@ -101,39 +104,41 @@ namespace verus
TEX_GBUFFER_0,
TEX_GBUFFER_1,
TEX_GBUFFER_2,
TEX_GBUFFER_3,
TEX_COUNT
};
String _url;
Mesh _mesh;
MaterialPwn _material;
CGI::TexturePwns<TEX_COUNT> _tex;
CGI::CSHandle _csh;
CGI::CSHandle _cshSimple;
Vector<BakedChunk> _vBakedChunks;
Vector<float> _vScales;
float _alignToNormal = 1;
float _maxScale = 0;
float _maxSize = 0;
float _windBending = 1;
float _aoSize = 1;
char _allowedNormal = 116;
String _url;
Mesh _mesh;
MaterialPwn _material;
CGI::TexturePwns<TEX_COUNT> _tex;
CGI::CSHandle _csh;
CGI::CSHandle _cshSimple;
Vector<BakedChunk> _vBakedChunks;
Vector<float> _vScales;
float _alignToNormal = 1;
float _maxScale = 0;
float _maxSize = 0;
float _windBending = 1;
char _allowedNormal = 116;
float GetSize() const;
};
VERUS_TYPEDEFS(Plant);
class LayerPlants
class LayerData
{
public:
char _plants[SCATTER_TYPE_COUNT];
BYTE _occlusion[s_scatterSide * s_scatterSide];
LayerPlants()
LayerData()
{
std::fill(_plants, _plants + SCATTER_TYPE_COUNT, -1);
std::fill(_occlusion, _occlusion + sizeof(_occlusion), 0xFF);
}
};
VERUS_TYPEDEFS(LayerPlants);
VERUS_TYPEDEFS(LayerData);
class DrawPlant
{
@ -161,7 +166,7 @@ namespace verus
Math::Octree _octree;
Scatter _scatter;
Vector<Plant> _vPlants;
Vector<LayerPlants> _vLayerPlants;
Vector<LayerData> _vLayerData;
Vector<DrawPlant> _vDrawPlants;
DifferenceVector<CollisionPlant> _vCollisionPlants;
Pool<CollisionPoolBlock> _vCollisionPool;
@ -182,12 +187,12 @@ namespace verus
public:
CSZ _url = nullptr;
float _alignToNormal = 1;
float _minScale = 0.5f;
float _maxScale = 1.5f;
float _minScale = 0.8f;
float _maxScale = 1.25f;
float _windBending = 1;
char _allowedNormal = 116;
void Set(CSZ url, float alignToNormal = 1, float minScale = 0.5f, float maxScale = 1.5f, float windBending = 1, char allowedNormal = 116)
void Set(CSZ url, float alignToNormal = 1, float minScale = 0.8f, float maxScale = 1.25f, float windBending = 1, char allowedNormal = 116)
{
_url = url;
_alignToNormal = alignToNormal;
@ -223,8 +228,7 @@ namespace verus
void Draw(bool allowTess = true);
VERUS_P(void DrawModels(bool allowTess));
VERUS_P(void DrawSprites());
void DrawAO();
void DrawSimple(DrawSimpleMode mode);
void DrawSimple(DrawSimpleMode mode, CGI::CubeMapFace cubeMapFace = CGI::CubeMapFace::none);
void UpdateCollision(const Vector<Vector4>& vZones);
@ -235,6 +239,9 @@ namespace verus
void SetLayer(int layer, RcLayerDesc desc);
VERUS_P(int FindPlant(CSZ url) const);
VERUS_P(void BakeChunks(RPlant plant));
VERUS_P(void UpdateOcclusion(RPlant plant));
VERUS_P(void AddOcclusionAt(const int ij[2], int layer, int radius));
bool LoadSprite(RPlant plant);
void BakeSprite(RPlant plant, CSZ url);
bool BakeSprites(CSZ url);
@ -243,6 +250,8 @@ namespace verus
float scale, float angle, UINT32 r) override;
virtual Continue Octree_ProcessNode(void* pToken, void* pUser) override;
BYTE GetOcclusionAt(const int ij[2], int layer) const;
};
VERUS_TYPEDEFS(Forest);
}

View File

@ -109,6 +109,7 @@ void Grass::Init(RTerrain terrain, CSZ atlasUrl)
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
_pipe[PIPE_MAIN].Init(pipeDesc);
}
@ -117,6 +118,7 @@ void Grass::Init(RTerrain terrain, CSZ atlasUrl)
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
pipeDesc._topology = CGI::PrimitiveTopology::pointList;
_pipe[PIPE_BILLBOARDS].Init(pipeDesc);
}
@ -158,8 +160,11 @@ void Grass::Init(RTerrain terrain, CSZ atlasUrl)
void Grass::Done()
{
s_shader->FreeDescriptorSet(_cshVS);
s_shader->FreeDescriptorSet(_cshFS);
if (s_shader)
{
s_shader->FreeDescriptorSet(_cshVS);
s_shader->FreeDescriptorSet(_cshFS);
}
VERUS_DONE(Grass);
}
@ -181,10 +186,10 @@ void Grass::Update()
_phase = glm::fract(_phase + dt * 2.3f);
const float windSpeed = atmo.GetWindSpeed();
const float warpStrength = Math::Clamp<float>(windSpeed * (1 / 13.f), 0, 1.f);
const float turbulence = Math::Clamp<float>(windSpeed * (1 / 17.f), 0, 0.4f);
const float warpStrength = Math::Clamp<float>(windSpeed * 0.04f, 0, 1.f);
const float turbulence = Math::Clamp<float>(windSpeed * 0.04f, 0, 0.4f);
_warpSpring.Update(atmo.GetWindDirection() * (warpStrength * 30.f));
_warpSpring.Update(atmo.GetWindDirection() * (warpStrength * 20.f));
_turbulence = turbulence * turbulence;
// Async texture loading:
@ -239,9 +244,9 @@ void Grass::Draw()
s_ubGrassVS._matWV = sm.GetCamera()->GetMatrixV().UniformBufferFormat();
s_ubGrassVS._matVP = sm.GetCamera()->GetMatrixVP().UniformBufferFormat();
s_ubGrassVS._matP = sm.GetCamera()->GetMatrixP().UniformBufferFormat();
s_ubGrassVS._phase_mapSideInv_bushMask.x = _phase;
s_ubGrassVS._phase_mapSideInv_bushMask.y = 1.f / _mapSide;
s_ubGrassVS._phase_mapSideInv_bushMask.z = *(float*)&bushMask;
s_ubGrassVS._phase_invMapSide_bushMask.x = _phase;
s_ubGrassVS._phase_invMapSide_bushMask.y = 1.f / _mapSide;
s_ubGrassVS._phase_invMapSide_bushMask.z = *(float*)&bushMask;
s_ubGrassVS._posEye = float4(sm.GetMainCamera()->GetEyePosition().GLM(), 0);
s_ubGrassVS._viewportSize = cb->GetViewportSize().GLM();
s_ubGrassVS._warp_turb = Vector4(_warpSpring.GetOffset(), _turbulence).GLM();
@ -456,7 +461,7 @@ void Grass::LoadLayersFromFile(CSZ url)
for (auto node : root.children("grass"))
{
const int id = node.attribute("id").as_int();
SetTexture(id, node.attribute("url").value(), node.attribute("urlEx").value());
SetTexture(id, node.attribute("url").value(), node.attribute("url2").value());
}
}
@ -473,7 +478,7 @@ void Grass::SetTexture(int layer, CSZ url, CSZ url2)
VERUS_RT_ASSERT(url);
_texLoaded[layer].LoadDDS(url);
if (layer < 8)
SetTexture(layer + 8, url2 ? url2 : url);
SetTexture(layer + 8, (url2 && *url2) ? url2 : url);
}
void Grass::SaveTexture(CSZ url)

View File

@ -38,6 +38,12 @@ void LightMapBaker::Init(RcDesc desc)
case Mode::faces:
{
_repsPerUpdate = Math::Max<int>(1, Utils::Cast32(_vMap.size()) / 100);
std::fill(_vMap.begin(), _vMap.end(), VERUS_COLOR_RGBA(0, 0, 0, 255));
}
break;
case Mode::ambientOcclusion:
{
std::fill(_vMap.begin(), _vMap.end(), VERUS_COLOR_RGBA(255, 255, 255, 0));
}
break;
}
@ -80,6 +86,9 @@ void LightMapBaker::Init(RcDesc desc)
_quadtree.BindElement(element);
}
if (Mode::faces == GetMode())
return;
_rph = renderer->CreateRenderPass(
{
CGI::RP::Attachment("Color", CGI::Format::floatR32).LoadOpClear().Layout(CGI::ImageLayout::fsReadOnly),
@ -232,14 +241,25 @@ void LightMapBaker::Update()
const BYTE value8 = Convert::UnormToUint8(Math::Clamp<float>(value * _normalizationFactor, 0, 1));
BYTE* pDst = reinterpret_cast<BYTE*>(_vQueued[ringBufferIndex][i]._pDst);
VERUS_FOR(j, 3)
pDst[j] = Math::Max(pDst[j], value8);
pDst[3] = 0xFF;
if (pDst[3]) // Already has some data?
{
VERUS_FOR(j, 3)
pDst[j] = Math::Max(pDst[j], value8);
}
else // Empty?
{
VERUS_FOR(j, 3)
pDst[j] = value8;
pDst[3] = 0xFF;
}
}
}
// Clear queued:
memset(_vQueued[ringBufferIndex].data(), 0, sizeof(Queued) * s_batchSize);
queuedCount = 0;
if (!_vQueued[ringBufferIndex].empty())
{
memset(_vQueued[ringBufferIndex].data(), 0, sizeof(Queued) * s_batchSize);
queuedCount = 0;
}
if (_currentI >= _desc._texHeight)
{
@ -254,7 +274,8 @@ void LightMapBaker::Update()
}
if (finish)
{
ComputeEdgePadding();
if (Mode::faces != GetMode())
ComputeEdgePadding();
Save();
_desc._mode = Mode::idle;
}
@ -304,7 +325,7 @@ void LightMapBaker::Update()
void LightMapBaker::Draw()
{
if (!IsInitialized() || !IsBaking())
if (!IsInitialized() || !IsBaking() || Mode::faces == GetMode())
return;
VERUS_QREF_RENDERER;
@ -313,6 +334,10 @@ void LightMapBaker::Draw()
auto cb = renderer.GetCommandBuffer();
auto shader = renderer.GetShaderQuad();
renderer.GetUbQuadVS()._matW = Math::QuadMatrix().UniformBufferFormat();
renderer.GetUbQuadVS()._matV = Math::ToUVMatrix().UniformBufferFormat();
renderer.ResetQuadMultiplexer();
cb->BindPipeline(_pipe[PIPE_QUAD]);
shader->BeginBindDescriptors();
cb->BindDescriptors(shader, 0);
@ -351,6 +376,11 @@ void LightMapBaker::DrawHemicubeMask()
auto shader = renderer.GetShaderQuad();
const float side = static_cast<float>(_desc._texLumelSide);
renderer.GetUbQuadVS()._matW = Math::QuadMatrix().UniformBufferFormat();
renderer.GetUbQuadVS()._matV = Math::ToUVMatrix().UniformBufferFormat();
renderer.ResetQuadMultiplexer();
cb->BindPipeline(_pipe[PIPE_HEMICUBE_MASK]);
cb->SetViewport({ Vector4(0, 0, side, side) });
shader->BeginBindDescriptors();
@ -464,6 +494,7 @@ Continue LightMapBaker::Quadtree_ProcessNode(void* pToken, void* pUser)
RQueued queued = _vQueued[ringBufferIndex][queuedCount];
queued._pos = pos;
queued._nrm = glm::normalize(nrm);
queued._pos += Vector3(nrm) * _desc._bias;
queued._pDst = &_vMap[index];
_currentLayer++;
@ -477,50 +508,12 @@ Continue LightMapBaker::Quadtree_ProcessNode(void* pToken, void* pUser)
return Continue::yes;
}
void LightMapBaker::ComputeEdgePadding(int radius)
void LightMapBaker::ComputeEdgePadding()
{
const int radiusSq = radius * radius;
VERUS_P_FOR(i, _desc._texHeight)
{
const int offset = i * _desc._texWidth;
VERUS_FOR(j, _desc._texWidth)
{
BYTE* pOriginChannels = reinterpret_cast<BYTE*>(&_vMap[offset + j]);
if (pOriginChannels[3])
continue;
int minRadiusSq = INT_MAX;
BYTE color[4] = {};
for (int di = -radius; di <= radius; ++di)
{
const int ki = i + di;
if (ki < 0 || ki >= _desc._texHeight)
continue;
for (int dj = -radius; dj <= radius; ++dj)
{
const int kj = j + dj;
if (kj < 0 || kj >= _desc._texWidth)
continue;
if (!di && !dj)
continue;
const int lenSq = di * di + dj * dj;
if (lenSq > radiusSq)
continue;
BYTE* pKernelChannels = reinterpret_cast<BYTE*>(&_vMap[ki * _desc._texWidth + kj]);
if (!pKernelChannels[3])
continue;
if (lenSq < minRadiusSq)
{
minRadiusSq = lenSq;
memcpy(color, pKernelChannels, 3);
}
}
}
if (minRadiusSq != INT_MAX)
memcpy(pOriginChannels, color, 3);
}
});
Utils::ComputeEdgePadding(
reinterpret_cast<BYTE*>(_vMap.data()) + 0, sizeof(UINT32),
reinterpret_cast<BYTE*>(_vMap.data()) + 3, sizeof(UINT32),
_desc._texWidth, _desc._texHeight);
}
void LightMapBaker::Save()
@ -528,10 +521,16 @@ void LightMapBaker::Save()
IO::FileSystem::SaveImage(_C(_pathname), _vMap.data(), _desc._texWidth, _desc._texHeight, IO::ImageFormat::extension);
}
void LightMapBaker::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
void LightMapBaker::BindPipeline(RcMesh mesh, CGI::CommandBufferPtr cb)
{
VERUS_RT_ASSERT(pipe >= PIPE_MESH_SIMPLE_BAKE_AO && pipe <= PIPE_MESH_SIMPLE_BAKE_AO_SKINNED);
static const PIPE pipes[] =
{
PIPE_MESH_SIMPLE_BAKE_AO,
PIPE_MESH_SIMPLE_BAKE_AO_INSTANCED,
PIPE_MESH_SIMPLE_BAKE_AO_ROBOTIC,
PIPE_MESH_SIMPLE_BAKE_AO_SKINNED
};
const PIPE pipe = pipes[mesh.GetPipelineIndex()];
if (!_pipe[pipe])
{
static CSZ branches[] =
@ -541,11 +540,10 @@ void LightMapBaker::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
"#BakeAORobotic",
"#BakeAOSkinned"
};
CGI::PipelineDesc pipeDesc(_desc._pMesh->GetGeometry(), Mesh::GetSimpleShader(), branches[pipe], _rph);
pipeDesc._vertexInputBindingsFilter = _desc._pMesh->GetBindingsMask();
CGI::PipelineDesc pipeDesc(mesh.GetGeometry(), Mesh::GetSimpleShader(), branches[pipe], _rph);
pipeDesc._vertexInputBindingsFilter = mesh.GetBindingsMask();
_pipe[pipe].Init(pipeDesc);
}
cb->BindPipeline(_pipe[pipe]);
}

View File

@ -91,6 +91,7 @@ namespace verus
int _texHeight = 256;
int _texLumelSide = 128;
float _distance = 2;
float _bias = 0.001f;
};
VERUS_TYPEDEFS(Desc);
@ -147,10 +148,10 @@ namespace verus
RcStats GetStats() const { return _stats; }
float GetProgress() const { return _stats._progress; }
void ComputeEdgePadding(int radius = 32);
void ComputeEdgePadding();
void Save();
void BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb);
void BindPipeline(RcMesh mesh, CGI::CommandBufferPtr cb);
void SetViewportFor(CGI::CubeMapFace cubeMapFace, CGI::CommandBufferPtr cb);
};
VERUS_TYPEDEFS(LightMapBaker);

View File

@ -47,57 +47,62 @@ bool Texture::Done()
void Texture::Update()
{
if (_streamParts)
UpdateStreaming();
}
void Texture::UpdateStreaming()
{
if (!_streamParts)
return;
VERUS_QREF_RENDERER;
// Check if the next huge texture is loaded:
const int nextHuge = (_currentHuge + 1) & 0x1;
if (_loading && _texHuge[nextHuge] && _texHuge[nextHuge]->IsLoaded())
{
VERUS_QREF_RENDERER;
_loading = false;
_currentHuge = nextHuge; // Use it.
_nextSafeFrame = renderer.GetFrameCount() + CGI::BaseRenderer::s_ringBufferSize + 1;
}
// Check if the next huge texture is loaded:
const int nextHuge = (_currentHuge + 1) & 0x1;
if (_loading && _texHuge[nextHuge] && _texHuge[nextHuge]->IsLoaded())
const bool safeFrame = !_loading && (renderer.GetFrameCount() >= _nextSafeFrame);
if (safeFrame)
{
const int prevHuge = (_currentHuge + 1) & 0x1;
if (_texHuge[prevHuge]) // Garbage collection (next huge texture must be empty).
_texHuge[prevHuge].Done();
const int maxPart = _texTiny->GetPart();
if (maxPart > 0) // Must have at least two parts: 0 and 1.
{
_loading = false;
_currentHuge = nextHuge; // Use it.
_nextSafeFrame = renderer.GetFrameCount() + CGI::BaseRenderer::s_ringBufferSize + 1;
}
const float reqPart = Math::Min<float>(_requestedPart, SHRT_MAX);
const bool safeFrame = !_loading && (renderer.GetFrameCount() >= _nextSafeFrame);
if (safeFrame)
{
const int prevHuge = (_currentHuge + 1) & 0x1;
if (_texHuge[prevHuge]) // Garbage collection (next huge texture must be empty).
_texHuge[prevHuge].Done();
const bool hugeReady = (_texHuge[_currentHuge] && _texHuge[_currentHuge]->IsLoaded());
const int currentPart = hugeReady ? _texHuge[_currentHuge]->GetPart() : maxPart;
int newPart = currentPart;
const int maxPart = _texTiny->GetPart();
if (maxPart > 0) // Must have at least two parts: 0 and 1.
if (reqPart < currentPart) // Increase texture?
newPart = static_cast<int>(reqPart);
if (reqPart > currentPart + 1.5f) // Decrease texture?
newPart = static_cast<int>(reqPart);
newPart = Math::Clamp(newPart, 0, maxPart);
if (_texHuge[_currentHuge] && (newPart == maxPart)) // Unload huge texture, use tiny?
{
const float reqPart = Math::Min<float>(_requestedPart, SHRT_MAX);
_currentHuge = (_currentHuge + 1) & 0x1; // Go to empty huge texture.
_nextSafeFrame = renderer.GetFrameCount() + CGI::BaseRenderer::s_ringBufferSize;
}
else if (newPart != currentPart) // Change part?
{
_loading = true;
const int nextHuge = (_currentHuge + 1) & 0x1;
const bool hugeReady = (_texHuge[_currentHuge] && _texHuge[_currentHuge]->IsLoaded());
const int currentPart = hugeReady ? _texHuge[_currentHuge]->GetPart() : maxPart;
int newPart = currentPart;
if (reqPart < currentPart) // Increase texture?
newPart = static_cast<int>(reqPart);
if (reqPart > currentPart + 1.5f) // Decrease texture?
newPart = static_cast<int>(reqPart);
newPart = Math::Clamp(newPart, 0, maxPart);
if (_texHuge[_currentHuge] && (newPart == maxPart)) // Unload huge texture, use tiny?
{
_currentHuge = (_currentHuge + 1) & 0x1; // Go to empty huge texture.
_nextSafeFrame = renderer.GetFrameCount() + CGI::BaseRenderer::s_ringBufferSize;
}
else if (newPart != currentPart) // Change part?
{
_loading = true;
const int nextHuge = (_currentHuge + 1) & 0x1;
CGI::TextureDesc texDesc;
texDesc._url = _C(_texTiny->GetName());
texDesc._texturePart = newPart;
_texHuge[nextHuge].Init(texDesc);
}
CGI::TextureDesc texDesc;
texDesc._url = _C(_texTiny->GetName());
texDesc._texturePart = newPart;
_texHuge[nextHuge].Init(texDesc);
}
}
}
@ -175,8 +180,8 @@ void Material::Pick::FromString(CSZ sz)
String Material::Pick::ToString()
{
const UINT32 color = Convert::ColorFloatToInt32(glm::value_ptr(static_cast<glm::vec4&>(*this)));
char txt[16];
sprintf_s(txt, "%02X%02X%02X%02X",
char txt[20];
sprintf_s(txt, "0x%02X%02X%02X%02X",
(color >> 0) & 0xFF,
(color >> 8) & 0xFF,
(color >> 16) & 0xFF,
@ -184,61 +189,6 @@ String Material::Pick::ToString()
return txt;
}
// Material::PickRound:
Material::PickRound::PickRound()
{
}
Material::PickRound::PickRound(const glm::vec4& v) : glm::vec4(v)
{
}
void Material::PickRound::SetUV(float u, float v)
{
x = u;
y = v;
}
void Material::PickRound::SetRadius(float r)
{
z = r;
}
void Material::PickRound::SetAlpha(float x)
{
w = x;
}
glm::vec4 Material::PickRound::ToPixels() const
{
if (w >= 2)
{
const float r = sqrt(z);
return glm::vec4(
glm::round(x * w),
glm::round(y * w),
glm::round(r * w),
w);
}
else
return *this;
}
void Material::PickRound::FromPixels(const glm::vec4& pix)
{
if (w >= 2)
{
glm::vec4::operator=(glm::vec4(
pix.x / pix.w,
pix.y / pix.w,
pow(pix.z / pix.w, 2),
w));
}
else
glm::vec4::operator=(pix);
}
// Material:
Material::Material()
@ -264,9 +214,9 @@ void Material::Init(RcDesc desc)
{
VERUS_RT_ASSERT(
Str::EndsWith(_C(_name), ".x3d") ||
Str::EndsWith(_C(_name), ".xmt"));
Str::EndsWith(_C(_name), ".vml"));
String url(desc._name);
Str::ReplaceExtension(url, ".xmt");
Str::ReplaceExtension(url, ".vml");
_name = url;
Vector<BYTE> vData;
@ -288,8 +238,9 @@ bool Material::Done()
Mesh::GetShader()->FreeDescriptorSet(_cshTemp);
Mesh::GetShader()->FreeDescriptorSet(_cshTiny);
Mesh::GetShader()->FreeDescriptorSet(_csh);
_texAlbedo.Done();
_texNormal.Done();
_texX.Done();
_texN.Done();
_texA.Done();
VERUS_DONE(Material);
return true;
}
@ -301,11 +252,14 @@ bool Material::operator<(RcMaterial that) const
if (_blending != that._blending)
return _blending < that._blending;
if (_texAlbedo != that._texAlbedo)
return _texAlbedo < that._texAlbedo;
if (_texA != that._texA)
return _texA < that._texA;
if (_texNormal != that._texNormal)
return _texNormal < that._texNormal;
if (_texN != that._texN)
return _texN < that._texN;
if (_texX != that._texX)
return _texX < that._texX;
return _name < that._name;
}
@ -321,12 +275,14 @@ void Material::Update()
// Request BindDescriptorSetTextures call by clearing _csh:
const bool partChanged =
_texAlbedo && (_albedoPart != _texAlbedo->GetPart()) ||
_texNormal && (_normalPart != _texNormal->GetPart());
_texA && (_aPart != _texA->GetPart()) ||
_texN && (_nPart != _texN->GetPart()) ||
_texX && (_xPart != _texX->GetPart());
if (partChanged && !_cshTemp.IsSet())
{
_albedoPart = _texAlbedo->GetPart();
_normalPart = _texNormal->GetPart();
_aPart = _texA->GetPart();
_nPart = _texN->GetPart();
_xPart = _texX->GetPart();
_cshTemp = _csh;
_csh = CGI::CSHandle();
_cshFreeFrame = renderer.GetFrameCount() + CGI::BaseRenderer::s_ringBufferSize;
@ -339,23 +295,37 @@ void Material::Update()
bool Material::IsLoaded() const
{
if (!_texAlbedo || !_texNormal)
if (!_texA || !_texN || !_texX)
return false;
return
_texAlbedo->GetTex()->IsLoaded() &&
_texNormal->GetTex()->IsLoaded();
_texA->GetTex()->IsLoaded() &&
_texN->GetTex()->IsLoaded() &&
_texX->GetTex()->IsLoaded();
}
void Material::LoadTextures(bool streamParts)
{
VERUS_QREF_SM;
_texAlbedo.Done();
_texNormal.Done();
_texAlbedo.Init(_dict.Find("texAlbedo"), streamParts);
_texNormal.Init(_dict.Find("texNormal"), streamParts);
_texEnableAlbedo.w = 1;
_texEnableNormal.w = 1;
_texX.Done();
_texN.Done();
_texA.Done();
String newUrl;
auto ExpandPath = [this, &newUrl](CSZ url)
{
if (!strncmp(url, "./", 2))
{
newUrl = Str::GetPath(_C(_name));
newUrl += url + 1;
return _C(newUrl);
}
return url;
};
_texA.Init(ExpandPath(_dict.Find("texA")), streamParts);
_texN.Init(ExpandPath(_dict.Find("texN")), streamParts);
_texX.Init(ExpandPath(_dict.Find("texX")), streamParts);
}
String Material::ToString(bool cleanDict)
@ -367,32 +337,30 @@ String Material::ToString(bool cleanDict)
CSZ empty = "";
CGI::PBaseTexture pTexAlbedo = _texAlbedo->GetTex().Get();
CGI::PBaseTexture pTexNormal = _texNormal->GetTex().Get();
CGI::PBaseTexture pTexA = _texA->GetTex().Get();
CGI::PBaseTexture pTexN = _texN->GetTex().Get();
CGI::PBaseTexture pTexX = _texX->GetTex().Get();
_dict.Insert("alphaSwitch", /**/_C(Str::ToString(_alphaSwitch)));
_dict.Insert("anisoSpecDir", /**/_C(Str::ToString(_anisoSpecDir)));
_dict.Insert("detail", /**/_C(Str::ToString(_detail)));
_dict.Insert("emission", /**/_C(Str::ToString(_emission)));
_dict.Insert("emissionPick", /**/_C(_emissionPick.ToString()));
_dict.Insert("eyePick", /**/_C(Str::ToString(_eyePick.ToPixels())));
_dict.Insert("gloss", /**/_C(Str::ToString(_gloss)));
_dict.Insert("glossPick", /**/_C(_glossPick.ToString()));
_dict.Insert("glossScaleBias", /**/_C(Str::ToString(_glossScaleBias)));
_dict.Insert("hairDesat", /**/_C(Str::ToString(_hairDesat)));
_dict.Insert("hairPick", /**/_C(_hairPick.ToString()));
_dict.Insert("lamScaleBias", /**/_C(Str::ToString(_lamScaleBias)));
_dict.Insert("lightPass", /**/_C(Str::ToString(_lightPass)));
_dict.Insert("metalPick", /**/_C(_metalPick.ToString()));
_dict.Insert("skinPick", /**/_C(_skinPick.ToString()));
_dict.Insert("specScaleBias", /**/_C(Str::ToString(_specScaleBias)));
_dict.Insert("tc0ScaleBias", /**/_C(Str::ToString(_tc0ScaleBias)));
_dict.Insert("texAlbedo", /**/pTexAlbedo ? _C(pTexAlbedo->GetName()) : empty);
_dict.Insert("texEnableAlbedo", /**/_C(Str::ToColorString(_texEnableAlbedo)));
_dict.Insert("texNormal", /**/pTexNormal ? _C(pTexNormal->GetName()) : empty);
_dict.Insert("texEnableNormal", /**/_C(Str::ToColorString(_texEnableNormal, false)));
_dict.Insert("userColor", /**/_C(Str::ToColorString(_userColor)));
_dict.Insert("userPick", /**/_C(_userPick.ToString()));
_dict.Insert("anisoSpecDir", /**/_C(Str::ToString(_anisoSpecDir, true)));
_dict.Insert("detail", /**/_C(Str::ToString(_detail)));
_dict.Insert("emission", /**/_C(Str::ToString(_emission)));
_dict.Insert("nmContrast", /**/_C(Str::ToString(_nmContrast)));
_dict.Insert("roughDiffuse", /**/_C(Str::ToString(_roughDiffuse)));
_dict.Insert("solidA", /**/_C(Str::ToColorString(_solidA, true, true)));
_dict.Insert("solidN", /**/_C(Str::ToColorString(_solidN, false, true)));
_dict.Insert("solidX", /**/_C(Str::ToColorString(_solidX, false, true)));
_dict.Insert("sssHue", /**/_C(Str::ToString(_sssHue)));
_dict.Insert("sssPick", /**/_C(_sssPick.ToString()));
_dict.Insert("tc0ScaleBias", /**/_C(Str::ToString(_tc0ScaleBias, true)));
_dict.Insert("texA", /**/pTexA ? _C(pTexA->GetName()) : empty);
_dict.Insert("texN", /**/pTexN ? _C(pTexN->GetName()) : empty);
_dict.Insert("texX", /**/pTexX ? _C(pTexX->GetName()) : empty);
_dict.Insert("userColor", /**/_C(Str::ToColorString(_userColor)));
_dict.Insert("userPick", /**/_C(_userPick.ToString()));
_dict.Insert("xAnisoSpecScaleBias", /**/_C(Str::ToString(_xAnisoSpecScaleBias, true)));
_dict.Insert("xMetallicScaleBias", /**/_C(Str::ToString(_xMetallicScaleBias, true)));
_dict.Insert("xRoughnessScaleBias", /**/_C(Str::ToString(_xRoughnessScaleBias, true)));
_dict.Insert("xWrapDiffuseScaleBias", /**/_C(Str::ToString(_xWrapDiffuseScaleBias, true)));
return _dict.ToString();
}
@ -401,29 +369,23 @@ void Material::FromString(CSZ txt)
{
_dict.FromString(txt);
_alphaSwitch = Str::FromStringVec2(_dict.Find("alphaSwitch", "1 1"));
_anisoSpecDir = Str::FromStringVec2(_dict.Find("anisoSpecDir", "0 1"));
_detail = _dict.FindFloat("detail", 0);
_emission = _dict.FindFloat("emission", 0);
_emissionPick.FromString(_dict.Find("emissionPick", "00000000"));
_eyePick = Str::FromStringVec4(_dict.Find("eyePick", "0 0 0 0"));
_gloss = _dict.FindFloat("gloss", 10);
_glossPick.FromString(_dict.Find("glossPick", "00000000"));
_glossScaleBias = Str::FromStringVec2(_dict.Find("glossScaleBias", "1 0"));
_hairDesat = _dict.FindFloat("hairDesat", 0);
_hairPick.FromString(_dict.Find("hairPick", "00000000"));
_lamScaleBias = Str::FromStringVec2(_dict.Find("lamScaleBias", "1 0"));
_lightPass = _dict.FindFloat("lightPass", 1);
_metalPick.FromString(_dict.Find("metalPick", "00000000"));
_skinPick.FromString(_dict.Find("skinPick", "00000000"));
_specScaleBias = Str::FromStringVec2(_dict.Find("specScaleBias", "1 0"));
_nmContrast = _dict.FindFloat("nmContrast", -2);
_roughDiffuse = _dict.FindFloat("roughDiffuse", 0);
_solidA = Str::FromColorString(_dict.Find("solidA", "80808000"));
_solidN = Str::FromColorString(_dict.Find("solidN", "8080FF00"), false);
_solidX = Str::FromColorString(_dict.Find("solidX", "FF808000"), false);
_sssHue = _dict.FindFloat("sssHue", 0);
_sssPick.FromString(_dict.Find("sssPick", "00000000"));
_tc0ScaleBias = Str::FromStringVec4(_dict.Find("tc0ScaleBias", "1 1 0 0"));
_texEnableAlbedo = Str::FromColorString(_dict.Find("texEnableAlbedo", "80808000"));
_texEnableNormal = Str::FromColorString(_dict.Find("texEnableNormal", "8080FF00"), false);
_userColor = Str::FromColorString(_dict.Find("userColor", "00000000"));
_userPick.FromString(_dict.Find("userPick", "0 0 0 0"));
_eyePick.FromPixels(_eyePick);
_userPick.FromString(_dict.Find("userPick", "00000000"));
_xAnisoSpecScaleBias = Str::FromStringVec2(_dict.Find("xAnisoSpecScaleBias", "1 0"));
_xMetallicScaleBias = Str::FromStringVec2(_dict.Find("xMetallicScaleBias", "1 0"));
_xRoughnessScaleBias = Str::FromStringVec2(_dict.Find("xRoughnessScaleBias", "1 0"));
_xWrapDiffuseScaleBias = Str::FromStringVec2(_dict.Find("xWrapDiffuseScaleBias", "1 0"));
}
CGI::CSHandle Material::GetComplexSetHandle() const
@ -445,44 +407,65 @@ void Material::BindDescriptorSetTextures()
VERUS_QREF_MM;
VERUS_QREF_ATMO;
if (!_cshTiny.IsSet())
_cshTiny = Mesh::GetShader()->BindDescriptorSetTextures(1, { _texAlbedo->GetTinyTex(), _texNormal->GetTinyTex(), mm.GetDetailTexture(), mm.GetStrassTexture() });
{
_cshTiny = Mesh::GetShader()->BindDescriptorSetTextures(1,
{
_texA->GetTinyTex(),
_texN->GetTinyTex(),
_texX->GetTinyTex(),
mm.GetDetailTexture(),
mm.GetDetailNTexture(),
mm.GetStrassTexture()
});
}
if (!_cshSimple.IsSet())
_cshSimple = Mesh::GetSimpleShader()->BindDescriptorSetTextures(1, { _texAlbedo->GetTinyTex(), atmo.GetShadowMapBaker().GetTexture() });
_csh = Mesh::GetShader()->BindDescriptorSetTextures(1, { _texAlbedo->GetTex(), _texNormal->GetTex(), mm.GetDetailTexture(), mm.GetStrassTexture() });
{
_cshSimple = Mesh::GetSimpleShader()->BindDescriptorSetTextures(1,
{
_texA->GetTinyTex(),
_texX->GetTinyTex(),
atmo.GetShadowMapBaker().GetTexture()
});
}
_csh = Mesh::GetShader()->BindDescriptorSetTextures(1,
{
_texA->GetTex(),
_texN->GetTex(),
_texX->GetTex(),
mm.GetDetailTexture(),
mm.GetDetailNTexture(),
mm.GetStrassTexture()
});
}
bool Material::UpdateMeshUniformBuffer(float motionBlur)
bool Material::UpdateMeshUniformBuffer(float motionBlur, bool resolveDitheringMaskEnabled)
{
Mesh::UB_PerMaterialFS& ub = Mesh::GetUbPerMaterialFS();
Mesh::UB_PerMaterialFS ubPrev;
memcpy(&ubPrev, &ub, sizeof(Mesh::UB_PerMaterialFS));
ub._alphaSwitch_anisoSpecDir = float4(_alphaSwitch, _anisoSpecDir);
ub._detail_emission_gloss_hairDesat.x = _detail;
ub._detail_emission_gloss_hairDesat.y = _emission;
ub._detail_emission_gloss_hairDesat.z = _gloss;
ub._detail_emission_gloss_hairDesat.w = _hairDesat;
ub._anisoSpecDir_detail_emission = float4(_anisoSpecDir, _detail, _emission);
ub._motionBlur_nmContrast_roughDiffuse_sssHue.x = motionBlur;
ub._motionBlur_nmContrast_roughDiffuse_sssHue.y = _nmContrast;
ub._motionBlur_nmContrast_roughDiffuse_sssHue.z = _roughDiffuse + (resolveDitheringMaskEnabled ? 0.f : 1.f);
ub._motionBlur_nmContrast_roughDiffuse_sssHue.w = _sssHue;
ub._detailScale_strassScale = float4(1, 1, 1, 1);
ub._emissionPick = _emissionPick;
ub._eyePick = _eyePick;
ub._glossPick = _glossPick;
ub._glossScaleBias_specScaleBias = float4(_glossScaleBias, _specScaleBias);
ub._hairPick = _hairPick;
ub._lamScaleBias_lightPass_motionBlur = float4(_lamScaleBias, _lightPass, motionBlur);
ub._metalPick = _metalPick;
ub._skinPick = _skinPick;
ub._solidA = _solidA;
ub._solidN = _solidN;
ub._solidX = _solidX;
ub._sssPick = _sssPick;
ub._tc0ScaleBias = _tc0ScaleBias;
ub._texEnableAlbedo = _texEnableAlbedo;
ub._texEnableNormal = _texEnableNormal;
ub._userColor = _userColor;
ub._userPick = _userPick;
if (_texAlbedo)
ub._xAnisoSpecScaleBias_xMetallicScaleBias = float4(_xAnisoSpecScaleBias, _xMetallicScaleBias);
ub._xRoughnessScaleBias_xWrapDiffuseScaleBias = float4(_xRoughnessScaleBias, _xWrapDiffuseScaleBias);
if (_texA)
{
ub._detailScale_strassScale = float4(
_texAlbedo->GetTex()->GetSize().getX() / 256 * 4,
_texAlbedo->GetTex()->GetSize().getY() / 256 * 4,
_texAlbedo->GetTex()->GetSize().getX() / 256 * 8,
_texAlbedo->GetTex()->GetSize().getY() / 256 * 8);
_texA->GetTex()->GetSize().getX() / 256 * 4,
_texA->GetTex()->GetSize().getY() / 256 * 4,
_texA->GetTex()->GetSize().getX() / 256 * 8,
_texA->GetTex()->GetSize().getY() / 256 * 8);
}
return 0 != memcmp(&ubPrev, &ub, sizeof(Mesh::UB_PerMaterialFS));
@ -492,43 +475,40 @@ bool Material::UpdateMeshUniformBufferSimple()
{
Mesh::UB_SimplePerMaterialFS& ub = Mesh::GetUbSimplePerMaterialFS();
Mesh::UB_SimplePerMaterialFS ubPrev;
memcpy(&ubPrev, &ub, sizeof(Mesh::UB_PerMaterialFS));
memcpy(&ubPrev, &ub, sizeof(Mesh::UB_SimplePerMaterialFS));
ub._alphaSwitch_anisoSpecDir = float4(_alphaSwitch, _anisoSpecDir);
ub._detail_emission_gloss_hairDesat.x = _detail;
ub._detail_emission_gloss_hairDesat.y = _emission;
ub._detail_emission_gloss_hairDesat.z = _gloss;
ub._detail_emission_gloss_hairDesat.w = _hairDesat;
ub._anisoSpecDir_detail_emission = float4(_anisoSpecDir, _detail, _emission);
ub._motionBlur_nmContrast_roughDiffuse_sssHue.x = 0;
ub._motionBlur_nmContrast_roughDiffuse_sssHue.y = _nmContrast;
ub._motionBlur_nmContrast_roughDiffuse_sssHue.z = _roughDiffuse;
ub._motionBlur_nmContrast_roughDiffuse_sssHue.w = _sssHue;
ub._detailScale_strassScale = float4(1, 1, 1, 1);
ub._emissionPick = _emissionPick;
ub._eyePick = _eyePick;
ub._glossPick = _glossPick;
ub._glossScaleBias_specScaleBias = float4(_glossScaleBias, _specScaleBias);
ub._hairPick = _hairPick;
ub._lamScaleBias_lightPass_motionBlur = float4(_lamScaleBias, _lightPass, 0);
ub._metalPick = _metalPick;
ub._skinPick = _skinPick;
ub._solidA = _solidA;
ub._solidN = _solidN;
ub._solidX = _solidX;
ub._sssPick = _sssPick;
ub._tc0ScaleBias = _tc0ScaleBias;
ub._texEnableAlbedo = _texEnableAlbedo;
ub._texEnableNormal = _texEnableNormal;
ub._userColor = _userColor;
ub._userPick = _userPick;
if (_texAlbedo)
ub._xAnisoSpecScaleBias_xMetallicScaleBias = float4(_xAnisoSpecScaleBias, _xMetallicScaleBias);
ub._xRoughnessScaleBias_xWrapDiffuseScaleBias = float4(_xRoughnessScaleBias, _xWrapDiffuseScaleBias);
if (_texA)
{
ub._detailScale_strassScale = float4(
_texAlbedo->GetTex()->GetSize().getX() / 256 * 4,
_texAlbedo->GetTex()->GetSize().getY() / 256 * 4,
_texAlbedo->GetTex()->GetSize().getX() / 256 * 8,
_texAlbedo->GetTex()->GetSize().getY() / 256 * 8);
_texA->GetTex()->GetSize().getX() / 256 * 4,
_texA->GetTex()->GetSize().getY() / 256 * 4,
_texA->GetTex()->GetSize().getX() / 256 * 8,
_texA->GetTex()->GetSize().getY() / 256 * 8);
}
return 0 != memcmp(&ubPrev, &ub, sizeof(Mesh::UB_PerMaterialFS));
return 0 != memcmp(&ubPrev, &ub, sizeof(Mesh::UB_SimplePerMaterialFS));
}
void Material::IncludePart(float part)
{
_texAlbedo->IncludePart(part);
_texNormal->IncludePart(part);
_texA->IncludePart(part);
_texN->IncludePart(part);
_texX->IncludePart(part);
}
// MaterialPtr:
@ -568,27 +548,52 @@ void MaterialManager::Init()
void MaterialManager::InitCmd()
{
_texDefaultAlbedo.Init("[Textures]:Default.dds", false, true);
_texDefaultNormal.Init("[Textures]:Default.NM.dds", false, true);
_texDetail.Init("[Textures]:Detail.FX.dds", false, true);
_texStrass.Init("[Textures]:Strass.dds", false, true);
_texDefaultA.Init("[Textures]:Default.dds", false, true);
_texDefaultN.Init("[Textures]:Default.N.dds", false, true);
_texDefaultX.Init("[Textures]:Default.X.dds", false, true);
_texDetail.Init("[Textures]:Detail.X.dds", false, true);
_texDetailN.Init("[Textures]:Detail.N.dds", false, true);
_texStrass.Init("[Textures]:Strass.X.dds", false, true);
CGI::TextureDesc texDesc;
texDesc._clearValue = Vector4(1);
texDesc._name = "MaterialManager.DummyShadow";
texDesc._format = CGI::Format::unormD24uintS8;
texDesc._width = 16;
texDesc._height = 16;
texDesc._flags = CGI::TextureDesc::Flags::depthSampledR;
_texDummyShadow.Init(texDesc);
_cshDefault = Mesh::GetShader()->BindDescriptorSetTextures(1,
{
_texDefaultAlbedo->GetTex(),
_texDefaultNormal->GetTex(),
_texDefaultA->GetTex(),
_texDefaultN->GetTex(),
_texDefaultX->GetTex(),
_texDetail->GetTex(),
_texDetailN->GetTex(),
_texStrass->GetTex()
});
_cshDefaultSimple = Mesh::GetSimpleShader()->BindDescriptorSetTextures(1,
{
_texDefaultA->GetTinyTex(),
_texDefaultX->GetTinyTex(),
_texDummyShadow
});
}
void MaterialManager::Done()
{
Mesh::GetShader()->FreeDescriptorSet(_cshDefault);
if (Mesh::GetSimpleShader())
Mesh::GetSimpleShader()->FreeDescriptorSet(_cshDefaultSimple);
if (Mesh::GetShader())
Mesh::GetShader()->FreeDescriptorSet(_cshDefault);
_texDummyShadow.Done();
_texStrass.Done();
_texDetailN.Done();
_texDetail.Done();
_texDefaultNormal.Done();
_texDefaultAlbedo.Done();
_texDefaultX.Done();
_texDefaultN.Done();
_texDefaultA.Done();
DeleteAll();
VERUS_DONE(MaterialManager);
}

View File

@ -21,11 +21,13 @@ namespace verus
Texture();
~Texture();
void Init(CSZ url, bool streamParts = false, bool sync = false, CGI::PcSamplerDesc pSamplerDes = nullptr);
void Init(CSZ url, bool streamParts = false, bool sync = false, CGI::PcSamplerDesc pSamplerDesc = nullptr);
bool Done();
void AddRef() { _refCount++; }
void Update();
void UpdateStreaming();
CGI::TexturePtr GetTex() const;
CGI::TexturePtr GetTinyTex() const;
@ -40,7 +42,7 @@ namespace verus
class TexturePtr : public Ptr<Texture>
{
public:
void Init(CSZ url, bool streamParts = false, bool sync = false, CGI::PcSamplerDesc pSamplerDes = nullptr);
void Init(CSZ url, bool streamParts = false, bool sync = false, CGI::PcSamplerDesc pSamplerDesc = nullptr);
};
VERUS_TYPEDEFS(TexturePtr);
@ -84,53 +86,37 @@ namespace verus
String ToString();
};
class PickRound : public glm::vec4
{
public:
PickRound();
PickRound(const glm::vec4& v);
void SetUV(float u, float v);
void SetRadius(float r);
void SetAlpha(float x);
glm::vec4 ToPixels() const;
void FromPixels(const glm::vec4& pix);
};
INT64 _cshFreeFrame = -1;
String _name;
IO::Dictionary _dict;
glm::vec2 _alphaSwitch = glm::vec2(1, 1);
glm::vec2 _anisoSpecDir = glm::vec2(0, 1);
float _detail = 0;
float _emission = 0;
Pick _emissionPick;
PickRound _eyePick;
float _gloss = 10;
Pick _glossPick;
glm::vec2 _glossScaleBias = glm::vec2(1, 0);
float _hairDesat = 0;
Pick _hairPick;
glm::vec2 _lamScaleBias = glm::vec2(1, 0);
float _lightPass = 1;
Pick _metalPick;
Pick _skinPick;
glm::vec2 _specScaleBias = glm::vec2(1, 0);
float _nmContrast = -2;
float _roughDiffuse = 0;
glm::vec4 _solidA = glm::vec4(1, 1, 1, 0);
glm::vec4 _solidN = glm::vec4(0.5f, 0.5f, 1, 0);
glm::vec4 _solidX = glm::vec4(1, 0.5f, 0.5f, 0);
float _sssHue = 0.5f;
Pick _sssPick;
glm::vec4 _tc0ScaleBias = glm::vec4(1, 1, 0, 0);
TexturePwn _texAlbedo;
glm::vec4 _texEnableAlbedo = glm::vec4(0.5f, 0.5f, 0.5f, 1);
TexturePwn _texNormal;
glm::vec4 _texEnableNormal = glm::vec4(0.5f, 0.5f, 1.0f, 1);
TexturePwn _texPacked;
glm::vec4 _texEnablePacked = glm::vec4(0.5f, 0.5f, 1.0f, 1);
glm::vec4 _userColor = glm::vec4(0, 0, 0, 0);
TexturePwn _texA;
TexturePwn _texN;
TexturePwn _texX;
glm::vec4 _userColor = glm::vec4(1, 1, 1, 1);
Pick _userPick;
glm::vec2 _xAnisoSpecScaleBias = glm::vec2(1, 0);
glm::vec2 _xMetallicScaleBias = glm::vec2(1, 0);
glm::vec2 _xRoughnessScaleBias = glm::vec2(1, 0);
glm::vec2 _xWrapDiffuseScaleBias = glm::vec2(1, 0);
Blending _blending = Blending::opaque;
CGI::CSHandle _csh;
CGI::CSHandle _cshTiny;
CGI::CSHandle _cshTemp;
CGI::CSHandle _cshSimple;
int _albedoPart = -1;
int _normalPart = -1;
int _aPart = -1;
int _nPart = -1;
int _xPart = -1;
int _refCount = 0;
Material();
@ -157,7 +143,7 @@ namespace verus
CGI::CSHandle GetComplexSetHandle() const;
CGI::CSHandle GetComplexSetHandleSimple() const;
void BindDescriptorSetTextures();
bool UpdateMeshUniformBuffer(float motionBlur = 1);
bool UpdateMeshUniformBuffer(float motionBlur = 1, bool resolveDitheringMaskEnabled = true);
bool UpdateMeshUniformBufferSimple();
void IncludePart(float part);
@ -183,12 +169,15 @@ namespace verus
typedef StoreUnique<String, Material> TStoreMaterials;
class MaterialManager : public Singleton<MaterialManager>, public Object, private TStoreTextures, private TStoreMaterials
{
TexturePwn _texDefaultAlbedo;
TexturePwn _texDefaultNormal;
TexturePwn _texDefaultPacked;
TexturePwn _texDetail;
TexturePwn _texStrass;
CGI::CSHandle _cshDefault; // For missing, non-mandatory materials.
TexturePwn _texDefaultA;
TexturePwn _texDefaultN;
TexturePwn _texDefaultX;
TexturePwn _texDetail;
TexturePwn _texDetailN;
TexturePwn _texStrass;
CGI::TexturePwn _texDummyShadow;
CGI::CSHandle _cshDefault; // For missing, non-mandatory materials.
CGI::CSHandle _cshDefaultSimple;
public:
MaterialManager();
@ -201,11 +190,12 @@ namespace verus
void Update();
CGI::TexturePtr GetDefaultTexture() { return _texDefaultAlbedo->GetTex(); }
CGI::TexturePtr GetDefaultTexture() { return _texDefaultA->GetTex(); }
CGI::TexturePtr GetDetailTexture() { return _texDetail->GetTex(); }
CGI::TexturePtr GetDetailNTexture() { return _texDetailN->GetTex(); }
CGI::TexturePtr GetStrassTexture() { return _texStrass->GetTex(); }
CGI::CSHandle GetDefaultComplexSetHandle() const { return _cshDefault; }
CGI::CSHandle GetDefaultComplexSetHandle(bool simple = false) const { return simple ? _cshDefaultSimple : _cshDefault; }
// Textures:
PTexture InsertTexture(CSZ url);

View File

@ -37,10 +37,12 @@ void Mesh::InitStatic()
s_shader[SHADER_MAIN]->CreateDescriptorSet(0, &s_ubPerFrame, sizeof(s_ubPerFrame), settings.GetLimits()._mesh_ubPerFrameCapacity, {}, CGI::ShaderStageFlags::vs_hs_ds_fs);
s_shader[SHADER_MAIN]->CreateDescriptorSet(1, &s_ubPerMaterialFS, sizeof(s_ubPerMaterialFS), settings.GetLimits()._mesh_ubPerMaterialFSCapacity,
{
CGI::Sampler::aniso,
CGI::Sampler::aniso,
CGI::Sampler::aniso,
CGI::Sampler::lodBias
CGI::Sampler::aniso, // A
CGI::Sampler::aniso, // N
CGI::Sampler::aniso, // X
CGI::Sampler::aniso, // Detail
CGI::Sampler::aniso, // DetailN
CGI::Sampler::lodBias // Strass
}, CGI::ShaderStageFlags::fs);
s_shader[SHADER_MAIN]->CreateDescriptorSet(2, &s_ubPerMeshVS, sizeof(s_ubPerMeshVS), settings.GetLimits()._mesh_ubPerMeshVSCapacity, {}, CGI::ShaderStageFlags::vs);
s_shader[SHADER_MAIN]->CreateDescriptorSet(3, &s_ubSkeletonVS, sizeof(s_ubSkeletonVS), settings.GetLimits()._mesh_ubSkinningVSCapacity, {}, CGI::ShaderStageFlags::vs);
@ -51,6 +53,7 @@ void Mesh::InitStatic()
s_shader[SHADER_SIMPLE]->CreateDescriptorSet(0, &s_ubSimplePerFrame, sizeof(s_ubSimplePerFrame), settings.GetLimits()._mesh_ubPerFrameCapacity);
s_shader[SHADER_SIMPLE]->CreateDescriptorSet(1, &s_ubSimplePerMaterialFS, sizeof(s_ubSimplePerMaterialFS), settings.GetLimits()._mesh_ubPerMaterialFSCapacity,
{
CGI::Sampler::linearMipN,
CGI::Sampler::linearMipN,
CGI::Sampler::shadow
}, CGI::ShaderStageFlags::fs);
@ -118,7 +121,7 @@ void Mesh::Draw(RcDrawDesc drawDesc, CGI::CommandBufferPtr cb)
cb->BindDescriptors(shader, 2);
// Set 3:
if (drawDesc._bindSkeleton)
if (drawDesc._bindSkeleton && _skeleton.IsInitialized())
{
UpdateUniformBufferSkeletonVS();
cb->BindDescriptors(shader, 3);
@ -161,7 +164,7 @@ void Mesh::DrawSimple(RcDrawDesc drawDesc, CGI::CommandBufferPtr cb)
cb->BindDescriptors(shader, 2);
// Set 3:
if (drawDesc._bindSkeleton)
if (drawDesc._bindSkeleton && _skeleton.IsInitialized())
{
UpdateUniformBufferSimpleSkeletonVS();
cb->BindDescriptors(shader, 3);
@ -253,7 +256,7 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
if (pipe >= PIPE_SIMPLE_TEX_ADD)
{
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], branches[pipe], renderer.GetDS().GetRenderPassHandle_ExtraCompose());
CGI::PipelineDesc pipeDesc(_geo, s_shader[SHADER_SIMPLE], branches[pipe], renderer.GetDS().GetRenderPassHandle_ForwardRendering());
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_ADD;
pipeDesc._rasterizationState._cullMode = CGI::CullMode::none;
pipeDesc._vertexInputBindingsFilter = _bindingsMask;
@ -285,6 +288,7 @@ void Mesh::BindPipeline(PIPE pipe, CGI::CommandBufferPtr cb)
pipeDesc._colorAttachBlendEqs[0] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[1] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[2] = VERUS_COLOR_BLEND_OFF;
pipeDesc._colorAttachBlendEqs[3] = VERUS_COLOR_BLEND_OFF;
};
switch (pipe)

View File

@ -40,6 +40,7 @@ void Scatter::Init(int side, int typeCount, PcTypeDesc pTypes, int seed)
{
type++;
maxPermille += pTypes[type]._permille;
instance._type = pTypes[type]._type;
}
else
@ -62,10 +63,10 @@ void Scatter::Init(int side, int typeCount, PcTypeDesc pTypes, int seed)
VERUS_FOR(i, _side)
{
const int offset = i * _side;
const int rowOffset = i * _side;
VERUS_FOR(j, _side)
{
const int index = offset + j;
const int index = rowOffset + j;
RInstance instance = _vInstances[index];
const float mn = instance._x;
const float mx = instance._z;

View File

@ -40,10 +40,10 @@ namespace verus
public:
int _type = 0;
int _permille = 0;
float _minOffset = 0.2f;
float _maxOffset = 0.8f;
float _minScale = 0.5f;
float _maxScale = 1.5f;
float _minOffset = 0.25f;
float _maxOffset = 0.75f;
float _minScale = 0.8f;
float _maxScale = 1.25f;
float _minAngle = 0;
float _maxAngle = VERUS_2PI;
TypeDesc(int type, int permille) : _type(type), _permille(permille) {}

View File

@ -97,6 +97,11 @@ void Model::Deserialize(IO::RStream stream, CSZ url)
char mat[IO::Stream::s_bufferSize] = {};
stream.ReadString(mat);
// TODO: handle old names, remove later:
char* pOldExt = strstr(mat, ".xmt");
if (pOldExt)
strncpy(pOldExt, ".vml", 4);
Desc desc;
desc._url = url;
desc._mat = mat;

View File

@ -68,7 +68,7 @@ void Prefab::LoadPrefab(SZ xml)
{
matFrag = _url;
Str::ReplaceFilename(matFrag, mat);
matFrag += ".xmt";
matFrag += ".vml";
}
Block::Desc desc;

Some files were not shown because too many files have changed in this diff Show More