mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-14 06:34:10 +00:00
Added more missing files
This commit is contained in:
parent
9b4b93e8ef
commit
025ba4419e
34 changed files with 4739 additions and 63 deletions
|
@ -487,6 +487,7 @@ if(USE_NVRHI)
|
|||
|
||||
set(NVRHI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/nvrhi)
|
||||
add_subdirectory(${NVRHI_DIR})
|
||||
add_definitions(-DUSE_NVRHI)
|
||||
|
||||
if(USE_DX11)
|
||||
find_package(FXC REQUIRED)
|
||||
|
@ -557,17 +558,17 @@ file(GLOB RENDERER_VULKAN_SOURCES renderer/Vulkan/*.cpp)
|
|||
file(GLOB RENDERER_NVRHI_INCLUDES renderer/NVRHI/*.h)
|
||||
file(GLOB RENDERER_NVRHI_SOURCES renderer/NVRHI/*.cpp)
|
||||
|
||||
file(GLOB SHADERS ../base/renderprogs/*.hlsl ../base/renderprogs/*.inc )
|
||||
file(GLOB SHADERS_BUILTIN ../base/renderprogs/builtin/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_DEBUG ../base/renderprogs/builtin/debug/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_FOG ../base/renderprogs/builtin/fog/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_LEGACY ../base/renderprogs/builtin/legacy/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_LIGHTING ../base/renderprogs/builtin/lighting/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_POST ../base/renderprogs/builtin/post/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_SSAO ../base/renderprogs/builtin/SSAO/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_SSGI ../base/renderprogs/builtin/SSGI/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_VIDEO ../base/renderprogs/builtin/video/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_VR ../base/renderprogs/builtin/VR/*.hlsl )
|
||||
file(GLOB SHADERS shaders/*.hlsl shaders/*.inc )
|
||||
file(GLOB SHADERS_BUILTIN shaders/builtin/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_DEBUG shaders/builtin/debug/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_FOG shaders/builtin/fog/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_LEGACY .shaders/builtin/legacy/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_LIGHTING shaders/builtin/lighting/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_POST shaders/builtin/post/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_SSAO shaders/builtin/SSAO/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_SSGI shaders/builtin/SSGI/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_VIDEO shaders/builtin/video/*.hlsl )
|
||||
file(GLOB SHADERS_BUILTIN_VR shaders/builtin/VR/*.hlsl )
|
||||
|
||||
file(GLOB IRRXML_INCLUDES libs/irrxml/src/*.h)
|
||||
file(GLOB IRRXML_SOURCES libs/irrxml/src/*.cpp)
|
||||
|
|
|
@ -357,6 +357,12 @@ ID_INLINE float* idVec2::ToFloatPtr()
|
|||
return &x;
|
||||
}
|
||||
|
||||
ID_INLINE idVec2& operator/( float lhs, idVec2& rhs )
|
||||
{
|
||||
rhs.x = lhs / rhs.x;
|
||||
rhs.y = lhs / rhs.y;
|
||||
return rhs;
|
||||
}
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
|
@ -963,6 +969,14 @@ ID_INLINE bool idVec3::ProjectAlongPlane( const idVec3& normal, const float epsi
|
|||
return true;
|
||||
}
|
||||
|
||||
ID_INLINE idVec3& operator/( float lhs, idVec3& rhs )
|
||||
{
|
||||
rhs.x = rhs.x / lhs;
|
||||
rhs.y = rhs.y / lhs;
|
||||
rhs.z = rhs.z / lhs;
|
||||
return rhs;
|
||||
}
|
||||
|
||||
//===============================================================
|
||||
//
|
||||
// idTupleSize< idVec3 > - Specialization to get the size
|
||||
|
@ -1757,6 +1771,14 @@ ID_INLINE idVec3 idPolar3::ToVec3() const
|
|||
return idVec3( cp * radius * ct, cp * radius * st, radius * sp );
|
||||
}
|
||||
|
||||
namespace VectorUtil
|
||||
{
|
||||
inline uint32_t Vec4ToColorInt( const idVec4& vec )
|
||||
{
|
||||
idVec4 vecCopy = 255.0f * vec;
|
||||
return ( ( uint32_t )vecCopy[0] << 28 ) | ( ( uint32_t )vecCopy[1] << 20 ) | ( ( uint32_t )vecCopy[2] << 12 ) | ( uint32_t )vecCopy[3];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
|
|
@ -99,10 +99,13 @@ const int MAX_EXPRESSION_REGISTERS = 4096;
|
|||
#elif defined(USE_VULKAN)
|
||||
#include "../renderer/Vulkan/qvk.h"
|
||||
#else
|
||||
// RB: replaced QGL with GLEW
|
||||
|
||||
#endif
|
||||
|
||||
// FIMXE remove GL with NVRHI
|
||||
// RB: replaced QGL with GLEW
|
||||
#include <GL/glew.h>
|
||||
// RB end
|
||||
#endif
|
||||
|
||||
|
||||
#include "../renderer/Cinematic.h"
|
||||
|
@ -113,6 +116,7 @@ const int MAX_EXPRESSION_REGISTERS = 4096;
|
|||
#include "../renderer/ModelManager.h"
|
||||
#include "../renderer/RenderSystem.h"
|
||||
#include "../renderer/RenderWorld.h"
|
||||
#include "../renderer/BindingCache.h"
|
||||
|
||||
// sound engine
|
||||
#include "../sound/sound.h"
|
||||
|
|
159
neo/renderer/BindingCache.cpp
Normal file
159
neo/renderer/BindingCache.cpp
Normal file
|
@ -0,0 +1,159 @@
|
|||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "BindingCache.h"
|
||||
|
||||
void BindingCache::Init( nvrhi::IDevice* _device )
|
||||
{
|
||||
device = _device;
|
||||
}
|
||||
|
||||
nvrhi::BindingSetHandle BindingCache::GetCachedBindingSet( const nvrhi::BindingSetDesc& desc, nvrhi::IBindingLayout* layout )
|
||||
{
|
||||
size_t hash = 0;
|
||||
nvrhi::hash_combine( hash, desc );
|
||||
nvrhi::hash_combine( hash, layout );
|
||||
|
||||
mutex.Lock();
|
||||
|
||||
nvrhi::BindingSetHandle result = nullptr;
|
||||
for( int i = bindingHash.First( hash ); i != -1; i = bindingHash.Next( i ) )
|
||||
{
|
||||
nvrhi::BindingSetHandle bindingSet = bindingSets[i];
|
||||
if( *bindingSet->getDesc() == desc )
|
||||
{
|
||||
result = bindingSet;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex.Unlock();
|
||||
|
||||
if( result )
|
||||
{
|
||||
assert( result->getDesc() && *result->getDesc() == desc );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nvrhi::BindingSetHandle BindingCache::GetOrCreateBindingSet( const nvrhi::BindingSetDesc& desc, nvrhi::IBindingLayout* layout )
|
||||
{
|
||||
size_t hash = 0;
|
||||
nvrhi::hash_combine( hash, desc );
|
||||
nvrhi::hash_combine( hash, layout );
|
||||
|
||||
mutex.Lock();
|
||||
|
||||
nvrhi::BindingSetHandle result = nullptr;
|
||||
for( int i = bindingHash.First( hash ); i != -1; i = bindingHash.Next( i ) )
|
||||
{
|
||||
nvrhi::BindingSetHandle bindingSet = bindingSets[i];
|
||||
if( *bindingSet->getDesc() == desc )
|
||||
{
|
||||
result = bindingSet;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex.Unlock();
|
||||
|
||||
if( !result )
|
||||
{
|
||||
mutex.Lock();
|
||||
|
||||
int entryIndex = bindingSets.Append( result );
|
||||
bindingHash.Add( hash, entryIndex );
|
||||
|
||||
nvrhi::BindingSetHandle& entry = bindingSets[entryIndex];
|
||||
|
||||
if( !entry )
|
||||
{
|
||||
result = device->createBindingSet( desc, layout );
|
||||
entry = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = entry;
|
||||
}
|
||||
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
if( result )
|
||||
{
|
||||
assert( result->getDesc() && *result->getDesc() == desc );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void BindingCache::Clear()
|
||||
{
|
||||
mutex.Lock();
|
||||
bindingSets.Clear();
|
||||
bindingHash.Clear();
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
void SamplerCache::Init( nvrhi::IDevice* _device )
|
||||
{
|
||||
device = _device;
|
||||
}
|
||||
|
||||
void SamplerCache::Clear()
|
||||
{
|
||||
mutex.Lock();
|
||||
samplers.Clear();
|
||||
samplerHash.Clear();
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
nvrhi::SamplerHandle SamplerCache::GetOrCreateSampler( nvrhi::SamplerDesc desc )
|
||||
{
|
||||
size_t hash = std::hash<nvrhi::SamplerDesc> {}( desc );
|
||||
|
||||
mutex.Lock();
|
||||
|
||||
nvrhi::SamplerHandle result = nullptr;
|
||||
for( int i = samplerHash.First( hash ); i != -1; i = samplerHash.Next( i ) )
|
||||
{
|
||||
nvrhi::SamplerHandle sampler = samplers[i];
|
||||
if( sampler->getDesc() == desc )
|
||||
{
|
||||
result = sampler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex.Unlock();
|
||||
|
||||
if( !result )
|
||||
{
|
||||
mutex.Lock();
|
||||
|
||||
int entryIndex = samplers.Append( result );
|
||||
samplerHash.Add( hash, entryIndex );
|
||||
|
||||
nvrhi::SamplerHandle& entry = samplers[entryIndex];
|
||||
|
||||
if( !entry )
|
||||
{
|
||||
result = device->createSampler( desc );
|
||||
entry = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = entry;
|
||||
}
|
||||
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
if( result )
|
||||
{
|
||||
assert( result->getDesc() == desc );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
70
neo/renderer/BindingCache.h
Normal file
70
neo/renderer/BindingCache.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef RENDERER_BINDING_CACHE_H_
|
||||
#define RENDERER_BINDING_CACHE_H_
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
class BindingCache
|
||||
{
|
||||
public:
|
||||
BindingCache() {}
|
||||
|
||||
void Init( nvrhi::IDevice* _device );
|
||||
void Clear();
|
||||
|
||||
nvrhi::BindingSetHandle GetCachedBindingSet( const nvrhi::BindingSetDesc& desc, nvrhi::IBindingLayout* layout );
|
||||
nvrhi::BindingSetHandle GetOrCreateBindingSet( const nvrhi::BindingSetDesc& desc, nvrhi::IBindingLayout* layout );
|
||||
|
||||
private:
|
||||
nvrhi::IDevice* device;
|
||||
idList<nvrhi::BindingSetHandle> bindingSets;
|
||||
idHashIndex bindingHash;
|
||||
idSysMutex mutex;
|
||||
};
|
||||
|
||||
class SamplerCache
|
||||
{
|
||||
public:
|
||||
|
||||
SamplerCache() {}
|
||||
|
||||
void Init( nvrhi::IDevice* _device );
|
||||
void Clear();
|
||||
|
||||
nvrhi::SamplerHandle GetOrCreateSampler( nvrhi::SamplerDesc samplerDesc );
|
||||
|
||||
private:
|
||||
|
||||
nvrhi::IDevice* device;
|
||||
idList<nvrhi::SamplerHandle> samplers;
|
||||
idHashIndex samplerHash;
|
||||
idSysMutex mutex;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -135,11 +135,11 @@ protected:
|
|||
#else
|
||||
vulkanAllocation_t allocation;
|
||||
#endif
|
||||
|
||||
#elif defined( USE_NVRHI )
|
||||
nvrhi::InputLayoutHandle inputLayout;
|
||||
nvrhi::BufferHandle bufferHandle;
|
||||
void* buffer;
|
||||
#elif defined( USE_NVRHI )
|
||||
|
||||
#else
|
||||
// GL
|
||||
GLintptr bufferHandle;
|
||||
|
|
|
@ -87,10 +87,10 @@ void idGuiModel::ReadFromDemo( idDemoFile* demo )
|
|||
idGuiModel::BeginFrame
|
||||
================
|
||||
*/
|
||||
void idGuiModel::BeginFrame()
|
||||
void idGuiModel::BeginFrame( nvrhi::ICommandList* commandList )
|
||||
{
|
||||
vertexBlock = vertexCache.AllocVertex( NULL, MAX_VERTS );
|
||||
indexBlock = vertexCache.AllocIndex( NULL, MAX_INDEXES );
|
||||
vertexBlock = vertexCache.AllocVertex( NULL, MAX_VERTS, sizeof( idDrawVert ), commandList );
|
||||
indexBlock = vertexCache.AllocIndex( NULL, MAX_INDEXES, sizeof( idTriList ), commandList );
|
||||
vertexPointer = ( idDrawVert* )vertexCache.MappedVertexBuffer( vertexBlock );
|
||||
indexPointer = ( triIndex_t* )vertexCache.MappedIndexBuffer( indexBlock );
|
||||
numVerts = 0;
|
||||
|
@ -180,6 +180,7 @@ void idGuiModel::EmitSurfaces( float modelMatrix[16], float modelViewMatrix[16],
|
|||
drawSurf->shaderRegisters = regs;
|
||||
shader->EvaluateRegisters( regs, shaderParms, tr.viewDef->renderView.shaderParms, tr.viewDef->renderView.time[1] * 0.001f, NULL );
|
||||
}
|
||||
|
||||
R_LinkDrawSurfToView( drawSurf, tr.viewDef );
|
||||
if( allowFullScreenStereoDepth )
|
||||
{
|
||||
|
@ -233,7 +234,7 @@ idGuiModel::EmitFullScreen
|
|||
Creates a view that covers the screen and emit the surfaces
|
||||
================
|
||||
*/
|
||||
void idGuiModel::EmitFullScreen()
|
||||
void idGuiModel::EmitFullScreen( textureStage_t* textureStage )
|
||||
{
|
||||
if( surfaces[0].numIndexes == 0 )
|
||||
{
|
||||
|
@ -244,7 +245,19 @@ void idGuiModel::EmitFullScreen()
|
|||
|
||||
viewDef_t* viewDef = ( viewDef_t* )R_ClearedFrameAlloc( sizeof( *viewDef ), FRAME_ALLOC_VIEW_DEF );
|
||||
viewDef->is2Dgui = true;
|
||||
tr.GetCroppedViewport( &viewDef->viewport );
|
||||
|
||||
if( textureStage )
|
||||
{
|
||||
viewDef->targetRender = globalFramebuffers.glowFBO[0];
|
||||
viewDef->viewport.x1 = 0;
|
||||
viewDef->viewport.y1 = 0;
|
||||
viewDef->viewport.x2 = textureStage->width;
|
||||
viewDef->viewport.y2 = textureStage->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.GetCroppedViewport( &viewDef->viewport );
|
||||
}
|
||||
|
||||
bool stereoEnabled = ( renderSystem->GetStereo3DMode() != STEREO3D_OFF );
|
||||
if( stereoEnabled )
|
||||
|
@ -262,38 +275,55 @@ void idGuiModel::EmitFullScreen()
|
|||
}
|
||||
}
|
||||
|
||||
idVec2 screenSize( renderSystem->GetVirtualWidth(), renderSystem->GetVirtualHeight() );
|
||||
|
||||
if( textureStage )
|
||||
{
|
||||
screenSize.x = textureStage->width;
|
||||
screenSize.y = textureStage->height;
|
||||
}
|
||||
|
||||
float xScale = 1.0f / screenSize.x;
|
||||
#if defined( USE_VULKAN ) || defined( USE_NVRHI )
|
||||
float yScale = -1.0f / screenSize.y; // flip y
|
||||
#else
|
||||
float yScale = 1.0f / screenSize.y;
|
||||
#endif
|
||||
float zScale = -1.0f;
|
||||
|
||||
viewDef->scissor.x1 = 0;
|
||||
viewDef->scissor.y1 = 0;
|
||||
viewDef->scissor.x2 = viewDef->viewport.x2 - viewDef->viewport.x1;
|
||||
viewDef->scissor.y2 = viewDef->viewport.y2 - viewDef->viewport.y1;
|
||||
|
||||
// RB: IMPORTANT - the projectionMatrix has a few changes to make it work with Vulkan
|
||||
viewDef->projectionMatrix[0 * 4 + 0] = 2.0f / renderSystem->GetVirtualWidth();
|
||||
viewDef->projectionMatrix[0 * 4 + 0] = 2.f * xScale;
|
||||
viewDef->projectionMatrix[0 * 4 + 1] = 0.0f;
|
||||
viewDef->projectionMatrix[0 * 4 + 2] = 0.0f;
|
||||
viewDef->projectionMatrix[0 * 4 + 3] = 0.0f;
|
||||
|
||||
viewDef->projectionMatrix[1 * 4 + 0] = 0.0f;
|
||||
#if defined(USE_VULKAN)
|
||||
viewDef->projectionMatrix[1 * 4 + 1] = 2.0f / renderSystem->GetVirtualHeight();
|
||||
#else
|
||||
viewDef->projectionMatrix[1 * 4 + 1] = -2.0f / renderSystem->GetVirtualHeight();
|
||||
#endif
|
||||
viewDef->projectionMatrix[1 * 4 + 1] = 2.f * yScale;
|
||||
viewDef->projectionMatrix[1 * 4 + 2] = 0.0f;
|
||||
viewDef->projectionMatrix[1 * 4 + 3] = 0.0f;
|
||||
|
||||
viewDef->projectionMatrix[2 * 4 + 0] = 0.0f;
|
||||
viewDef->projectionMatrix[2 * 4 + 1] = 0.0f;
|
||||
viewDef->projectionMatrix[2 * 4 + 2] = -1.0f;
|
||||
viewDef->projectionMatrix[2 * 4 + 2] = zScale;
|
||||
viewDef->projectionMatrix[2 * 4 + 3] = 0.0f;
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
viewDef->projectionMatrix[3 * 4 + 0] = -( screenSize.x * xScale );
|
||||
viewDef->projectionMatrix[3 * 4 + 1] = -( screenSize.y * yScale );
|
||||
#else
|
||||
viewDef->projectionMatrix[3 * 4 + 0] = -1.0f; // RB: was -2.0f
|
||||
#if defined(USE_VULKAN)
|
||||
viewDef->projectionMatrix[3 * 4 + 1] = -1.0f;
|
||||
#else
|
||||
viewDef->projectionMatrix[3 * 4 + 1] = 1.0f;
|
||||
#endif
|
||||
viewDef->projectionMatrix[3 * 4 + 2] = 0.0f; // RB: was 1.0f
|
||||
#endif
|
||||
viewDef->projectionMatrix[3 * 4 + 2] = 0.0f;
|
||||
viewDef->projectionMatrix[3 * 4 + 3] = 1.0f;
|
||||
|
||||
// make a tech5 renderMatrix for faster culling
|
||||
|
@ -322,6 +352,8 @@ void idGuiModel::EmitFullScreen()
|
|||
#endif
|
||||
|
||||
viewDef_t* oldViewDef = tr.viewDef;
|
||||
viewDef->superView = oldViewDef;
|
||||
|
||||
tr.viewDef = viewDef;
|
||||
|
||||
EmitSurfaces( viewDef->worldSpace.modelMatrix, viewDef->worldSpace.modelViewMatrix,
|
||||
|
@ -330,6 +362,17 @@ void idGuiModel::EmitFullScreen()
|
|||
tr.viewDef = oldViewDef;
|
||||
|
||||
// add the command to draw this view
|
||||
if( textureStage )
|
||||
{
|
||||
textureStage->dynamicFrameCount = tr.frameCount;
|
||||
|
||||
viewDef->targetRender = globalFramebuffers.glowFBO[0];
|
||||
//if (textureStage->image == NULL)
|
||||
//{
|
||||
// textureStage->image = globalImages->glowImage[0];
|
||||
//}
|
||||
}
|
||||
|
||||
R_AddDrawViewCmd( viewDef, true );
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ namespace ImGui
|
|||
struct ImDrawData;
|
||||
}
|
||||
|
||||
struct ImDrawData;
|
||||
|
||||
class idGuiModel
|
||||
{
|
||||
public:
|
||||
|
@ -54,10 +56,11 @@ public:
|
|||
void ReadFromDemo( idDemoFile* demo );
|
||||
|
||||
// allocates memory for verts and indexes in frame-temporary buffer memory
|
||||
void BeginFrame();
|
||||
void BeginFrame( nvrhi::ICommandList* commandList );
|
||||
|
||||
void EmitToCurrentView( float modelMatrix[16], bool depthHack );
|
||||
void EmitFullScreen();
|
||||
void EmitFullScreen( textureStage_t* textureStage = nullptr );
|
||||
void EmitSurfaces( float modelMatrix[16], float modelViewMatrix[16], bool depthHack, bool allowFullScreenStereoDepth, bool linkAsEntity );
|
||||
|
||||
// RB
|
||||
void EmitImGui( ImDrawData* drawData );
|
||||
|
@ -70,7 +73,6 @@ public:
|
|||
//---------------------------
|
||||
private:
|
||||
void AdvanceSurf();
|
||||
void EmitSurfaces( float modelMatrix[16], float modelViewMatrix[16], bool depthHack, bool allowFullScreenStereoDepth, bool linkAsEntity );
|
||||
|
||||
guiModelSurface_t* surf;
|
||||
|
||||
|
|
|
@ -465,18 +465,7 @@ public:
|
|||
// DG: added for imgui integration (to be used with ImGui::Image() etc)
|
||||
void* GetImGuiTextureID()
|
||||
{
|
||||
if( !IsLoaded() )
|
||||
{
|
||||
// load the image on demand here, which isn't our normal game operating mode
|
||||
ActuallyLoadImage( true );
|
||||
}
|
||||
|
||||
#if defined( USE_VULKAN )
|
||||
return ( void* )( intptr_t )image;
|
||||
#else
|
||||
return ( void* )( intptr_t )texnum;
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
// DG end
|
||||
|
||||
|
|
|
@ -72,7 +72,15 @@ void R_ReloadImages_f( const idCmdArgs& args )
|
|||
}
|
||||
}
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
nvrhi::CommandListHandle commandList = deviceManager->GetDevice()->createCommandList();
|
||||
commandList->open();
|
||||
globalImages->ReloadImages( all, commandList );
|
||||
commandList->close();
|
||||
deviceManager->GetDevice()->executeCommandList( commandList );
|
||||
#else
|
||||
globalImages->ReloadImages( all );
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct
|
||||
|
@ -469,7 +477,11 @@ idImage* idImageManager::ImageFromFile( const char* _name, textureFilter_t filte
|
|||
image->levelLoadReferenced = true;
|
||||
|
||||
// load it if we aren't in a level preload
|
||||
#if defined( USE_NVRHI )
|
||||
if( !insideLevelLoad || preloadingMapImages )
|
||||
#else
|
||||
if( ( !insideLevelLoad || preloadingMapImages ) && idLib::IsMainThread() )
|
||||
#endif
|
||||
{
|
||||
image->referencedOutsideLevelLoad = ( !insideLevelLoad && !preloadingMapImages );
|
||||
image->FinalizeImage( false, nullptr );
|
||||
|
|
|
@ -990,12 +990,35 @@ void idImage::GenerateImage( const byte* pic, int width, int height, textureFilt
|
|||
|
||||
AllocImage();
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
if( commandList )
|
||||
{
|
||||
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
|
||||
const int bytesPerBlock = info.bytesPerBlock;
|
||||
|
||||
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
|
||||
|
||||
for( int i = 0; i < im.NumImages(); i++ )
|
||||
{
|
||||
const bimageImage_t& img = im.GetImageHeader( i );
|
||||
const byte* data = im.GetImageData( i );
|
||||
int rowPitch = GetRowPitch( opts.format, img.width );
|
||||
commandList->writeTexture( texture, img.destZ, img.level, data, rowPitch );
|
||||
}
|
||||
|
||||
commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource );
|
||||
commandList->commitBarriers();
|
||||
}
|
||||
#else
|
||||
for( int i = 0; i < im.NumImages(); i++ )
|
||||
{
|
||||
const bimageImage_t& img = im.GetImageHeader( i );
|
||||
const byte* data = im.GetImageData( i );
|
||||
SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data );
|
||||
}
|
||||
#endif
|
||||
|
||||
isLoaded = true;
|
||||
}
|
||||
// RB end
|
||||
}
|
||||
|
@ -1050,12 +1073,44 @@ void idImage::GenerateCubeImage( const byte* pic[6], int size, textureFilter_t f
|
|||
|
||||
AllocImage();
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
int numChannels = 4;
|
||||
int bytesPerPixel = numChannels;
|
||||
if( opts.format == FMT_ALPHA || opts.format == FMT_DXT1 || opts.format == FMT_INT8 || opts.format == FMT_R8 )
|
||||
{
|
||||
bytesPerPixel = 1;
|
||||
}
|
||||
|
||||
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
|
||||
bytesPerPixel = info.bytesPerBlock;
|
||||
|
||||
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
|
||||
|
||||
for( int i = 0; i < im.NumImages(); i++ )
|
||||
{
|
||||
const bimageImage_t& img = im.GetImageHeader( i );
|
||||
const byte* data = im.GetImageData( i );
|
||||
int bufferW = img.width;
|
||||
if( IsCompressed() )
|
||||
{
|
||||
bufferW = ( img.width + 3 ) & ~3;
|
||||
}
|
||||
commandList->writeTexture( texture, 0, img.level, data, GetRowPitch( opts.format, img.width ) );
|
||||
}
|
||||
|
||||
commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource );
|
||||
commandList->commitBarriers();
|
||||
#else
|
||||
|
||||
for( int i = 0; i < im.NumImages(); i++ )
|
||||
{
|
||||
const bimageImage_t& img = im.GetImageHeader( i );
|
||||
const byte* data = im.GetImageData( i );
|
||||
SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data );
|
||||
}
|
||||
#endif
|
||||
|
||||
isLoaded = true;
|
||||
}
|
||||
|
||||
// RB begin
|
||||
|
@ -1118,11 +1173,41 @@ void idImage::UploadScratch( const byte* data, int cols, int rows, nvrhi::IComma
|
|||
|
||||
AllocImage();
|
||||
}
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
int numChannels = 4;
|
||||
int bytesPerPixel = numChannels;
|
||||
if( opts.format == FMT_ALPHA || opts.format == FMT_DXT1 || opts.format == FMT_INT8 || opts.format == FMT_R8 )
|
||||
{
|
||||
bytesPerPixel = 1;
|
||||
}
|
||||
|
||||
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
|
||||
bytesPerPixel = info.bytesPerBlock;
|
||||
|
||||
SetSamplerState( TF_LINEAR, TR_CLAMP );
|
||||
|
||||
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
|
||||
|
||||
int bufferW = opts.width;
|
||||
if( IsCompressed() )
|
||||
{
|
||||
bufferW = ( opts.width + 3 ) & ~3;
|
||||
}
|
||||
|
||||
for( int i = 0; i < 6; i++ )
|
||||
{
|
||||
commandList->writeTexture( texture, i, 0, pic[i], GetRowPitch( opts.format, opts.width ) );
|
||||
}
|
||||
|
||||
commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource );
|
||||
commandList->commitBarriers();
|
||||
#else
|
||||
for( int i = 0; i < 6; i++ )
|
||||
{
|
||||
SubImageUpload( 0, 0, 0, i, opts.width, opts.height, pic[i] );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1139,8 +1224,34 @@ void idImage::UploadScratch( const byte* data, int cols, int rows, nvrhi::IComma
|
|||
|
||||
AllocImage();
|
||||
}
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
int numChannels = 4;
|
||||
int bytesPerPixel = numChannels;
|
||||
if( opts.format == FMT_ALPHA || opts.format == FMT_DXT1 || opts.format == FMT_INT8 || opts.format == FMT_R8 )
|
||||
{
|
||||
bytesPerPixel = 1;
|
||||
}
|
||||
|
||||
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
|
||||
bytesPerPixel = info.bytesPerBlock;
|
||||
|
||||
SetSamplerState( TF_LINEAR, TR_REPEAT );
|
||||
|
||||
int bufferW = opts.width;
|
||||
if( IsCompressed() )
|
||||
{
|
||||
bufferW = ( opts.width + 3 ) & ~3;
|
||||
}
|
||||
|
||||
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
|
||||
commandList->writeTexture( texture, 0, 0, data, GetRowPitch( opts.format, opts.width ) );
|
||||
commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource );
|
||||
commandList->commitBarriers();
|
||||
#else
|
||||
SetSamplerState( TF_LINEAR, TR_REPEAT );
|
||||
SubImageUpload( 0, 0, 0, 0, opts.width, opts.height, data );
|
||||
#endif
|
||||
}
|
||||
|
||||
isLoaded = true;
|
||||
|
|
|
@ -706,8 +706,8 @@ drawSurf_t* idRenderModelOverlay::CreateOverlayDrawSurf( const viewEntity_t* spa
|
|||
srfTriangles_t* newTri = ( srfTriangles_t* )R_ClearedFrameAlloc( sizeof( *newTri ), FRAME_ALLOC_SURFACE_TRIANGLES );
|
||||
newTri->staticModelWithJoints = ( staticModel->jointsInverted != NULL ) ? const_cast< idRenderModelStatic* >( staticModel ) : NULL; // allow GPU skinning
|
||||
|
||||
newTri->ambientCache = vertexCache.AllocVertex( NULL, maxVerts );
|
||||
newTri->indexCache = vertexCache.AllocIndex( NULL, maxIndexes );
|
||||
newTri->ambientCache = vertexCache.AllocVertex( NULL, maxVerts, sizeof( idDrawVert ), nullptr );
|
||||
newTri->indexCache = vertexCache.AllocIndex( NULL, maxIndexes, sizeof( idDrawVert ), nullptr );
|
||||
|
||||
idDrawVert* mappedVerts = ( idDrawVert* )vertexCache.MappedVertexBuffer( newTri->ambientCache );
|
||||
triIndex_t* mappedIndexes = ( triIndex_t* )vertexCache.MappedIndexBuffer( newTri->indexCache );
|
||||
|
@ -793,7 +793,7 @@ drawSurf_t* idRenderModelOverlay::CreateOverlayDrawSurf( const viewEntity_t* spa
|
|||
drawSurf->renderZFail = 0;
|
||||
|
||||
R_SetupDrawSurfShader( drawSurf, material, &space->entityDef->parms );
|
||||
R_SetupDrawSurfJoints( drawSurf, newTri, NULL );
|
||||
R_SetupDrawSurfJoints( drawSurf, newTri, NULL, nullptr );
|
||||
|
||||
return drawSurf;
|
||||
}
|
||||
|
|
|
@ -882,9 +882,9 @@ void idRenderBackend::DBG_ShowSurfaceInfo( drawSurf_t** drawSurfs, int numDrawSu
|
|||
// transform the object verts into global space
|
||||
// R_AxisToModelMatrix( mt.entity->axis, mt.entity->origin, matrix );
|
||||
|
||||
tr.primaryWorld->DebugText( surfModelName, surfPoint + tr.primaryView->renderView.viewaxis[2] * 12,
|
||||
tr.primaryWorld->DrawText( surfModelName, surfPoint + tr.primaryView->renderView.viewaxis[2] * 12,
|
||||
0.35f, colorRed, tr.primaryView->renderView.viewaxis );
|
||||
tr.primaryWorld->DebugText( surfMatName, surfPoint,
|
||||
tr.primaryWorld->DrawText( surfMatName, surfPoint,
|
||||
0.35f, colorBlue, tr.primaryView->renderView.viewaxis );
|
||||
}
|
||||
|
||||
|
@ -956,7 +956,7 @@ void idRenderBackend::DBG_ShowViewEntitys( viewEntity_t* vModels )
|
|||
idVec3 corner;
|
||||
R_LocalPointToGlobal( vModel->modelMatrix, edef->localReferenceBounds[1], corner );
|
||||
|
||||
tr.primaryWorld->DebugText(
|
||||
tr.primaryWorld->DrawText(
|
||||
va( "%i:%s", edef->index, edef->parms.hModel->Name() ),
|
||||
corner,
|
||||
0.25f, color,
|
||||
|
|
285
neo/renderer/Passes/CommonPasses.cpp
Normal file
285
neo/renderer/Passes/CommonPasses.cpp
Normal file
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "renderer/RenderCommon.h"
|
||||
#include "CommonPasses.h"
|
||||
|
||||
|
||||
CommonRenderPasses::CommonRenderPasses()
|
||||
: m_Device( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
static bool IsSupportedBlitDimension( nvrhi::TextureDimension dimension )
|
||||
{
|
||||
return dimension == nvrhi::TextureDimension::Texture2D
|
||||
|| dimension == nvrhi::TextureDimension::Texture2DArray
|
||||
|| dimension == nvrhi::TextureDimension::TextureCube
|
||||
|| dimension == nvrhi::TextureDimension::TextureCubeArray;
|
||||
}
|
||||
|
||||
static bool IsTextureArray( nvrhi::TextureDimension dimension )
|
||||
{
|
||||
return dimension == nvrhi::TextureDimension::Texture2DArray
|
||||
|| dimension == nvrhi::TextureDimension::TextureCube
|
||||
|| dimension == nvrhi::TextureDimension::TextureCubeArray;
|
||||
}
|
||||
|
||||
void CommonRenderPasses::Init( nvrhi::IDevice* device )
|
||||
{
|
||||
m_Device = device;
|
||||
|
||||
int rectIndex = renderProgManager.FindShader( "builtin/rect", SHADER_STAGE_VERTEX, "", idList<shaderMacro_t>(), true, LAYOUT_DRAW_VERT );
|
||||
m_RectVS = renderProgManager.GetShader( rectIndex );
|
||||
|
||||
idList<shaderMacro_t> shaderMacros;
|
||||
shaderMacros.Append( shaderMacro_t( "TEXTURE_ARRAY", "0" ) );
|
||||
int blitIndex = renderProgManager.FindShader( "builtin/blit", SHADER_STAGE_FRAGMENT, "", shaderMacros, true, LAYOUT_DRAW_VERT );
|
||||
m_BlitPS = renderProgManager.GetShader( blitIndex );
|
||||
|
||||
shaderMacros[0].definition = "1";
|
||||
blitIndex = renderProgManager.FindShader( "builtin/blit", SHADER_STAGE_FRAGMENT, "", shaderMacros, true, LAYOUT_DRAW_VERT );
|
||||
m_BlitArrayPS = renderProgManager.GetShader( blitIndex );
|
||||
|
||||
auto samplerDesc = nvrhi::SamplerDesc()
|
||||
.setAllFilters( false )
|
||||
.setAllAddressModes( nvrhi::SamplerAddressMode::Clamp );
|
||||
m_PointClampSampler = m_Device->createSampler( samplerDesc );
|
||||
|
||||
samplerDesc.setAllFilters( true );
|
||||
m_LinearClampSampler = m_Device->createSampler( samplerDesc );
|
||||
|
||||
samplerDesc.setAllAddressModes( nvrhi::SamplerAddressMode::Wrap );
|
||||
m_LinearWrapSampler = m_Device->createSampler( samplerDesc );
|
||||
|
||||
samplerDesc.setMaxAnisotropy( 16 );
|
||||
m_AnisotropicWrapSampler = m_Device->createSampler( samplerDesc );
|
||||
|
||||
{
|
||||
unsigned int blackImage = 0xff000000;
|
||||
unsigned int grayImage = 0xff808080;
|
||||
unsigned int whiteImage = 0xffffffff;
|
||||
|
||||
nvrhi::TextureDesc textureDesc;
|
||||
textureDesc.format = nvrhi::Format::RGBA8_UNORM;
|
||||
textureDesc.width = 1;
|
||||
textureDesc.height = 1;
|
||||
textureDesc.mipLevels = 1;
|
||||
|
||||
textureDesc.debugName = "BlackTexture";
|
||||
m_BlackTexture = m_Device->createTexture( textureDesc );
|
||||
|
||||
textureDesc.debugName = "GrayTexture";
|
||||
m_GrayTexture = m_Device->createTexture( textureDesc );
|
||||
|
||||
textureDesc.debugName = "WhiteTexture";
|
||||
m_WhiteTexture = m_Device->createTexture( textureDesc );
|
||||
|
||||
textureDesc.dimension = nvrhi::TextureDimension::TextureCubeArray;
|
||||
textureDesc.debugName = "BlackCubeMapArray";
|
||||
textureDesc.arraySize = 6;
|
||||
m_BlackCubeMapArray = m_Device->createTexture( textureDesc );
|
||||
|
||||
textureDesc.dimension = nvrhi::TextureDimension::Texture2DArray;
|
||||
textureDesc.debugName = "BlackTexture2DArray";
|
||||
textureDesc.arraySize = 6;
|
||||
m_BlackTexture2DArray = m_Device->createTexture( textureDesc );
|
||||
textureDesc.debugName = "WhiteTexture2DArray";
|
||||
m_WhiteTexture2DArray = m_Device->createTexture( textureDesc );
|
||||
|
||||
// Write the textures using a temporary CL
|
||||
|
||||
nvrhi::CommandListHandle commandList = m_Device->createCommandList();
|
||||
commandList->open();
|
||||
|
||||
commandList->beginTrackingTextureState( m_BlackTexture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
|
||||
commandList->beginTrackingTextureState( m_GrayTexture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
|
||||
commandList->beginTrackingTextureState( m_WhiteTexture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
|
||||
commandList->beginTrackingTextureState( m_BlackCubeMapArray, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
|
||||
commandList->beginTrackingTextureState( m_BlackTexture2DArray, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
|
||||
commandList->beginTrackingTextureState( m_WhiteTexture2DArray, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
|
||||
|
||||
commandList->writeTexture( m_BlackTexture, 0, 0, &blackImage, 0 );
|
||||
commandList->writeTexture( m_GrayTexture, 0, 0, &grayImage, 0 );
|
||||
commandList->writeTexture( m_WhiteTexture, 0, 0, &whiteImage, 0 );
|
||||
|
||||
for( uint32_t arraySlice = 0; arraySlice < 6; arraySlice += 1 )
|
||||
{
|
||||
commandList->writeTexture( m_BlackTexture2DArray, arraySlice, 0, &blackImage, 0 );
|
||||
commandList->writeTexture( m_WhiteTexture2DArray, arraySlice, 0, &whiteImage, 0 );
|
||||
commandList->writeTexture( m_BlackCubeMapArray, arraySlice, 0, &blackImage, 0 );
|
||||
}
|
||||
|
||||
commandList->setPermanentTextureState( m_BlackTexture, nvrhi::ResourceStates::ShaderResource );
|
||||
commandList->setPermanentTextureState( m_GrayTexture, nvrhi::ResourceStates::ShaderResource );
|
||||
commandList->setPermanentTextureState( m_WhiteTexture, nvrhi::ResourceStates::ShaderResource );
|
||||
commandList->setPermanentTextureState( m_BlackCubeMapArray, nvrhi::ResourceStates::ShaderResource );
|
||||
commandList->setPermanentTextureState( m_BlackTexture2DArray, nvrhi::ResourceStates::ShaderResource );
|
||||
commandList->setPermanentTextureState( m_WhiteTexture2DArray, nvrhi::ResourceStates::ShaderResource );
|
||||
commandList->commitBarriers();
|
||||
|
||||
commandList->close();
|
||||
m_Device->executeCommandList( commandList );
|
||||
}
|
||||
|
||||
{
|
||||
nvrhi::BindingLayoutDesc layoutDesc;
|
||||
layoutDesc.visibility = nvrhi::ShaderType::All;
|
||||
layoutDesc.bindings =
|
||||
{
|
||||
nvrhi::BindingLayoutItem::PushConstants( 0, sizeof( BlitConstants ) ),
|
||||
nvrhi::BindingLayoutItem::Texture_SRV( 0 ),
|
||||
nvrhi::BindingLayoutItem::Sampler( 0 )
|
||||
};
|
||||
|
||||
m_BlitBindingLayout = m_Device->createBindingLayout( layoutDesc );
|
||||
}
|
||||
}
|
||||
|
||||
void CommonRenderPasses::BlitTexture( nvrhi::ICommandList* commandList, const BlitParameters& params, BindingCache* bindingCache )
|
||||
{
|
||||
assert( commandList );
|
||||
assert( params.targetFramebuffer );
|
||||
assert( params.sourceTexture );
|
||||
|
||||
const nvrhi::FramebufferDesc& targetFramebufferDesc = params.targetFramebuffer->getDesc();
|
||||
assert( targetFramebufferDesc.colorAttachments.size() == 1 );
|
||||
assert( targetFramebufferDesc.colorAttachments[0].valid() );
|
||||
assert( !targetFramebufferDesc.depthAttachment.valid() );
|
||||
|
||||
const nvrhi::FramebufferInfo& fbinfo = params.targetFramebuffer->getFramebufferInfo();
|
||||
const nvrhi::TextureDesc& sourceDesc = params.sourceTexture->getDesc();
|
||||
|
||||
assert( IsSupportedBlitDimension( sourceDesc.dimension ) );
|
||||
bool isTextureArray = IsTextureArray( sourceDesc.dimension );
|
||||
|
||||
nvrhi::Viewport targetViewport = params.targetViewport;
|
||||
if( targetViewport.width() == 0 && targetViewport.height() == 0 )
|
||||
{
|
||||
// If no viewport is specified, create one based on the framebuffer dimensions.
|
||||
// Note that the FB dimensions may not be the same as target texture dimensions, in case a non-zero mip level is used.
|
||||
targetViewport = nvrhi::Viewport( float( fbinfo.width ), float( fbinfo.height ) );
|
||||
}
|
||||
|
||||
nvrhi::IShader* shader = nullptr;
|
||||
switch( params.sampler )
|
||||
{
|
||||
case BlitSampler::Point:
|
||||
case BlitSampler::Linear:
|
||||
shader = isTextureArray ? m_BlitArrayPS : m_BlitPS;
|
||||
break;
|
||||
case BlitSampler::Sharpen:
|
||||
shader = isTextureArray ? m_SharpenArrayPS : m_SharpenPS;
|
||||
break;
|
||||
default:
|
||||
assert( false );
|
||||
}
|
||||
|
||||
nvrhi::GraphicsPipelineHandle& pso = m_BlitPsoCache[PsoCacheKey{ fbinfo, shader, params.blendState }];
|
||||
if( !pso )
|
||||
{
|
||||
nvrhi::GraphicsPipelineDesc psoDesc;
|
||||
psoDesc.bindingLayouts = { m_BlitBindingLayout };
|
||||
psoDesc.VS = m_RectVS;
|
||||
psoDesc.PS = shader;
|
||||
psoDesc.primType = nvrhi::PrimitiveType::TriangleStrip;
|
||||
psoDesc.renderState.rasterState.setCullNone();
|
||||
psoDesc.renderState.depthStencilState.depthTestEnable = false;
|
||||
psoDesc.renderState.depthStencilState.stencilEnable = false;
|
||||
psoDesc.renderState.blendState.targets[0] = params.blendState;
|
||||
|
||||
pso = m_Device->createGraphicsPipeline( psoDesc, params.targetFramebuffer );
|
||||
}
|
||||
|
||||
nvrhi::BindingSetDesc bindingSetDesc;
|
||||
{
|
||||
auto sourceDimension = sourceDesc.dimension;
|
||||
if( sourceDimension == nvrhi::TextureDimension::TextureCube || sourceDimension == nvrhi::TextureDimension::TextureCubeArray )
|
||||
{
|
||||
sourceDimension = nvrhi::TextureDimension::Texture2DArray;
|
||||
}
|
||||
|
||||
auto sourceSubresources = nvrhi::TextureSubresourceSet( params.sourceMip, 1, params.sourceArraySlice, 1 );
|
||||
|
||||
bindingSetDesc.bindings =
|
||||
{
|
||||
nvrhi::BindingSetItem::PushConstants( 0, sizeof( BlitConstants ) ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 0, params.sourceTexture ).setSubresources( sourceSubresources ).setDimension( sourceDimension ),
|
||||
nvrhi::BindingSetItem::Sampler( 0, params.sampler == BlitSampler::Point ? m_PointClampSampler : m_LinearClampSampler )
|
||||
};
|
||||
}
|
||||
|
||||
// If a binding cache is provided, get the binding set from the cache.
|
||||
// Otherwise, create one and then release it.
|
||||
nvrhi::BindingSetHandle sourceBindingSet;
|
||||
if( bindingCache )
|
||||
{
|
||||
sourceBindingSet = bindingCache->GetOrCreateBindingSet( bindingSetDesc, m_BlitBindingLayout );
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceBindingSet = m_Device->createBindingSet( bindingSetDesc, m_BlitBindingLayout );
|
||||
}
|
||||
|
||||
nvrhi::GraphicsState state;
|
||||
state.pipeline = pso;
|
||||
state.framebuffer = params.targetFramebuffer;
|
||||
state.bindings = { sourceBindingSet };
|
||||
state.viewport.addViewport( targetViewport );
|
||||
state.viewport.addScissorRect( nvrhi::Rect( targetViewport ) );
|
||||
state.blendConstantColor = params.blendConstantColor;
|
||||
|
||||
BlitConstants blitConstants = {};
|
||||
blitConstants.sourceOrigin = idVec2( params.sourceBox.x, params.sourceBox.y );
|
||||
blitConstants.sourceSize = idVec2( params.sourceBox.z, params.sourceBox.w );
|
||||
blitConstants.targetOrigin = idVec2( params.targetBox.x, params.targetBox.y );
|
||||
blitConstants.targetSize = idVec2( params.targetBox.z, params.targetBox.w );
|
||||
|
||||
commandList->setGraphicsState( state );
|
||||
|
||||
commandList->setPushConstants( &blitConstants, sizeof( blitConstants ) );
|
||||
|
||||
nvrhi::DrawArguments args;
|
||||
args.instanceCount = 1;
|
||||
args.vertexCount = 4;
|
||||
commandList->draw( args );
|
||||
}
|
||||
|
||||
void CommonRenderPasses::BlitTexture( nvrhi::ICommandList* commandList, nvrhi::IFramebuffer* targetFramebuffer, nvrhi::ITexture* sourceTexture, BindingCache* bindingCache )
|
||||
{
|
||||
assert( commandList );
|
||||
assert( targetFramebuffer );
|
||||
assert( sourceTexture );
|
||||
|
||||
BlitParameters params;
|
||||
params.targetFramebuffer = targetFramebuffer;
|
||||
params.sourceTexture = sourceTexture;
|
||||
BlitTexture( commandList, params, bindingCache );
|
||||
}
|
142
neo/renderer/Passes/CommonPasses.h
Normal file
142
neo/renderer/Passes/CommonPasses.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef COMMON_PASSES_H_
|
||||
#define COMMON_PASSES_H_
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
class BindingCache;
|
||||
class ShaderFactory;
|
||||
|
||||
constexpr uint32_t c_MaxRenderPassConstantBufferVersions = 16;
|
||||
|
||||
enum class BlitSampler
|
||||
{
|
||||
Point,
|
||||
Linear,
|
||||
Sharpen
|
||||
};
|
||||
|
||||
struct BlitParameters
|
||||
{
|
||||
nvrhi::IFramebuffer* targetFramebuffer = nullptr;
|
||||
nvrhi::Viewport targetViewport;
|
||||
idVec4 targetBox = idVec4( 0.f, 0.f, 1.f, 1.f );
|
||||
|
||||
nvrhi::ITexture* sourceTexture = nullptr;
|
||||
uint32_t sourceArraySlice = 0;
|
||||
uint32_t sourceMip = 0;
|
||||
idVec4 sourceBox = idVec4( 0.f, 0.f, 1.f, 1.f );
|
||||
|
||||
BlitSampler sampler = BlitSampler::Linear;
|
||||
nvrhi::BlendState::RenderTarget blendState;
|
||||
nvrhi::Color blendConstantColor = nvrhi::Color( 0.f );
|
||||
};
|
||||
|
||||
struct BlitConstants
|
||||
{
|
||||
idVec2 sourceOrigin;
|
||||
idVec2 sourceSize;
|
||||
|
||||
idVec2 targetOrigin;
|
||||
idVec2 targetSize;
|
||||
|
||||
float sharpenFactor;
|
||||
};
|
||||
|
||||
class CommonRenderPasses
|
||||
{
|
||||
protected:
|
||||
nvrhi::DeviceHandle m_Device;
|
||||
|
||||
struct PsoCacheKey
|
||||
{
|
||||
nvrhi::FramebufferInfo fbinfo;
|
||||
nvrhi::IShader* shader;
|
||||
nvrhi::BlendState::RenderTarget blendState;
|
||||
|
||||
bool operator==( const PsoCacheKey& other ) const
|
||||
{
|
||||
return fbinfo == other.fbinfo && shader == other.shader && blendState == other.blendState;
|
||||
}
|
||||
bool operator!=( const PsoCacheKey& other ) const
|
||||
{
|
||||
return !( *this == other );
|
||||
}
|
||||
|
||||
struct Hash
|
||||
{
|
||||
size_t operator()( const PsoCacheKey& s ) const
|
||||
{
|
||||
size_t hash = 0;
|
||||
nvrhi::hash_combine( hash, s.fbinfo );
|
||||
nvrhi::hash_combine( hash, s.shader );
|
||||
nvrhi::hash_combine( hash, s.blendState );
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
std::unordered_map<PsoCacheKey, nvrhi::GraphicsPipelineHandle, PsoCacheKey::Hash> m_BlitPsoCache;
|
||||
|
||||
public:
|
||||
nvrhi::ShaderHandle m_FullscreenVS;
|
||||
nvrhi::ShaderHandle m_FullscreenAtOneVS;
|
||||
nvrhi::ShaderHandle m_RectVS;
|
||||
nvrhi::ShaderHandle m_BlitPS;
|
||||
nvrhi::ShaderHandle m_BlitArrayPS;
|
||||
nvrhi::ShaderHandle m_SharpenPS;
|
||||
nvrhi::ShaderHandle m_SharpenArrayPS;
|
||||
|
||||
nvrhi::TextureHandle m_BlackTexture;
|
||||
nvrhi::TextureHandle m_GrayTexture;
|
||||
nvrhi::TextureHandle m_WhiteTexture;
|
||||
nvrhi::TextureHandle m_BlackTexture2DArray;
|
||||
nvrhi::TextureHandle m_WhiteTexture2DArray;
|
||||
nvrhi::TextureHandle m_BlackCubeMapArray;
|
||||
|
||||
nvrhi::SamplerHandle m_PointClampSampler;
|
||||
nvrhi::SamplerHandle m_LinearClampSampler;
|
||||
nvrhi::SamplerHandle m_LinearWrapSampler;
|
||||
nvrhi::SamplerHandle m_AnisotropicWrapSampler;
|
||||
|
||||
nvrhi::BindingLayoutHandle m_BlitBindingLayout;
|
||||
|
||||
CommonRenderPasses();
|
||||
|
||||
void Init( nvrhi::IDevice* device );
|
||||
|
||||
void BlitTexture( nvrhi::ICommandList* commandList, const BlitParameters& params, BindingCache* bindingCache = nullptr );
|
||||
|
||||
// Simplified form of BlitTexture that blits the entire source texture, mip 0 slice 0, into the entire target framebuffer using a linear sampler.
|
||||
void BlitTexture( nvrhi::ICommandList* commandList, nvrhi::IFramebuffer* targetFramebuffer, nvrhi::ITexture* sourceTexture, BindingCache* bindingCache = nullptr );
|
||||
};
|
||||
|
||||
#endif
|
855
neo/renderer/Passes/FowardShadingPass.cpp
Normal file
855
neo/renderer/Passes/FowardShadingPass.cpp
Normal file
|
@ -0,0 +1,855 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#include <precompiled.h>
|
||||
#pragma hdrstop
|
||||
|
||||
#include "framework/Common_local.h"
|
||||
#include "renderer/RenderCommon.h"
|
||||
#include "renderer/Framebuffer.h"
|
||||
|
||||
#include "FowardShadingPass.h"
|
||||
|
||||
/*
|
||||
same as D3DXMatrixOrthoOffCenterRH
|
||||
|
||||
http://msdn.microsoft.com/en-us/library/bb205348(VS.85).aspx
|
||||
*/
|
||||
static void MatrixOrthogonalProjectionRH( float m[16], float left, float right, float bottom, float top, float zNear, float zFar )
|
||||
{
|
||||
m[0] = 2 / ( right - left );
|
||||
m[4] = 0;
|
||||
m[8] = 0;
|
||||
m[12] = ( left + right ) / ( left - right );
|
||||
m[1] = 0;
|
||||
m[5] = 2 / ( top - bottom );
|
||||
m[9] = 0;
|
||||
m[13] = ( top + bottom ) / ( bottom - top );
|
||||
m[2] = 0;
|
||||
m[6] = 0;
|
||||
m[10] = 1 / ( zNear - zFar );
|
||||
m[14] = zNear / ( zNear - zFar );
|
||||
m[3] = 0;
|
||||
m[7] = 0;
|
||||
m[11] = 0;
|
||||
m[15] = 1;
|
||||
}
|
||||
|
||||
void ForwardShadingPass::Init( nvrhi::DeviceHandle deviceHandle )
|
||||
{
|
||||
device = deviceHandle;
|
||||
|
||||
auto texturedBindingLayoutDesc = nvrhi::BindingLayoutDesc( )
|
||||
.setVisibility( nvrhi::ShaderType::All )
|
||||
.addItem( nvrhi::BindingLayoutItem::VolatileConstantBuffer( 0 ) )
|
||||
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 0 ) )
|
||||
.addItem( nvrhi::BindingLayoutItem::Sampler( 0 ) );
|
||||
|
||||
auto geometrySkinnedBindingLayoutDesc = nvrhi::BindingLayoutDesc( )
|
||||
.setVisibility( nvrhi::ShaderType::All )
|
||||
.addItem( nvrhi::BindingLayoutItem::VolatileConstantBuffer( 0 ) )
|
||||
.addItem( nvrhi::BindingLayoutItem::VolatileConstantBuffer( 1 ) );
|
||||
|
||||
auto geometryBindingLayoutDesc = nvrhi::BindingLayoutDesc( )
|
||||
.setVisibility( nvrhi::ShaderType::All )
|
||||
.addItem( nvrhi::BindingLayoutItem::VolatileConstantBuffer( 0 ) );
|
||||
|
||||
texturedBindingLayout = device->createBindingLayout( texturedBindingLayoutDesc );
|
||||
geometryBindingLayout = device->createBindingLayout( geometryBindingLayoutDesc );
|
||||
pipelineDesc.bindingLayouts = { geometryBindingLayout };
|
||||
|
||||
geometryBindingSetDesc = nvrhi::BindingSetDesc( )
|
||||
.addItem( nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.ConstantBuffer( ) ) );
|
||||
|
||||
samplerCache.Init( deviceHandle.Get( ) );
|
||||
|
||||
pipeline = nullptr;
|
||||
}
|
||||
|
||||
void ForwardShadingPass::DrawInteractions( nvrhi::ICommandList* commandList, const viewDef_t* viewDef )
|
||||
{
|
||||
if( r_skipInteractions.GetBool( ) || viewDef->viewLights == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
commandList->beginMarker( "DrawInteractions" );
|
||||
|
||||
GL_SelectTexture( 0 );
|
||||
|
||||
const bool useLightDepthBounds = r_useLightDepthBounds.GetBool( ) && !r_useShadowMapping.GetBool( );
|
||||
|
||||
Framebuffer* previousFramebuffer = currentFramebuffer;
|
||||
|
||||
//
|
||||
// for each light, perform shadowing and adding
|
||||
//
|
||||
for( const viewLight_t* vLight = viewDef->viewLights; vLight != NULL; vLight = vLight->next )
|
||||
{
|
||||
// do fogging later
|
||||
if( vLight->lightShader->IsFogLight( ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( vLight->lightShader->IsBlendLight( ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( vLight->localInteractions == NULL && vLight->globalInteractions == NULL && vLight->translucentInteractions == NULL )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const idMaterial* lightShader = vLight->lightShader;
|
||||
commandList->beginMarker( lightShader->GetName( ) );
|
||||
|
||||
// set the depth bounds for the whole light
|
||||
if( useLightDepthBounds )
|
||||
{
|
||||
GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax );
|
||||
}
|
||||
|
||||
// RB: shadow mapping
|
||||
if( r_useShadowMapping.GetBool( ) )
|
||||
{
|
||||
int side, sideStop;
|
||||
|
||||
if( vLight->parallel )
|
||||
{
|
||||
side = 0;
|
||||
sideStop = r_shadowMapSplits.GetInteger( ) + 1;
|
||||
}
|
||||
else if( vLight->pointLight )
|
||||
{
|
||||
if( r_shadowMapSingleSide.GetInteger( ) != -1 )
|
||||
{
|
||||
side = r_shadowMapSingleSide.GetInteger( );
|
||||
sideStop = side + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
side = 0;
|
||||
sideStop = 6;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
side = -1;
|
||||
sideStop = 0;
|
||||
}
|
||||
|
||||
for( ; side < sideStop; side++ )
|
||||
{
|
||||
ShadowMapPass( commandList, vLight->globalShadows, vLight, side );
|
||||
}
|
||||
|
||||
// go back to main render target
|
||||
if( previousFramebuffer != NULL )
|
||||
{
|
||||
previousFramebuffer->Bind( );
|
||||
}
|
||||
else
|
||||
{
|
||||
Framebuffer::Unbind( );
|
||||
}
|
||||
|
||||
renderProgManager.Unbind( );
|
||||
|
||||
GL_State( GLS_DEFAULT, false );
|
||||
}
|
||||
// RB end
|
||||
|
||||
commandList->endMarker( );
|
||||
}
|
||||
|
||||
// disable stencil shadow test
|
||||
GL_State( GLS_DEFAULT );
|
||||
|
||||
// unbind texture units
|
||||
GL_SelectTexture( 0 );
|
||||
|
||||
// reset depth bounds
|
||||
if( useLightDepthBounds )
|
||||
{
|
||||
GL_DepthBoundsTest( 0.0f, 0.0f );
|
||||
}
|
||||
|
||||
commandList->endMarker( );
|
||||
}
|
||||
|
||||
void ForwardShadingPass::ShadowMapPass( nvrhi::ICommandList* commandList, const drawSurf_t* drawSurfs, const viewLight_t* vLight, int side )
|
||||
{
|
||||
if( r_skipShadows.GetBool( ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( drawSurfs == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( viewDef->renderView.rdflags & RDF_NOSHADOWS )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RENDERLOG_PRINTF( "---------- RB_ShadowMapPass( side = %i ) ----------\n", side );
|
||||
|
||||
renderProgManager.BindShader_Depth( );
|
||||
|
||||
GL_SelectTexture( 0 );
|
||||
|
||||
uint64 glState = 0;
|
||||
|
||||
// the actual stencil func will be set in the draw code, but we need to make sure it isn't
|
||||
// disabled here, and that the value will get reset for the interactions without looking
|
||||
// like a no-change-required
|
||||
GL_State( glState | GLS_POLYGON_OFFSET );
|
||||
|
||||
switch( r_shadowMapOccluderFacing.GetInteger( ) )
|
||||
{
|
||||
case 0:
|
||||
GL_State( ( glStateBits & ~( GLS_CULL_MASK ) ) | GLS_CULL_FRONTSIDED );
|
||||
GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat( ), r_shadowMapPolygonOffset.GetFloat( ) );
|
||||
break;
|
||||
|
||||
case 1:
|
||||
GL_State( ( glStateBits & ~( GLS_CULL_MASK ) ) | GLS_CULL_BACKSIDED );
|
||||
GL_PolygonOffset( -r_shadowMapPolygonFactor.GetFloat( ), -r_shadowMapPolygonOffset.GetFloat( ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
GL_State( ( glStateBits & ~( GLS_CULL_MASK ) ) | GLS_CULL_TWOSIDED );
|
||||
GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat( ), r_shadowMapPolygonOffset.GetFloat( ) );
|
||||
break;
|
||||
}
|
||||
|
||||
idRenderMatrix lightProjectionRenderMatrix;
|
||||
idRenderMatrix lightViewRenderMatrix;
|
||||
|
||||
|
||||
if( vLight->parallel && side >= 0 )
|
||||
{
|
||||
assert( side >= 0 && side < 6 );
|
||||
|
||||
// original light direction is from surface to light origin
|
||||
idVec3 lightDir = -vLight->lightCenter;
|
||||
if( lightDir.Normalize( ) == 0.0f )
|
||||
{
|
||||
lightDir[2] = -1.0f;
|
||||
}
|
||||
|
||||
idMat3 rotation = lightDir.ToMat3( );
|
||||
//idAngles angles = lightDir.ToAngles();
|
||||
//idMat3 rotation = angles.ToMat3();
|
||||
|
||||
const idVec3 viewDir = viewDef->renderView.viewaxis[0];
|
||||
const idVec3 viewPos = viewDef->renderView.vieworg;
|
||||
|
||||
#if 1
|
||||
idRenderMatrix::CreateViewMatrix( viewDef->renderView.vieworg, rotation, lightViewRenderMatrix );
|
||||
#else
|
||||
float lightViewMatrix[16];
|
||||
MatrixLookAtRH( lightViewMatrix, viewPos, lightDir, viewDir );
|
||||
idRenderMatrix::Transpose( *( idRenderMatrix* )lightViewMatrix, lightViewRenderMatrix );
|
||||
#endif
|
||||
|
||||
idBounds lightBounds;
|
||||
lightBounds.Clear( );
|
||||
|
||||
ALIGNTYPE16 frustumCorners_t corners;
|
||||
idRenderMatrix::GetFrustumCorners( corners, vLight->inverseBaseLightProject, bounds_zeroOneCube );
|
||||
|
||||
idVec4 point, transf;
|
||||
for( int j = 0; j < 8; j++ )
|
||||
{
|
||||
point[0] = corners.x[j];
|
||||
point[1] = corners.y[j];
|
||||
point[2] = corners.z[j];
|
||||
point[3] = 1;
|
||||
|
||||
lightViewRenderMatrix.TransformPoint( point, transf );
|
||||
transf[0] /= transf[3];
|
||||
transf[1] /= transf[3];
|
||||
transf[2] /= transf[3];
|
||||
|
||||
lightBounds.AddPoint( transf.ToVec3( ) );
|
||||
}
|
||||
|
||||
float lightProjectionMatrix[16];
|
||||
MatrixOrthogonalProjectionRH( lightProjectionMatrix, lightBounds[0][0], lightBounds[1][0], lightBounds[0][1], lightBounds[1][1], -lightBounds[1][2], -lightBounds[0][2] );
|
||||
idRenderMatrix::Transpose( *( idRenderMatrix* )lightProjectionMatrix, lightProjectionRenderMatrix );
|
||||
|
||||
|
||||
// 'frustumMVP' goes from global space -> camera local space -> camera projective space
|
||||
// invert the MVP projection so we can deform zero-to-one cubes into the frustum pyramid shape and calculate global bounds
|
||||
|
||||
idRenderMatrix splitFrustumInverse;
|
||||
if( !idRenderMatrix::Inverse( viewDef->frustumMVPs[FRUSTUM_CASCADE1 + side], splitFrustumInverse ) )
|
||||
{
|
||||
idLib::Warning( "splitFrustumMVP invert failed" );
|
||||
}
|
||||
|
||||
// splitFrustumCorners in global space
|
||||
ALIGNTYPE16 frustumCorners_t splitFrustumCorners;
|
||||
idRenderMatrix::GetFrustumCorners( splitFrustumCorners, splitFrustumInverse, bounds_unitCube );
|
||||
|
||||
idRenderMatrix lightViewProjectionRenderMatrix;
|
||||
idRenderMatrix::Multiply( lightProjectionRenderMatrix, lightViewRenderMatrix, lightViewProjectionRenderMatrix );
|
||||
|
||||
// find the bounding box of the current split in the light's clip space
|
||||
idBounds cropBounds;
|
||||
cropBounds.Clear( );
|
||||
for( int j = 0; j < 8; j++ )
|
||||
{
|
||||
point[0] = splitFrustumCorners.x[j];
|
||||
point[1] = splitFrustumCorners.y[j];
|
||||
point[2] = splitFrustumCorners.z[j];
|
||||
point[3] = 1;
|
||||
|
||||
lightViewRenderMatrix.TransformPoint( point, transf );
|
||||
transf[0] /= transf[3];
|
||||
transf[1] /= transf[3];
|
||||
transf[2] /= transf[3];
|
||||
|
||||
cropBounds.AddPoint( transf.ToVec3( ) );
|
||||
}
|
||||
|
||||
// don't let the frustum AABB be bigger than the light AABB
|
||||
if( cropBounds[0][0] < lightBounds[0][0] )
|
||||
{
|
||||
cropBounds[0][0] = lightBounds[0][0];
|
||||
}
|
||||
|
||||
if( cropBounds[0][1] < lightBounds[0][1] )
|
||||
{
|
||||
cropBounds[0][1] = lightBounds[0][1];
|
||||
}
|
||||
|
||||
if( cropBounds[1][0] > lightBounds[1][0] )
|
||||
{
|
||||
cropBounds[1][0] = lightBounds[1][0];
|
||||
}
|
||||
|
||||
if( cropBounds[1][1] > lightBounds[1][1] )
|
||||
{
|
||||
cropBounds[1][1] = lightBounds[1][1];
|
||||
}
|
||||
|
||||
cropBounds[0][2] = lightBounds[0][2];
|
||||
cropBounds[1][2] = lightBounds[1][2];
|
||||
|
||||
//float cropMatrix[16];
|
||||
//MatrixCrop(cropMatrix, cropBounds[0], cropBounds[1]);
|
||||
|
||||
//idRenderMatrix cropRenderMatrix;
|
||||
//idRenderMatrix::Transpose( *( idRenderMatrix* )cropMatrix, cropRenderMatrix );
|
||||
|
||||
//idRenderMatrix tmp = lightProjectionRenderMatrix;
|
||||
//idRenderMatrix::Multiply( cropRenderMatrix, tmp, lightProjectionRenderMatrix );
|
||||
|
||||
MatrixOrthogonalProjectionRH( lightProjectionMatrix, cropBounds[0][0], cropBounds[1][0], cropBounds[0][1], cropBounds[1][1], -cropBounds[1][2], -cropBounds[0][2] );
|
||||
idRenderMatrix::Transpose( *( idRenderMatrix* )lightProjectionMatrix, lightProjectionRenderMatrix );
|
||||
|
||||
shadowV[side] = lightViewRenderMatrix;
|
||||
shadowP[side] = lightProjectionRenderMatrix;
|
||||
}
|
||||
else if( vLight->pointLight && side >= 0 )
|
||||
{
|
||||
assert( side >= 0 && side < 6 );
|
||||
|
||||
// FIXME OPTIMIZE no memset
|
||||
|
||||
float viewMatrix[16];
|
||||
|
||||
idVec3 vec;
|
||||
idVec3 origin = vLight->globalLightOrigin;
|
||||
|
||||
// side of a point light
|
||||
memset( viewMatrix, 0, sizeof( viewMatrix ) );
|
||||
switch( side )
|
||||
{
|
||||
case 0:
|
||||
viewMatrix[0] = 1;
|
||||
viewMatrix[9] = 1;
|
||||
viewMatrix[6] = -1;
|
||||
break;
|
||||
case 1:
|
||||
viewMatrix[0] = -1;
|
||||
viewMatrix[9] = -1;
|
||||
viewMatrix[6] = -1;
|
||||
break;
|
||||
case 2:
|
||||
viewMatrix[4] = 1;
|
||||
viewMatrix[1] = -1;
|
||||
viewMatrix[10] = 1;
|
||||
break;
|
||||
case 3:
|
||||
viewMatrix[4] = -1;
|
||||
viewMatrix[1] = -1;
|
||||
viewMatrix[10] = -1;
|
||||
break;
|
||||
case 4:
|
||||
viewMatrix[8] = 1;
|
||||
viewMatrix[1] = -1;
|
||||
viewMatrix[6] = -1;
|
||||
break;
|
||||
case 5:
|
||||
viewMatrix[8] = -1;
|
||||
viewMatrix[1] = 1;
|
||||
viewMatrix[6] = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
viewMatrix[12] = -origin[0] * viewMatrix[0] + -origin[1] * viewMatrix[4] + -origin[2] * viewMatrix[8];
|
||||
viewMatrix[13] = -origin[0] * viewMatrix[1] + -origin[1] * viewMatrix[5] + -origin[2] * viewMatrix[9];
|
||||
viewMatrix[14] = -origin[0] * viewMatrix[2] + -origin[1] * viewMatrix[6] + -origin[2] * viewMatrix[10];
|
||||
|
||||
viewMatrix[3] = 0;
|
||||
viewMatrix[7] = 0;
|
||||
viewMatrix[11] = 0;
|
||||
viewMatrix[15] = 1;
|
||||
|
||||
// from world space to light origin, looking down the X axis
|
||||
float unflippedLightViewMatrix[16];
|
||||
|
||||
// from world space to OpenGL view space, looking down the negative Z axis
|
||||
float lightViewMatrix[16];
|
||||
|
||||
static float s_flipMatrix[16] =
|
||||
{
|
||||
// convert from our coordinate system (looking down X)
|
||||
// to OpenGL's coordinate system (looking down -Z)
|
||||
0, 0, -1, 0,
|
||||
-1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 0, 1
|
||||
};
|
||||
|
||||
memcpy( unflippedLightViewMatrix, viewMatrix, sizeof( unflippedLightViewMatrix ) );
|
||||
R_MatrixMultiply( viewMatrix, s_flipMatrix, lightViewMatrix );
|
||||
|
||||
idRenderMatrix::Transpose( *( idRenderMatrix* )lightViewMatrix, lightViewRenderMatrix );
|
||||
|
||||
// set up 90 degree projection matrix
|
||||
const float zNear = 4;
|
||||
const float fov = r_shadowMapFrustumFOV.GetFloat( );
|
||||
|
||||
float ymax = zNear * tan( fov * idMath::PI / 360.0f );
|
||||
float ymin = -ymax;
|
||||
|
||||
float xmax = zNear * tan( fov * idMath::PI / 360.0f );
|
||||
float xmin = -xmax;
|
||||
|
||||
const float width = xmax - xmin;
|
||||
const float height = ymax - ymin;
|
||||
|
||||
// from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ )
|
||||
float lightProjectionMatrix[16];
|
||||
|
||||
lightProjectionMatrix[0 * 4 + 0] = 2.0f * zNear / width;
|
||||
lightProjectionMatrix[1 * 4 + 0] = 0.0f;
|
||||
lightProjectionMatrix[2 * 4 + 0] = ( xmax + xmin ) / width; // normally 0
|
||||
lightProjectionMatrix[3 * 4 + 0] = 0.0f;
|
||||
|
||||
lightProjectionMatrix[0 * 4 + 1] = 0.0f;
|
||||
lightProjectionMatrix[1 * 4 + 1] = 2.0f * zNear / height;
|
||||
lightProjectionMatrix[2 * 4 + 1] = ( ymax + ymin ) / height; // normally 0
|
||||
lightProjectionMatrix[3 * 4 + 1] = 0.0f;
|
||||
|
||||
// this is the far-plane-at-infinity formulation, and
|
||||
// crunches the Z range slightly so w=0 vertexes do not
|
||||
// rasterize right at the wraparound point
|
||||
lightProjectionMatrix[0 * 4 + 2] = 0.0f;
|
||||
lightProjectionMatrix[1 * 4 + 2] = 0.0f;
|
||||
lightProjectionMatrix[2 * 4 + 2] = -0.999f; // adjust value to prevent imprecision issues
|
||||
lightProjectionMatrix[3 * 4 + 2] = -2.0f * zNear;
|
||||
|
||||
lightProjectionMatrix[0 * 4 + 3] = 0.0f;
|
||||
lightProjectionMatrix[1 * 4 + 3] = 0.0f;
|
||||
lightProjectionMatrix[2 * 4 + 3] = -1.0f;
|
||||
lightProjectionMatrix[3 * 4 + 3] = 0.0f;
|
||||
|
||||
idRenderMatrix::Transpose( *( idRenderMatrix* )lightProjectionMatrix, lightProjectionRenderMatrix );
|
||||
|
||||
shadowV[side] = lightViewRenderMatrix;
|
||||
shadowP[side] = lightProjectionRenderMatrix;
|
||||
}
|
||||
else
|
||||
{
|
||||
lightViewRenderMatrix.Identity( );
|
||||
lightProjectionRenderMatrix = vLight->baseLightProject;
|
||||
|
||||
shadowV[0] = lightViewRenderMatrix;
|
||||
shadowP[0] = lightProjectionRenderMatrix;
|
||||
}
|
||||
|
||||
GL_ViewportAndScissor( 0, 0, shadowMapResolutions[vLight->shadowLOD], shadowMapResolutions[vLight->shadowLOD] );
|
||||
|
||||
//glClear( GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
// process the chain of shadows with the current rendering state
|
||||
currentSpace = NULL;
|
||||
|
||||
nvrhi::GraphicsState graphicsState;
|
||||
graphicsState.framebuffer = currentFramebuffer->GetApiObject( );
|
||||
nvrhi::Viewport viewport;
|
||||
viewport.minX = currentViewport.x1;
|
||||
viewport.minY = currentViewport.y1;
|
||||
viewport.maxX = currentViewport.x2;
|
||||
viewport.maxY = currentViewport.y2;
|
||||
viewport.minZ = currentViewport.zmin;
|
||||
viewport.maxZ = currentViewport.zmax;
|
||||
graphicsState.viewport.addViewportAndScissorRect( viewport );
|
||||
graphicsState.viewport.addScissorRect( nvrhi::Rect( currentScissor.x1, currentScissor.y1, currentScissor.x2, currentScissor.y2 ) );
|
||||
renderProgManager.BindShader_Depth( );
|
||||
auto currentBindingSet = bindingCache.GetOrCreateBindingSet( geometryBindingSetDesc, renderProgManager.BindingLayout( ) );
|
||||
graphicsState.bindings = { currentBindingSet };
|
||||
|
||||
bool stateValid = false;
|
||||
|
||||
nvrhi::DrawArguments currentDraw;
|
||||
currentDraw.instanceCount = 0;
|
||||
|
||||
shaderStage_t lastStage;
|
||||
bool changedStage = false;
|
||||
|
||||
int lastShader = -1;
|
||||
|
||||
for( const drawSurf_t* drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight )
|
||||
{
|
||||
stateValid = false;
|
||||
|
||||
// Make sure the shadow occluder geometry is done
|
||||
if( drawSurf->shadowVolumeState != SHADOWVOLUME_DONE )
|
||||
{
|
||||
assert( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED || drawSurf->shadowVolumeState == SHADOWVOLUME_DONE );
|
||||
|
||||
uint64 start = Sys_Microseconds( );
|
||||
while( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED )
|
||||
{
|
||||
Sys_Yield( );
|
||||
}
|
||||
uint64 end = Sys_Microseconds( );
|
||||
|
||||
// TODO(Stephen): will probably need to change this if we're going to make this multi-threaded.
|
||||
tr.backend.pc.cpuShadowMicroSec += end - start;
|
||||
}
|
||||
|
||||
if( drawSurf->numIndexes == 0 )
|
||||
{
|
||||
continue; // a job may have created an empty shadow geometry
|
||||
}
|
||||
|
||||
if( drawSurf->space != currentSpace )
|
||||
{
|
||||
idRenderMatrix modelRenderMatrix;
|
||||
idRenderMatrix::Transpose( *( idRenderMatrix* )drawSurf->space->modelMatrix, modelRenderMatrix );
|
||||
|
||||
idRenderMatrix modelToLightRenderMatrix;
|
||||
idRenderMatrix::Multiply( lightViewRenderMatrix, modelRenderMatrix, modelToLightRenderMatrix );
|
||||
|
||||
idRenderMatrix clipMVP;
|
||||
idRenderMatrix::Multiply( lightProjectionRenderMatrix, modelToLightRenderMatrix, clipMVP );
|
||||
|
||||
if( vLight->parallel )
|
||||
{
|
||||
idRenderMatrix MVP;
|
||||
idRenderMatrix::Multiply( renderMatrix_clipSpaceToWindowSpace, clipMVP, MVP );
|
||||
|
||||
RB_SetMVP( clipMVP );
|
||||
}
|
||||
else if( side < 0 )
|
||||
{
|
||||
// from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ )
|
||||
idRenderMatrix MVP;
|
||||
idRenderMatrix::Multiply( renderMatrix_windowSpaceToClipSpace, clipMVP, MVP );
|
||||
|
||||
RB_SetMVP( MVP );
|
||||
}
|
||||
else
|
||||
{
|
||||
RB_SetMVP( clipMVP );
|
||||
}
|
||||
|
||||
// set the local light position to allow the vertex program to project the shadow volume end cap to infinity
|
||||
/*
|
||||
idVec4 localLight( 0.0f );
|
||||
R_GlobalPointToLocal( drawSurf->space->modelMatrix, vLight->globalLightOrigin, localLight.ToVec3() );
|
||||
SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLight.ToFloatPtr() );
|
||||
*/
|
||||
|
||||
currentSpace = drawSurf->space;
|
||||
}
|
||||
|
||||
bool didDraw = false;
|
||||
|
||||
const idMaterial* shader = drawSurf->material;
|
||||
|
||||
// get the expressions for conditionals / color / texcoords
|
||||
const float* regs = drawSurf->shaderRegisters;
|
||||
idVec4 color( 0, 0, 0, 1 );
|
||||
|
||||
uint64 surfGLState = 0;
|
||||
|
||||
// set polygon offset if necessary
|
||||
if( shader && shader->TestMaterialFlag( MF_POLYGONOFFSET ) )
|
||||
{
|
||||
surfGLState |= GLS_POLYGON_OFFSET;
|
||||
GL_PolygonOffset( r_offsetFactor.GetFloat( ), r_offsetUnits.GetFloat( ) * shader->GetPolygonOffset( ) );
|
||||
}
|
||||
|
||||
if( shader && shader->Coverage( ) == MC_PERFORATED )
|
||||
{
|
||||
// perforated surfaces may have multiple alpha tested stages
|
||||
for( int stage = 0; stage < shader->GetNumStages( ); stage++ )
|
||||
{
|
||||
const shaderStage_t* pStage = shader->GetStage( stage );
|
||||
|
||||
if( !pStage->hasAlphaTest )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check the stage enable condition
|
||||
if( regs[pStage->conditionRegister] == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we at least tried to draw an alpha tested stage,
|
||||
// we won't draw the opaque surface
|
||||
didDraw = true;
|
||||
|
||||
// set the alpha modulate
|
||||
color[3] = regs[pStage->color.registers[3]];
|
||||
|
||||
// skip the entire stage if alpha would be black
|
||||
if( color[3] <= 0.0f )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64 stageGLState = surfGLState;
|
||||
|
||||
// set privatePolygonOffset if necessary
|
||||
if( pStage->privatePolygonOffset )
|
||||
{
|
||||
GL_PolygonOffset( r_offsetFactor.GetFloat( ), r_offsetUnits.GetFloat( ) * pStage->privatePolygonOffset );
|
||||
stageGLState |= GLS_POLYGON_OFFSET;
|
||||
}
|
||||
|
||||
GL_Color( color );
|
||||
|
||||
GL_State( stageGLState );
|
||||
idVec4 alphaTestValue( regs[pStage->alphaTestRegister] );
|
||||
renderProgManager.SetRenderParm( RENDERPARM_ALPHA_TEST, alphaTestValue.ToFloatPtr( ) );
|
||||
|
||||
if( drawSurf->jointCache )
|
||||
{
|
||||
renderProgManager.BindShader_TextureVertexColorSkinned( );
|
||||
}
|
||||
else
|
||||
{
|
||||
renderProgManager.BindShader_TextureVertexColor( );
|
||||
}
|
||||
|
||||
RB_SetVertexColorParms( SVC_IGNORE );
|
||||
|
||||
bool imageChanged = ( imageParms[0] != pStage->texture.image );
|
||||
|
||||
// bind the texture
|
||||
GL_SelectTexture( 0 );
|
||||
GL_BindTexture( pStage->texture.image );
|
||||
|
||||
// set texture matrix and texGens
|
||||
PrepareStageTexturing( pStage, drawSurf );
|
||||
|
||||
if( imageChanged )
|
||||
{
|
||||
auto bindingSetDesc = nvrhi::BindingSetDesc( )
|
||||
.addItem( nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.ConstantBuffer( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 0, ( nvrhi::ITexture* )imageParms[0]->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 0, ( nvrhi::ISampler* )imageParms[0]->GetSampler( samplerCache ) ) );
|
||||
|
||||
auto currentBindingSet = bindingCache.GetOrCreateBindingSet( bindingSetDesc, renderProgManager.BindingLayout() );
|
||||
|
||||
graphicsState.bindings = { currentBindingSet };
|
||||
|
||||
stateValid = false;
|
||||
}
|
||||
|
||||
// must render with less-equal for Z-Cull to work properly
|
||||
assert( ( GL_GetCurrentState( ) & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS );
|
||||
|
||||
SetupInputBuffers( drawSurf, graphicsState );
|
||||
|
||||
renderProgManager.CommitConstantBuffer( commandList );
|
||||
|
||||
if( !stateValid )
|
||||
{
|
||||
commandList->setGraphicsState( graphicsState );
|
||||
stateValid = true;
|
||||
}
|
||||
|
||||
if( !pipeline )
|
||||
{
|
||||
pipeline = CreateGraphicsPipeline( currentFramebuffer->GetApiObject() );
|
||||
}
|
||||
|
||||
nvrhi::DrawArguments args;
|
||||
args.vertexCount = drawSurf->numIndexes;
|
||||
args.instanceCount = 1;
|
||||
commandList->drawIndexed( args );
|
||||
|
||||
// clean up
|
||||
FinishStageTexturing( pStage, drawSurf );
|
||||
|
||||
// unset privatePolygonOffset if necessary
|
||||
if( pStage->privatePolygonOffset )
|
||||
{
|
||||
GL_PolygonOffset( r_offsetFactor.GetFloat( ), r_offsetUnits.GetFloat( ) * shader->GetPolygonOffset( ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !didDraw )
|
||||
{
|
||||
if( drawSurf->jointCache )
|
||||
{
|
||||
renderProgManager.BindShader_DepthSkinned( );
|
||||
}
|
||||
else
|
||||
{
|
||||
renderProgManager.BindShader_Depth( );
|
||||
}
|
||||
|
||||
// must render with less-equal for Z-Cull to work properly
|
||||
assert( ( GL_GetCurrentState( ) & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS );
|
||||
|
||||
SetupInputBuffers( drawSurf, graphicsState );
|
||||
|
||||
if( !stateValid )
|
||||
{
|
||||
commandList->setGraphicsState( graphicsState );
|
||||
stateValid = true;
|
||||
}
|
||||
|
||||
if( !pipeline )
|
||||
{
|
||||
pipeline = CreateGraphicsPipeline( currentFramebuffer->GetApiObject( ) );
|
||||
}
|
||||
|
||||
renderProgManager.CommitConstantBuffer( commandList );
|
||||
|
||||
nvrhi::DrawArguments args;
|
||||
args.vertexCount = drawSurf->numIndexes;
|
||||
args.instanceCount = 1;
|
||||
commandList->drawIndexed( args );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nvrhi::GraphicsPipelineHandle ForwardShadingPass::CreateGraphicsPipeline( nvrhi::IFramebuffer* framebuffer )
|
||||
{
|
||||
return device->createGraphicsPipeline( pipelineDesc, framebuffer );
|
||||
}
|
||||
|
||||
void ForwardShadingPass::SetupView( nvrhi::ICommandList* commandList, viewDef_t* viewDef )
|
||||
{
|
||||
}
|
||||
|
||||
bool ForwardShadingPass::SetupMaterial( const idMaterial* material, nvrhi::RasterCullMode cullMode, nvrhi::GraphicsState& state )
|
||||
{
|
||||
if( !pipeline )
|
||||
{
|
||||
pipeline = CreateGraphicsPipeline( state.framebuffer );
|
||||
}
|
||||
|
||||
if( !pipeline )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
assert( pipeline->getFramebufferInfo( ) == state.framebuffer->getFramebufferInfo( ) );
|
||||
|
||||
state.pipeline = pipeline;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ForwardShadingPass::SetupInputBuffers( const drawSurf_t* surf, nvrhi::GraphicsState& state )
|
||||
{
|
||||
// Get vertex buffer
|
||||
const vertCacheHandle_t vbHandle = surf->ambientCache;
|
||||
idVertexBuffer* vertexBuffer;
|
||||
if( vertexCache.CacheIsStatic( vbHandle ) )
|
||||
{
|
||||
vertexBuffer = &vertexCache.staticData.vertexBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint64 frameNum = ( int )( vbHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
|
||||
if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
|
||||
{
|
||||
idLib::Warning( "RB_DrawElementsWithCounters, vertexBuffer == NULL" );
|
||||
return;
|
||||
}
|
||||
vertexBuffer = &vertexCache.frameData[vertexCache.drawListNum].vertexBuffer;
|
||||
}
|
||||
const uint vertOffset = ( uint )( vbHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
|
||||
|
||||
// Get index buffer
|
||||
const vertCacheHandle_t ibHandle = surf->indexCache;
|
||||
idIndexBuffer* indexBuffer;
|
||||
if( vertexCache.CacheIsStatic( ibHandle ) )
|
||||
{
|
||||
indexBuffer = &vertexCache.staticData.indexBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint64 frameNum = ( int )( ibHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
|
||||
if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
|
||||
{
|
||||
idLib::Warning( "RB_DrawElementsWithCounters, indexBuffer == NULL" );
|
||||
return;
|
||||
}
|
||||
indexBuffer = &vertexCache.frameData[vertexCache.drawListNum].indexBuffer;
|
||||
}
|
||||
const uint indexOffset = ( uint )( ibHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
|
||||
|
||||
RENDERLOG_PRINTF( "Binding Buffers: %p:%i %p:%i\n", vertexBuffer, vertOffset, indexBuffer, indexOffset );
|
||||
|
||||
state.indexBuffer = { indexBuffer->GetAPIObject(), nvrhi::Format::R16_UINT, indexOffset };
|
||||
state.vertexBuffers = { { vertexBuffer->GetAPIObject(), 0, vertOffset } };
|
||||
}
|
||||
|
||||
void ForwardShadingPass::SetPushConstants( nvrhi::ICommandList* commandList, nvrhi::GraphicsState& state, nvrhi::DrawArguments& args )
|
||||
{
|
||||
}
|
68
neo/renderer/Passes/FowardShadingPass.h
Normal file
68
neo/renderer/Passes/FowardShadingPass.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef RENDERER_PASSES_FORWARDSHADINGPASS_H_
|
||||
#define RENDERER_PASSES_FORWARDSHADINGPASS_H_
|
||||
|
||||
#include "GeometryPasses.h"
|
||||
|
||||
class ForwardShadingPass : IGeometryPass
|
||||
{
|
||||
public:
|
||||
|
||||
ForwardShadingPass( ) = default;
|
||||
virtual ~ForwardShadingPass( ) = default;
|
||||
|
||||
void Init( nvrhi::DeviceHandle deviceHandle );
|
||||
|
||||
void DrawInteractions( nvrhi::ICommandList* commandList, const viewDef_t* _viewDef );
|
||||
void ShadowMapPass( nvrhi::ICommandList* commandList, const drawSurf_t* drawSurfs, const viewLight_t* vLight, int side );
|
||||
|
||||
protected:
|
||||
|
||||
nvrhi::DeviceHandle device;
|
||||
nvrhi::BindingLayoutHandle geometryBindingLayout;
|
||||
nvrhi::BindingLayoutHandle texturedBindingLayout;
|
||||
nvrhi::BindingSetDesc geometryBindingSetDesc;
|
||||
SamplerCache samplerCache;
|
||||
|
||||
nvrhi::GraphicsPipelineHandle CreateGraphicsPipeline( nvrhi::IFramebuffer* framebuffer );
|
||||
|
||||
public:
|
||||
|
||||
void SetupView( nvrhi::ICommandList* commandList, viewDef_t* viewDef ) override;
|
||||
bool SetupMaterial( const idMaterial* material, nvrhi::RasterCullMode cullMode, nvrhi::GraphicsState& state ) override;
|
||||
void SetupInputBuffers( const drawSurf_t* drawSurf, nvrhi::GraphicsState& state ) override;
|
||||
void SetPushConstants( nvrhi::ICommandList* commandList, nvrhi::GraphicsState& state, nvrhi::DrawArguments& args ) override;
|
||||
|
||||
private:
|
||||
|
||||
idRenderMatrix shadowV[6]; // shadow depth view matrix
|
||||
idRenderMatrix shadowP[6]; // shadow depth projection matrix
|
||||
};
|
||||
|
||||
#endif
|
683
neo/renderer/Passes/GBufferFillPass.cpp
Normal file
683
neo/renderer/Passes/GBufferFillPass.cpp
Normal file
|
@ -0,0 +1,683 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#include <precompiled.h>
|
||||
#pragma hdrstop
|
||||
|
||||
#include "renderer/RenderCommon.h"
|
||||
|
||||
#include "GBufferFillPass.h"
|
||||
|
||||
void GBufferFillPass::Init( nvrhi::DeviceHandle deviceHandle )
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
void GBufferFillPass::RenderView( nvrhi::ICommandList* commandList, const drawSurf_t* const* drawSurfs, int numDrawSurfs, bool fillGbuffer )
|
||||
{
|
||||
Framebuffer* previousFramebuffer = Framebuffer::GetActiveFramebuffer( );
|
||||
|
||||
if( numDrawSurfs == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !drawSurfs )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if we are just doing 2D rendering, no need to fill the depth buffer
|
||||
if( viewDef->viewEntitys == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( viewDef->renderView.rdflags & RDF_NOAMBIENT )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined( USE_VULKAN )
|
||||
if( fillGbuffer )
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
if( !fillGbuffer )
|
||||
{
|
||||
// clear gbuffer
|
||||
GL_Clear( true, false, false, 0, 0.0f, 0.0f, 0.0f, 1.0f, false );
|
||||
}
|
||||
*/
|
||||
|
||||
if( !fillGbuffer && r_useSSAO.GetBool( ) && r_ssaoDebug.GetBool( ) )
|
||||
{
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS );
|
||||
|
||||
// We just want to do a quad pass - so make sure we disable any texgen and
|
||||
// set the texture matrix to the identity so we don't get anomalies from
|
||||
// any stale uniform data being present from a previous draw call
|
||||
const float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
|
||||
const float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
|
||||
renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_S, texS );
|
||||
renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_T, texT );
|
||||
|
||||
// disable any texgen
|
||||
const float texGenEnabled[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
renderProgManager.SetRenderParm( RENDERPARM_TEXGEN_0_ENABLED, texGenEnabled );
|
||||
|
||||
currentSpace = NULL;
|
||||
RB_SetMVP( renderMatrix_identity );
|
||||
|
||||
renderProgManager.BindShader_Texture( );
|
||||
GL_Color( idVec4( 1 ) );
|
||||
|
||||
GL_SelectTexture( 0 );
|
||||
globalImages->ambientOcclusionImage[0]->Bind( );
|
||||
|
||||
DrawElementsWithCounters( &tr.backend.unitSquareSurface );
|
||||
|
||||
renderProgManager.Unbind( );
|
||||
GL_State( GLS_DEFAULT );
|
||||
|
||||
renderProgManager.SetRenderParm( RENDERPARM_ALPHA_TEST, vec4_zero.ToFloatPtr( ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
renderLog.OpenMainBlock( fillGbuffer ? MRB_FILL_GEOMETRY_BUFFER : MRB_AMBIENT_PASS );
|
||||
renderLog.OpenBlock( fillGbuffer ? "Fill_GeometryBuffer" : "Render_AmbientPass", colorBlue );
|
||||
|
||||
if( fillGbuffer )
|
||||
{
|
||||
globalFramebuffers.geometryBufferFBO->Bind( );
|
||||
|
||||
GL_Clear( true, false, false, 0, 0.0f, 0.0f, 0.0f, 1.0f, false );
|
||||
}
|
||||
|
||||
commandList->setEnableAutomaticBarriers( false );
|
||||
commandList->setResourceStatesForFramebuffer( currentFrameBuffer->GetApiObject( ) );
|
||||
commandList->commitBarriers( );
|
||||
|
||||
// RB: not needed
|
||||
// GL_StartDepthPass( backEnd.viewDef->scissor );
|
||||
|
||||
// force MVP change on first surface
|
||||
currentSpace = NULL;
|
||||
|
||||
// draw all the subview surfaces, which will already be at the start of the sorted list,
|
||||
// with the general purpose path
|
||||
GL_State( GLS_DEFAULT );
|
||||
|
||||
#define BLEND_NORMALS 1
|
||||
|
||||
// RB: even use additive blending to blend the normals
|
||||
//GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
|
||||
GL_Color( colorWhite );
|
||||
|
||||
idVec4 diffuseColor;
|
||||
idVec4 specularColor;
|
||||
idVec4 ambientColor;
|
||||
|
||||
if( viewDef->renderView.rdflags & RDF_IRRADIANCE )
|
||||
{
|
||||
// RB: don't let artist run into a trap when baking multibounce lightgrids
|
||||
|
||||
// use default value of r_lightScale 3
|
||||
const float lightScale = 3;
|
||||
const idVec4 lightColor = colorWhite * lightScale;
|
||||
|
||||
// apply the world-global overbright and the 2x factor for specular
|
||||
diffuseColor = lightColor;
|
||||
specularColor = lightColor;// * 2.0f;
|
||||
|
||||
// loose 5% with every bounce like in DDGI
|
||||
const float energyConservation = 0.95f;
|
||||
|
||||
//ambientColor.Set( energyConservation, energyConservation, energyConservation, 1.0f );
|
||||
float a = r_forceAmbient.GetFloat( );
|
||||
|
||||
ambientColor.Set( a, a, a, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
const float lightScale = r_lightScale.GetFloat( );
|
||||
const idVec4 lightColor = colorWhite * lightScale;
|
||||
|
||||
// apply the world-global overbright and tune down specular a bit so we have less fresnel overglow
|
||||
diffuseColor = lightColor;
|
||||
specularColor = lightColor;// * 0.5f;
|
||||
|
||||
float ambientBoost = 1.0f;
|
||||
if( !r_usePBR.GetBool( ) )
|
||||
{
|
||||
ambientBoost += r_useSSAO.GetBool( ) ? 0.2f : 0.0f;
|
||||
ambientBoost *= r_useHDR.GetBool( ) ? 1.1f : 1.0f;
|
||||
}
|
||||
|
||||
ambientColor.x = r_forceAmbient.GetFloat( ) * ambientBoost;
|
||||
ambientColor.y = r_forceAmbient.GetFloat( ) * ambientBoost;
|
||||
ambientColor.z = r_forceAmbient.GetFloat( ) * ambientBoost;
|
||||
ambientColor.w = 1;
|
||||
}
|
||||
|
||||
renderProgManager.SetRenderParm( RENDERPARM_AMBIENT_COLOR, ambientColor.ToFloatPtr( ) );
|
||||
|
||||
bool useIBL = r_usePBR.GetBool( ) && !fillGbuffer;
|
||||
|
||||
// setup renderparms assuming we will be drawing trivial surfaces first
|
||||
RB_SetupForFastPathInteractions( diffuseColor, specularColor );
|
||||
|
||||
for( int i = 0; i < numDrawSurfs; i++ )
|
||||
{
|
||||
const drawSurf_t* drawSurf = drawSurfs[i];
|
||||
const idMaterial* surfaceMaterial = drawSurf->material;
|
||||
|
||||
// translucent surfaces don't put anything in the depth buffer and don't
|
||||
// test against it, which makes them fail the mirror clip plane operation
|
||||
if( surfaceMaterial->Coverage( ) == MC_TRANSLUCENT )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the expressions for conditionals / color / texcoords
|
||||
const float* surfaceRegs = drawSurf->shaderRegisters;
|
||||
|
||||
// if all stages of a material have been conditioned off, don't do anything
|
||||
int stage = 0;
|
||||
for( ; stage < surfaceMaterial->GetNumStages( ); stage++ )
|
||||
{
|
||||
const shaderStage_t* pStage = surfaceMaterial->GetStage( stage );
|
||||
// check the stage enable condition
|
||||
if( surfaceRegs[pStage->conditionRegister] != 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( stage == surfaceMaterial->GetNumStages( ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//bool isWorldModel = ( drawSurf->space->entityDef->parms.origin == vec3_origin );
|
||||
|
||||
//if( isWorldModel )
|
||||
//{
|
||||
// renderProgManager.BindShader_VertexLighting();
|
||||
//}
|
||||
//else
|
||||
{
|
||||
if( fillGbuffer )
|
||||
{
|
||||
// TODO support PBR textures and store roughness in the alpha channel
|
||||
|
||||
// fill geometry buffer with normal/roughness information
|
||||
if( drawSurf->jointCache )
|
||||
{
|
||||
renderProgManager.BindShader_SmallGeometryBufferSkinned( );
|
||||
}
|
||||
else
|
||||
{
|
||||
renderProgManager.BindShader_SmallGeometryBuffer( );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// TODO support PBR textures
|
||||
|
||||
// draw Quake 4 style ambient
|
||||
if( drawSurf->jointCache )
|
||||
{
|
||||
renderProgManager.BindShader_AmbientLightingSkinned( );
|
||||
}
|
||||
else
|
||||
{
|
||||
renderProgManager.BindShader_AmbientLighting( );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// change the matrix if needed
|
||||
if( drawSurf->space != currentSpace )
|
||||
{
|
||||
currentSpace = drawSurf->space;
|
||||
|
||||
RB_SetMVP( drawSurf->space->mvp );
|
||||
|
||||
// tranform the view origin into model local space
|
||||
idVec4 localViewOrigin( 1.0f );
|
||||
R_GlobalPointToLocal( drawSurf->space->modelMatrix, viewDef->renderView.vieworg, localViewOrigin.ToVec3( ) );
|
||||
SetVertexParm( RENDERPARM_LOCALVIEWORIGIN, localViewOrigin.ToFloatPtr( ) );
|
||||
|
||||
// RB: if we want to store the normals in world space so we need the model -> world matrix
|
||||
idRenderMatrix modelMatrix;
|
||||
idRenderMatrix::Transpose( *( idRenderMatrix* )drawSurf->space->modelMatrix, modelMatrix );
|
||||
|
||||
SetVertexParms( RENDERPARM_MODELMATRIX_X, modelMatrix[0], 4 );
|
||||
|
||||
// RB: if we want to store the normals in camera space so we need the model -> camera matrix
|
||||
float modelViewMatrixTranspose[16];
|
||||
R_MatrixTranspose( drawSurf->space->modelViewMatrix, modelViewMatrixTranspose );
|
||||
SetVertexParms( RENDERPARM_MODELVIEWMATRIX_X, modelViewMatrixTranspose, 4 );
|
||||
}
|
||||
|
||||
/*
|
||||
uint64 surfGLState = 0;
|
||||
|
||||
// set polygon offset if necessary
|
||||
if( surfaceMaterial->TestMaterialFlag( MF_POLYGONOFFSET ) )
|
||||
{
|
||||
surfGLState |= GLS_POLYGON_OFFSET;
|
||||
GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * surfaceMaterial->GetPolygonOffset() );
|
||||
}
|
||||
|
||||
// subviews will just down-modulate the color buffer
|
||||
idVec4 color;
|
||||
if( surfaceMaterial->GetSort() == SS_SUBVIEW )
|
||||
{
|
||||
surfGLState |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHFUNC_LESS;
|
||||
color[0] = 1.0f;
|
||||
color[1] = 1.0f;
|
||||
color[2] = 1.0f;
|
||||
color[3] = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// others just draw black
|
||||
#if 0
|
||||
color[0] = 0.0f;
|
||||
color[1] = 0.0f;
|
||||
color[2] = 0.0f;
|
||||
color[3] = 1.0f;
|
||||
#else
|
||||
color = colorWhite;
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
drawInteraction_t inter = {};
|
||||
inter.surf = drawSurf;
|
||||
|
||||
inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 1;
|
||||
inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0;
|
||||
|
||||
// check for the fast path
|
||||
if( surfaceMaterial->GetFastPathBumpImage( ) && !r_skipInteractionFastPath.GetBool( ) )
|
||||
{
|
||||
renderLog.OpenBlock( surfaceMaterial->GetName( ), colorMdGrey );
|
||||
|
||||
inter.bumpImage = surfaceMaterial->GetFastPathBumpImage( );
|
||||
inter.specularImage = surfaceMaterial->GetFastPathSpecularImage( );
|
||||
inter.diffuseImage = surfaceMaterial->GetFastPathDiffuseImage( );
|
||||
|
||||
DrawSingleInteraction( &inter, true, useIBL, false );
|
||||
|
||||
renderLog.CloseBlock( );
|
||||
continue;
|
||||
}
|
||||
|
||||
renderLog.OpenBlock( surfaceMaterial->GetName( ), colorMdGrey );
|
||||
|
||||
//bool drawSolid = false;
|
||||
|
||||
inter.bumpImage = NULL;
|
||||
inter.specularImage = NULL;
|
||||
inter.diffuseImage = NULL;
|
||||
|
||||
// we may have multiple alpha tested stages
|
||||
// if the only alpha tested stages are condition register omitted,
|
||||
// draw a normal opaque surface
|
||||
bool didDraw = false;
|
||||
|
||||
// perforated surfaces may have multiple alpha tested stages
|
||||
for( stage = 0; stage < surfaceMaterial->GetNumStages( ); stage++ )
|
||||
{
|
||||
const shaderStage_t* surfaceStage = surfaceMaterial->GetStage( stage );
|
||||
|
||||
switch( surfaceStage->lighting )
|
||||
{
|
||||
case SL_COVERAGE:
|
||||
{
|
||||
// ignore any coverage stages since they should only be used for the depth fill pass
|
||||
// for diffuse stages that use alpha test.
|
||||
break;
|
||||
}
|
||||
|
||||
case SL_AMBIENT:
|
||||
{
|
||||
// ignore ambient stages while drawing interactions
|
||||
break;
|
||||
}
|
||||
|
||||
case SL_BUMP:
|
||||
{
|
||||
// ignore stage that fails the condition
|
||||
if( !surfaceRegs[surfaceStage->conditionRegister] )
|
||||
{
|
||||
break;
|
||||
}
|
||||
// draw any previous interaction
|
||||
if( inter.bumpImage != NULL )
|
||||
{
|
||||
#if BLEND_NORMALS
|
||||
if( inter.vertexColor == SVC_IGNORE )
|
||||
{
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
}
|
||||
else
|
||||
{
|
||||
// RB: this is a bit hacky: use additive blending to blend the normals
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
}
|
||||
#endif
|
||||
|
||||
DrawSingleInteraction( &inter, false, useIBL, false );
|
||||
}
|
||||
inter.bumpImage = surfaceStage->texture.image;
|
||||
inter.diffuseImage = NULL;
|
||||
inter.specularImage = NULL;
|
||||
SetupInteractionStage( surfaceStage, surfaceRegs, NULL,
|
||||
inter.bumpMatrix, NULL );
|
||||
break;
|
||||
}
|
||||
|
||||
case SL_DIFFUSE:
|
||||
{
|
||||
// ignore stage that fails the condition
|
||||
if( !surfaceRegs[surfaceStage->conditionRegister] )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// draw any previous interaction
|
||||
if( inter.diffuseImage != NULL )
|
||||
{
|
||||
#if BLEND_NORMALS
|
||||
if( inter.vertexColor == SVC_IGNORE )
|
||||
{
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
}
|
||||
else
|
||||
{
|
||||
// RB: this is a bit hacky: use additive blending to blend the normals
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
}
|
||||
#endif
|
||||
|
||||
DrawSingleInteraction( &inter, false, useIBL, false );
|
||||
}
|
||||
|
||||
inter.diffuseImage = surfaceStage->texture.image;
|
||||
inter.vertexColor = surfaceStage->vertexColor;
|
||||
SetupInteractionStage( surfaceStage, surfaceRegs, diffuseColor.ToFloatPtr( ),
|
||||
inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr( ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case SL_SPECULAR:
|
||||
case SL_RMAO:
|
||||
{
|
||||
// ignore stage that fails the condition
|
||||
if( !surfaceRegs[surfaceStage->conditionRegister] )
|
||||
{
|
||||
break;
|
||||
}
|
||||
// draw any previous interaction
|
||||
if( inter.specularImage != NULL )
|
||||
{
|
||||
#if BLEND_NORMALS
|
||||
if( inter.vertexColor == SVC_IGNORE )
|
||||
{
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
}
|
||||
else
|
||||
{
|
||||
// RB: this is a bit hacky: use additive blending to blend the normals
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
}
|
||||
#endif
|
||||
|
||||
DrawSingleInteraction( &inter, false, useIBL, false );
|
||||
}
|
||||
inter.specularImage = surfaceStage->texture.image;
|
||||
inter.vertexColor = surfaceStage->vertexColor;
|
||||
SetupInteractionStage( surfaceStage, surfaceRegs, specularColor.ToFloatPtr( ),
|
||||
inter.specularMatrix, inter.specularColor.ToFloatPtr( ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw the final interaction
|
||||
#if BLEND_NORMALS
|
||||
if( inter.vertexColor == SVC_IGNORE )
|
||||
{
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
}
|
||||
else
|
||||
{
|
||||
// RB: this is a bit hacky: use additive blending to blend the normals
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
}
|
||||
#endif
|
||||
|
||||
DrawSingleInteraction( &inter, false, useIBL, false );
|
||||
|
||||
renderLog.CloseBlock( );
|
||||
}
|
||||
|
||||
// disable blending
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL );
|
||||
SetFragmentParm( RENDERPARM_ALPHA_TEST, vec4_zero.ToFloatPtr( ) );
|
||||
|
||||
GL_SelectTexture( 0 );
|
||||
|
||||
if( fillGbuffer )
|
||||
{
|
||||
// go back to main render target
|
||||
if( previousFramebuffer != NULL )
|
||||
{
|
||||
previousFramebuffer->Bind( );
|
||||
}
|
||||
else
|
||||
{
|
||||
Framebuffer::Unbind( );
|
||||
}
|
||||
}
|
||||
|
||||
renderProgManager.Unbind( );
|
||||
|
||||
renderLog.CloseBlock( );
|
||||
renderLog.CloseMainBlock( );
|
||||
}
|
||||
|
||||
nvrhi::GraphicsPipelineHandle GBufferFillPass::CreateGraphicsPipeline( nvrhi::IFramebuffer* framebuffer )
|
||||
{
|
||||
return nvrhi::GraphicsPipelineHandle( );
|
||||
}
|
||||
|
||||
void GBufferFillPass::DrawElementsWithCounters( const drawSurf_t* surf )
|
||||
{
|
||||
// Get vertex buffer
|
||||
const vertCacheHandle_t vbHandle = surf->ambientCache;
|
||||
idVertexBuffer* vertexBuffer;
|
||||
if( vertexCache.CacheIsStatic( vbHandle ) )
|
||||
{
|
||||
vertexBuffer = &vertexCache.staticData.vertexBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint64 frameNum = ( int )( vbHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
|
||||
if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
|
||||
{
|
||||
idLib::Warning( "RB_DrawElementsWithCounters, vertexBuffer == NULL" );
|
||||
return;
|
||||
}
|
||||
vertexBuffer = &vertexCache.frameData[vertexCache.drawListNum].vertexBuffer;
|
||||
}
|
||||
const uint vertOffset = ( uint )( vbHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
|
||||
auto currentVertexBuffer = vertexBuffer->GetAPIObject( );
|
||||
|
||||
// Get index buffer
|
||||
const vertCacheHandle_t ibHandle = surf->indexCache;
|
||||
idIndexBuffer* indexBuffer;
|
||||
if( vertexCache.CacheIsStatic( ibHandle ) )
|
||||
{
|
||||
indexBuffer = &vertexCache.staticData.indexBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint64 frameNum = ( int )( ibHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
|
||||
if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
|
||||
{
|
||||
idLib::Warning( "RB_DrawElementsWithCounters, indexBuffer == NULL" );
|
||||
return;
|
||||
}
|
||||
indexBuffer = &vertexCache.frameData[vertexCache.drawListNum].indexBuffer;
|
||||
}
|
||||
const uint indexOffset = ( uint )( ibHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
|
||||
|
||||
RENDERLOG_PRINTF( "Binding Buffers: %p:%i %p:%i\n", vertexBuffer, vertOffset, indexBuffer, indexOffset );
|
||||
|
||||
auto currentIndexBuffer = ( nvrhi::IBuffer* )indexBuffer->GetAPIObject( );
|
||||
|
||||
if( currentIndexBuffer != ( nvrhi::IBuffer* )indexBuffer->GetAPIObject( ) || !r_useStateCaching.GetBool( ) )
|
||||
{
|
||||
currentIndexBuffer = indexBuffer->GetAPIObject( );
|
||||
}
|
||||
|
||||
if( !pipeline )
|
||||
{
|
||||
nvrhi::GraphicsPipelineDesc psoDesc;
|
||||
psoDesc.VS = vertexShader;
|
||||
psoDesc.PS = pixelShader;
|
||||
psoDesc.inputLayout = inputLayout;
|
||||
psoDesc.bindingLayouts = { currentBindingLayout };
|
||||
psoDesc.primType = nvrhi::PrimitiveType::TriangleList;
|
||||
currentRenderState.rasterState.enableScissor( );
|
||||
psoDesc.setRenderState( currentRenderState );
|
||||
|
||||
pipeline = device->createGraphicsPipeline( psoDesc, currentFramebuffer->GetApiObject( ) );
|
||||
}
|
||||
|
||||
nvrhi::BindingSetDesc bindingSetDesc;
|
||||
|
||||
if( renderProgManager.BindingLayoutType( ) == BINDING_LAYOUT_DEFAULT )
|
||||
{
|
||||
bindingSetDesc
|
||||
.addItem( nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.ConstantBuffer( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 0, ( nvrhi::ITexture* )GetImageAt( 0 )->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 0, ( nvrhi::ISampler* )GetImageAt( 0 )->GetSampler( ) ) );
|
||||
}
|
||||
else if( renderProgManager.BindingLayoutType( ) == BINDING_LAYOUT_GBUFFER )
|
||||
{
|
||||
bindingSetDesc
|
||||
.addItem( nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.ConstantBuffer( ) ) );
|
||||
}
|
||||
else if( renderProgManager.BindingLayoutType( ) == BINDING_LAYOUT_LIGHTGRID )
|
||||
{
|
||||
bindingSetDesc
|
||||
.addItem( nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.ConstantBuffer( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 0, ( nvrhi::ITexture* )GetImageAt( 0 )->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 1, ( nvrhi::ITexture* )GetImageAt( 1 )->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 2, ( nvrhi::ITexture* )GetImageAt( 2 )->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 3, ( nvrhi::ITexture* )GetImageAt( 3 )->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 4, ( nvrhi::ITexture* )GetImageAt( 4 )->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 7, ( nvrhi::ITexture* )GetImageAt( 7 )->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 8, ( nvrhi::ITexture* )GetImageAt( 8 )->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 9, ( nvrhi::ITexture* )GetImageAt( 9 )->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Texture_SRV( 10, ( nvrhi::ITexture* )GetImageAt( 10 )->GetTextureID( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 0, ( nvrhi::ISampler* )GetImageAt( 0 )->GetSampler( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 1, ( nvrhi::ISampler* )GetImageAt( 1 )->GetSampler( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 2, ( nvrhi::ISampler* )GetImageAt( 2 )->GetSampler( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 3, ( nvrhi::ISampler* )GetImageAt( 3 )->GetSampler( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 4, ( nvrhi::ISampler* )GetImageAt( 4 )->GetSampler( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 7, ( nvrhi::ISampler* )GetImageAt( 7 )->GetSampler( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 8, ( nvrhi::ISampler* )GetImageAt( 8 )->GetSampler( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 9, ( nvrhi::ISampler* )GetImageAt( 9 )->GetSampler( ) ) )
|
||||
.addItem( nvrhi::BindingSetItem::Sampler( 10, ( nvrhi::ISampler* )GetImageAt( 10 )->GetSampler( ) ) );
|
||||
}
|
||||
|
||||
currentBindingSet = bindingCache.GetOrCreateBindingSet( bindingSetDesc, currentBindingLayout );
|
||||
|
||||
renderProgManager.CommitConstantBuffer( commandList );
|
||||
|
||||
nvrhi::GraphicsState state;
|
||||
state.bindings = { currentBindingSet };
|
||||
state.indexBuffer = { currentIndexBuffer, nvrhi::Format::R16_UINT, indexOffset };
|
||||
state.vertexBuffers = { { currentVertexBuffer, 0, vertOffset } };
|
||||
state.pipeline = currentPipeline;
|
||||
state.framebuffer = currentFrameBuffer->GetApiObject( );
|
||||
|
||||
// TODO(Stephen): use currentViewport instead.
|
||||
nvrhi::Viewport viewport;
|
||||
viewport.minX = currentViewport.x1;
|
||||
viewport.minY = currentViewport.y1;
|
||||
viewport.maxX = currentViewport.x2;
|
||||
viewport.maxY = currentViewport.y2;
|
||||
viewport.minZ = currentViewport.zmin;
|
||||
viewport.maxZ = currentViewport.zmax;
|
||||
state.viewport.addViewportAndScissorRect( viewport );
|
||||
state.viewport.addScissorRect( nvrhi::Rect( currentScissor.x1, currentScissor.y1, currentScissor.x2, currentScissor.y2 ) );
|
||||
|
||||
commandList->setGraphicsState( state );
|
||||
|
||||
nvrhi::DrawArguments args;
|
||||
args.vertexCount = surf->numIndexes;
|
||||
commandList->drawIndexed( args );
|
||||
|
||||
// RB: added stats
|
||||
pc.c_drawElements++;
|
||||
pc.c_drawIndexes += surf->numIndexes;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void GBufferFillPass::SetupView( nvrhi::ICommandList* commandList, viewDef_t* viewDef )
|
||||
{
|
||||
}
|
||||
|
||||
bool GBufferFillPass::SetupMaterial( const idMaterial* material, nvrhi::RasterCullMode cullMode, nvrhi::GraphicsState& state )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void GBufferFillPass::SetupInputBuffers( const drawSurf_t* drawSurf, nvrhi::GraphicsState& state )
|
||||
{
|
||||
}
|
||||
|
||||
void GBufferFillPass::SetPushConstants( nvrhi::ICommandList* commandList, nvrhi::GraphicsState& state, nvrhi::DrawArguments& args )
|
||||
{
|
||||
}
|
64
neo/renderer/Passes/GBufferFillPass.h
Normal file
64
neo/renderer/Passes/GBufferFillPass.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef RENDERER_PASSES_GBUFFERFILLPASS_H_
|
||||
#define RENDERER_PASSES_GBUFFERFILLPASS_H_
|
||||
|
||||
#include "GeometryPasses.h"
|
||||
|
||||
// "Light" G-Buffer that renders the normals of the geometry
|
||||
class GBufferFillPass : IGeometryPass
|
||||
{
|
||||
public:
|
||||
|
||||
GBufferFillPass( ) = default;
|
||||
virtual ~GBufferFillPass( ) = default;
|
||||
|
||||
void Init( nvrhi::DeviceHandle deviceHandle );
|
||||
void RenderView( nvrhi::ICommandList* commandList, const drawSurf_t* const* drawSurfs, int numDrawSurfs, bool fillGbuffer );
|
||||
|
||||
protected:
|
||||
|
||||
nvrhi::DeviceHandle device;
|
||||
nvrhi::BindingLayoutHandle geometryBindingLayout;
|
||||
nvrhi::BindingLayoutHandle texturedBindingLayout;
|
||||
nvrhi::BindingSetDesc geometryBindingSetDesc;
|
||||
|
||||
nvrhi::GraphicsPipelineHandle CreateGraphicsPipeline( nvrhi::IFramebuffer* framebuffer );
|
||||
|
||||
void DrawElementsWithCounters( const drawSurf_t* surf );
|
||||
|
||||
public:
|
||||
|
||||
void SetupView( nvrhi::ICommandList* commandList, viewDef_t* viewDef ) override;
|
||||
bool SetupMaterial( const idMaterial* material, nvrhi::RasterCullMode cullMode, nvrhi::GraphicsState& state ) override;
|
||||
void SetupInputBuffers( const drawSurf_t* drawSurf, nvrhi::GraphicsState& state ) override;
|
||||
void SetPushConstants( nvrhi::ICommandList* commandList, nvrhi::GraphicsState& state, nvrhi::DrawArguments& args ) override;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
804
neo/renderer/Passes/GeometryPasses.cpp
Normal file
804
neo/renderer/Passes/GeometryPasses.cpp
Normal file
|
@ -0,0 +1,804 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#include <precompiled.h>
|
||||
#pragma hdrstop
|
||||
|
||||
#include "renderer/RenderCommon.h"
|
||||
|
||||
#include "GeometryPasses.h"
|
||||
|
||||
#include "nvrhi/utils.h"
|
||||
|
||||
|
||||
static ID_INLINE void SetVertexParm( renderParm_t rp, const float* value )
|
||||
{
|
||||
renderProgManager.SetUniformValue( rp, value );
|
||||
}
|
||||
|
||||
static ID_INLINE void SetVertexParms( renderParm_t rp, const float* value, int num )
|
||||
{
|
||||
for( int i = 0; i < num; i++ )
|
||||
{
|
||||
renderProgManager.SetUniformValue( ( renderParm_t )( rp + i ), value + ( i * 4 ) );
|
||||
}
|
||||
}
|
||||
|
||||
static ID_INLINE void SetFragmentParm( renderParm_t rp, const float* value )
|
||||
{
|
||||
renderProgManager.SetUniformValue( rp, value );
|
||||
}
|
||||
|
||||
static void RB_GetShaderTextureMatrix( const float* shaderRegisters, const textureStage_t* texture, float matrix[16] )
|
||||
{
|
||||
matrix[0 * 4 + 0] = shaderRegisters[texture->matrix[0][0]];
|
||||
matrix[1 * 4 + 0] = shaderRegisters[texture->matrix[0][1]];
|
||||
matrix[2 * 4 + 0] = 0.0f;
|
||||
matrix[3 * 4 + 0] = shaderRegisters[texture->matrix[0][2]];
|
||||
|
||||
matrix[0 * 4 + 1] = shaderRegisters[texture->matrix[1][0]];
|
||||
matrix[1 * 4 + 1] = shaderRegisters[texture->matrix[1][1]];
|
||||
matrix[2 * 4 + 1] = 0.0f;
|
||||
matrix[3 * 4 + 1] = shaderRegisters[texture->matrix[1][2]];
|
||||
|
||||
// we attempt to keep scrolls from generating incredibly large texture values, but
|
||||
// center rotations and center scales can still generate offsets that need to be > 1
|
||||
if( matrix[3 * 4 + 0] < -40.0f || matrix[12] > 40.0f )
|
||||
{
|
||||
matrix[3 * 4 + 0] -= ( int )matrix[3 * 4 + 0];
|
||||
}
|
||||
if( matrix[13] < -40.0f || matrix[13] > 40.0f )
|
||||
{
|
||||
matrix[13] -= ( int )matrix[13];
|
||||
}
|
||||
|
||||
matrix[0 * 4 + 2] = 0.0f;
|
||||
matrix[1 * 4 + 2] = 0.0f;
|
||||
matrix[2 * 4 + 2] = 1.0f;
|
||||
matrix[3 * 4 + 2] = 0.0f;
|
||||
|
||||
matrix[0 * 4 + 3] = 0.0f;
|
||||
matrix[1 * 4 + 3] = 0.0f;
|
||||
matrix[2 * 4 + 3] = 0.0f;
|
||||
matrix[3 * 4 + 3] = 1.0f;
|
||||
}
|
||||
|
||||
static void RB_LoadShaderTextureMatrix( const float* shaderRegisters, const textureStage_t* texture )
|
||||
{
|
||||
float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
|
||||
float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
|
||||
|
||||
if( texture->hasMatrix )
|
||||
{
|
||||
float matrix[16];
|
||||
RB_GetShaderTextureMatrix( shaderRegisters, texture, matrix );
|
||||
texS[0] = matrix[0 * 4 + 0];
|
||||
texS[1] = matrix[1 * 4 + 0];
|
||||
texS[2] = matrix[2 * 4 + 0];
|
||||
texS[3] = matrix[3 * 4 + 0];
|
||||
|
||||
texT[0] = matrix[0 * 4 + 1];
|
||||
texT[1] = matrix[1 * 4 + 1];
|
||||
texT[2] = matrix[2 * 4 + 1];
|
||||
texT[3] = matrix[3 * 4 + 1];
|
||||
|
||||
RENDERLOG_PRINTF( "Setting Texture Matrix\n" );
|
||||
renderLog.Indent( );
|
||||
RENDERLOG_PRINTF( "Texture Matrix S : %4.3f, %4.3f, %4.3f, %4.3f\n", texS[0], texS[1], texS[2], texS[3] );
|
||||
RENDERLOG_PRINTF( "Texture Matrix T : %4.3f, %4.3f, %4.3f, %4.3f\n", texT[0], texT[1], texT[2], texT[3] );
|
||||
renderLog.Outdent( );
|
||||
}
|
||||
|
||||
SetVertexParm( RENDERPARM_TEXTUREMATRIX_S, texS );
|
||||
SetVertexParm( RENDERPARM_TEXTUREMATRIX_T, texT );
|
||||
}
|
||||
|
||||
void IGeometryPass::PrepareStageTexturing( const shaderStage_t* pStage, const drawSurf_t* surf )
|
||||
{
|
||||
float useTexGenParm[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
// set the texture matrix if needed
|
||||
RB_LoadShaderTextureMatrix( surf->shaderRegisters, &pStage->texture );
|
||||
|
||||
// texgens
|
||||
if( pStage->texture.texgen == TG_REFLECT_CUBE )
|
||||
{
|
||||
|
||||
// see if there is also a bump map specified
|
||||
const shaderStage_t* bumpStage = surf->material->GetBumpStage( );
|
||||
if( bumpStage != NULL )
|
||||
{
|
||||
// per-pixel reflection mapping with bump mapping
|
||||
GL_SelectTexture( 1 );
|
||||
bumpStage->texture.image->Bind( );
|
||||
|
||||
GL_SelectTexture( 0 );
|
||||
|
||||
RENDERLOG_PRINTF( "TexGen: TG_REFLECT_CUBE: Bumpy Environment\n" );
|
||||
if( surf->jointCache )
|
||||
{
|
||||
renderProgManager.BindShader_BumpyEnvironmentSkinned( );
|
||||
}
|
||||
else
|
||||
{
|
||||
renderProgManager.BindShader_BumpyEnvironment( );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RENDERLOG_PRINTF( "TexGen: TG_REFLECT_CUBE: Environment\n" );
|
||||
if( surf->jointCache )
|
||||
{
|
||||
renderProgManager.BindShader_EnvironmentSkinned( );
|
||||
}
|
||||
else
|
||||
{
|
||||
renderProgManager.BindShader_Environment( );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if( pStage->texture.texgen == TG_SKYBOX_CUBE )
|
||||
{
|
||||
renderProgManager.BindShader_SkyBox( );
|
||||
}
|
||||
else if( pStage->texture.texgen == TG_WOBBLESKY_CUBE )
|
||||
{
|
||||
|
||||
const int* parms = surf->material->GetTexGenRegisters( );
|
||||
|
||||
float wobbleDegrees = surf->shaderRegisters[parms[0]] * ( idMath::PI / 180.0f );
|
||||
float wobbleSpeed = surf->shaderRegisters[parms[1]] * ( 2.0f * idMath::PI / 60.0f );
|
||||
float rotateSpeed = surf->shaderRegisters[parms[2]] * ( 2.0f * idMath::PI / 60.0f );
|
||||
|
||||
idVec3 axis[3];
|
||||
{
|
||||
// very ad-hoc "wobble" transform
|
||||
float s, c;
|
||||
idMath::SinCos( wobbleSpeed * viewDef->renderView.time[0] * 0.001f, s, c );
|
||||
|
||||
float ws, wc;
|
||||
idMath::SinCos( wobbleDegrees, ws, wc );
|
||||
|
||||
axis[2][0] = ws * c;
|
||||
axis[2][1] = ws * s;
|
||||
axis[2][2] = wc;
|
||||
|
||||
axis[1][0] = -s * s * ws;
|
||||
axis[1][2] = -s * ws * ws;
|
||||
axis[1][1] = idMath::Sqrt( idMath::Fabs( 1.0f - ( axis[1][0] * axis[1][0] + axis[1][2] * axis[1][2] ) ) );
|
||||
|
||||
// make the second vector exactly perpendicular to the first
|
||||
axis[1] -= ( axis[2] * axis[1] ) * axis[2];
|
||||
axis[1].Normalize( );
|
||||
|
||||
// construct the third with a cross
|
||||
axis[0].Cross( axis[1], axis[2] );
|
||||
}
|
||||
|
||||
// add the rotate
|
||||
float rs, rc;
|
||||
idMath::SinCos( rotateSpeed * viewDef->renderView.time[0] * 0.001f, rs, rc );
|
||||
|
||||
float transform[12];
|
||||
transform[0 * 4 + 0] = axis[0][0] * rc + axis[1][0] * rs;
|
||||
transform[0 * 4 + 1] = axis[0][1] * rc + axis[1][1] * rs;
|
||||
transform[0 * 4 + 2] = axis[0][2] * rc + axis[1][2] * rs;
|
||||
transform[0 * 4 + 3] = 0.0f;
|
||||
|
||||
transform[1 * 4 + 0] = axis[1][0] * rc - axis[0][0] * rs;
|
||||
transform[1 * 4 + 1] = axis[1][1] * rc - axis[0][1] * rs;
|
||||
transform[1 * 4 + 2] = axis[1][2] * rc - axis[0][2] * rs;
|
||||
transform[1 * 4 + 3] = 0.0f;
|
||||
|
||||
transform[2 * 4 + 0] = axis[2][0];
|
||||
transform[2 * 4 + 1] = axis[2][1];
|
||||
transform[2 * 4 + 2] = axis[2][2];
|
||||
transform[2 * 4 + 3] = 0.0f;
|
||||
|
||||
SetVertexParms( RENDERPARM_WOBBLESKY_X, transform, 3 );
|
||||
renderProgManager.BindShader_WobbleSky( );
|
||||
|
||||
}
|
||||
else if( ( pStage->texture.texgen == TG_SCREEN ) || ( pStage->texture.texgen == TG_SCREEN2 ) )
|
||||
{
|
||||
|
||||
useTexGenParm[0] = 1.0f;
|
||||
useTexGenParm[1] = 1.0f;
|
||||
useTexGenParm[2] = 1.0f;
|
||||
useTexGenParm[3] = 1.0f;
|
||||
|
||||
float mat[16];
|
||||
R_MatrixMultiply( surf->space->modelViewMatrix, viewDef->projectionMatrix, mat );
|
||||
|
||||
RENDERLOG_PRINTF( "TexGen : %s\n", ( pStage->texture.texgen == TG_SCREEN ) ? "TG_SCREEN" : "TG_SCREEN2" );
|
||||
renderLog.Indent( );
|
||||
|
||||
float plane[4];
|
||||
plane[0] = mat[0 * 4 + 0];
|
||||
plane[1] = mat[1 * 4 + 0];
|
||||
plane[2] = mat[2 * 4 + 0];
|
||||
plane[3] = mat[3 * 4 + 0];
|
||||
SetVertexParm( RENDERPARM_TEXGEN_0_S, plane );
|
||||
RENDERLOG_PRINTF( "TEXGEN_S = %4.3f, %4.3f, %4.3f, %4.3f\n", plane[0], plane[1], plane[2], plane[3] );
|
||||
|
||||
plane[0] = mat[0 * 4 + 1];
|
||||
plane[1] = mat[1 * 4 + 1];
|
||||
plane[2] = mat[2 * 4 + 1];
|
||||
plane[3] = mat[3 * 4 + 1];
|
||||
SetVertexParm( RENDERPARM_TEXGEN_0_T, plane );
|
||||
RENDERLOG_PRINTF( "TEXGEN_T = %4.3f, %4.3f, %4.3f, %4.3f\n", plane[0], plane[1], plane[2], plane[3] );
|
||||
|
||||
plane[0] = mat[0 * 4 + 3];
|
||||
plane[1] = mat[1 * 4 + 3];
|
||||
plane[2] = mat[2 * 4 + 3];
|
||||
plane[3] = mat[3 * 4 + 3];
|
||||
SetVertexParm( RENDERPARM_TEXGEN_0_Q, plane );
|
||||
RENDERLOG_PRINTF( "TEXGEN_Q = %4.3f, %4.3f, %4.3f, %4.3f\n", plane[0], plane[1], plane[2], plane[3] );
|
||||
|
||||
renderLog.Outdent( );
|
||||
|
||||
}
|
||||
else if( pStage->texture.texgen == TG_DIFFUSE_CUBE )
|
||||
{
|
||||
// As far as I can tell, this is never used
|
||||
idLib::Warning( "Using Diffuse Cube! Please contact Brian!" );
|
||||
|
||||
}
|
||||
else if( pStage->texture.texgen == TG_GLASSWARP )
|
||||
{
|
||||
// As far as I can tell, this is never used
|
||||
idLib::Warning( "Using GlassWarp! Please contact Brian!" );
|
||||
}
|
||||
|
||||
SetVertexParm( RENDERPARM_TEXGEN_0_ENABLED, useTexGenParm );
|
||||
}
|
||||
|
||||
void IGeometryPass::FinishStageTexturing( const shaderStage_t* stage, const drawSurf_t* surf )
|
||||
{
|
||||
if( stage->texture.cinematic )
|
||||
{
|
||||
// unbind the extra bink textures
|
||||
GL_SelectTexture( 0 );
|
||||
}
|
||||
|
||||
if( stage->texture.texgen == TG_REFLECT_CUBE )
|
||||
{
|
||||
// see if there is also a bump map specified
|
||||
const shaderStage_t* bumpStage = surf->material->GetBumpStage( );
|
||||
if( bumpStage != NULL )
|
||||
{
|
||||
// per-pixel reflection mapping with bump mapping
|
||||
GL_SelectTexture( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// per-pixel reflection mapping without bump mapping
|
||||
}
|
||||
renderProgManager.Unbind( );
|
||||
}
|
||||
}
|
||||
|
||||
bool IGeometryPass::GL_State( uint64 stateBits, bool forceGlState )
|
||||
{
|
||||
uint64 diff = stateBits ^ glStateBits;
|
||||
|
||||
if( !r_useStateCaching.GetBool( ) || forceGlState )
|
||||
{
|
||||
// make sure everything is set all the time, so we
|
||||
// can see if our delta checking is screwing up
|
||||
diff = 0xFFFFFFFFFFFFFFFF;
|
||||
}
|
||||
else if( diff == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset pipeline
|
||||
auto& currentBlendState = pipelineDesc.renderState.blendState;
|
||||
auto& currentDepthStencilState = pipelineDesc.renderState.depthStencilState;
|
||||
auto& currentRasterState = pipelineDesc.renderState.rasterState;
|
||||
|
||||
//
|
||||
// culling
|
||||
//
|
||||
if( diff & ( GLS_CULL_BITS ) )//| GLS_MIRROR_VIEW ) )
|
||||
{
|
||||
switch( stateBits & GLS_CULL_BITS )
|
||||
{
|
||||
case GLS_CULL_TWOSIDED:
|
||||
currentRasterState.setCullNone( );
|
||||
break;
|
||||
|
||||
case GLS_CULL_BACKSIDED:
|
||||
if( viewDef != NULL && viewDef->isMirror )
|
||||
{
|
||||
stateBits |= GLS_MIRROR_VIEW;
|
||||
currentRasterState.setCullFront( );
|
||||
}
|
||||
else
|
||||
{
|
||||
currentRasterState.setCullBack( );
|
||||
}
|
||||
break;
|
||||
|
||||
case GLS_CULL_FRONTSIDED:
|
||||
default:
|
||||
if( viewDef != NULL && viewDef->isMirror )
|
||||
{
|
||||
stateBits |= GLS_MIRROR_VIEW;
|
||||
currentRasterState.setCullBack( );
|
||||
}
|
||||
else
|
||||
{
|
||||
currentRasterState.setCullFront( );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// check depthFunc bits
|
||||
//
|
||||
if( diff & GLS_DEPTHFUNC_BITS )
|
||||
{
|
||||
switch( stateBits & GLS_DEPTHFUNC_BITS )
|
||||
{
|
||||
case GLS_DEPTHFUNC_EQUAL:
|
||||
currentDepthStencilState.depthFunc = nvrhi::ComparisonFunc::Equal;
|
||||
break;
|
||||
case GLS_DEPTHFUNC_ALWAYS:
|
||||
currentDepthStencilState.depthFunc = nvrhi::ComparisonFunc::Always;
|
||||
break;
|
||||
case GLS_DEPTHFUNC_LESS:
|
||||
currentDepthStencilState.depthFunc = nvrhi::ComparisonFunc::Less;
|
||||
break;
|
||||
case GLS_DEPTHFUNC_GREATER:
|
||||
currentDepthStencilState.depthFunc = nvrhi::ComparisonFunc::Greater;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nvrhi::BlendState::RenderTarget renderTarget;
|
||||
|
||||
//
|
||||
// check blend bits
|
||||
//
|
||||
if( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
|
||||
{
|
||||
nvrhi::BlendFactor srcFactor = nvrhi::BlendFactor::One;
|
||||
nvrhi::BlendFactor dstFactor = nvrhi::BlendFactor::One;
|
||||
|
||||
switch( stateBits & GLS_SRCBLEND_BITS )
|
||||
{
|
||||
case GLS_SRCBLEND_ZERO:
|
||||
srcFactor = nvrhi::BlendFactor::Zero;
|
||||
break;
|
||||
case GLS_SRCBLEND_ONE:
|
||||
srcFactor = nvrhi::BlendFactor::One;
|
||||
break;
|
||||
case GLS_SRCBLEND_DST_COLOR:
|
||||
srcFactor = nvrhi::BlendFactor::DstColor;
|
||||
break;
|
||||
case GLS_SRCBLEND_ONE_MINUS_DST_COLOR:
|
||||
srcFactor = nvrhi::BlendFactor::OneMinusDstColor;
|
||||
break;
|
||||
case GLS_SRCBLEND_SRC_ALPHA:
|
||||
srcFactor = nvrhi::BlendFactor::SrcAlpha;
|
||||
break;
|
||||
case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:
|
||||
srcFactor = nvrhi::BlendFactor::OneMinusSrcAlpha;
|
||||
break;
|
||||
case GLS_SRCBLEND_DST_ALPHA:
|
||||
srcFactor = nvrhi::BlendFactor::DstAlpha;
|
||||
break;
|
||||
case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:
|
||||
srcFactor = nvrhi::BlendFactor::OneMinusDstAlpha;
|
||||
break;
|
||||
default:
|
||||
assert( !"GL_State: invalid src blend state bits\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
switch( stateBits & GLS_DSTBLEND_BITS )
|
||||
{
|
||||
case GLS_DSTBLEND_ZERO:
|
||||
dstFactor = nvrhi::BlendFactor::Zero;
|
||||
break;
|
||||
case GLS_DSTBLEND_ONE:
|
||||
dstFactor = nvrhi::BlendFactor::One;
|
||||
break;
|
||||
case GLS_DSTBLEND_SRC_COLOR:
|
||||
dstFactor = nvrhi::BlendFactor::SrcColor;
|
||||
break;
|
||||
case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:
|
||||
dstFactor = nvrhi::BlendFactor::OneMinusSrcColor;
|
||||
break;
|
||||
case GLS_DSTBLEND_SRC_ALPHA:
|
||||
dstFactor = nvrhi::BlendFactor::SrcAlpha;
|
||||
break;
|
||||
case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:
|
||||
dstFactor = nvrhi::BlendFactor::OneMinusSrcAlpha;
|
||||
break;
|
||||
case GLS_DSTBLEND_DST_ALPHA:
|
||||
dstFactor = nvrhi::BlendFactor::DstAlpha;
|
||||
break;
|
||||
case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:
|
||||
dstFactor = nvrhi::BlendFactor::OneMinusDstAlpha;
|
||||
break;
|
||||
default:
|
||||
assert( !"GL_State: invalid dst blend state bits\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
// Only actually update GL's blend func if blending is enabled.
|
||||
if( srcFactor == nvrhi::BlendFactor::One && dstFactor == nvrhi::BlendFactor::Zero )
|
||||
{
|
||||
renderTarget.disableBlend( );
|
||||
}
|
||||
else
|
||||
{
|
||||
currentBlendState.setAlphaToCoverageEnable( true );
|
||||
nvrhi::BlendState::RenderTarget renderTarget;
|
||||
renderTarget.enableBlend( );
|
||||
renderTarget.setSrcBlend( srcFactor );
|
||||
renderTarget.setDestBlend( dstFactor );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// check depthmask
|
||||
//
|
||||
if( diff & GLS_DEPTHMASK )
|
||||
{
|
||||
if( stateBits & GLS_DEPTHMASK )
|
||||
{
|
||||
currentDepthStencilState.disableDepthWrite( );
|
||||
currentDepthStencilState.disableDepthTest( );
|
||||
}
|
||||
else
|
||||
{
|
||||
currentDepthStencilState.enableDepthWrite( );
|
||||
currentDepthStencilState.enableDepthTest( );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// check colormask
|
||||
//
|
||||
if( diff & ( GLS_REDMASK | GLS_GREENMASK | GLS_BLUEMASK | GLS_ALPHAMASK ) )
|
||||
{
|
||||
nvrhi::ColorMask mask{ nvrhi::ColorMask::All };
|
||||
|
||||
if( stateBits & GLS_REDMASK )
|
||||
{
|
||||
mask = mask & ~nvrhi::ColorMask::Red;
|
||||
}
|
||||
if( stateBits & GLS_GREENMASK )
|
||||
{
|
||||
mask = mask & ~nvrhi::ColorMask::Green;
|
||||
}
|
||||
if( stateBits & GLS_BLUEMASK )
|
||||
{
|
||||
mask = mask & ~nvrhi::ColorMask::Blue;
|
||||
}
|
||||
if( stateBits & GLS_ALPHAMASK )
|
||||
{
|
||||
mask = mask & ~nvrhi::ColorMask::Alpha;
|
||||
}
|
||||
|
||||
renderTarget.setColorWriteMask( mask );
|
||||
}
|
||||
|
||||
currentBlendState.setRenderTarget( 0, renderTarget );
|
||||
|
||||
//
|
||||
// fill/line mode
|
||||
//
|
||||
if( diff & GLS_POLYMODE_LINE )
|
||||
{
|
||||
if( stateBits & GLS_POLYMODE_LINE )
|
||||
{
|
||||
currentRasterState.setFillMode( nvrhi::RasterFillMode::Line );
|
||||
currentRasterState.setCullNone( );
|
||||
}
|
||||
else
|
||||
{
|
||||
currentRasterState.setCullNone( );
|
||||
currentRasterState.setFillMode( nvrhi::RasterFillMode::Fill );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// polygon offset
|
||||
//
|
||||
if( diff & GLS_POLYGON_OFFSET )
|
||||
{
|
||||
if( stateBits & GLS_POLYGON_OFFSET )
|
||||
{
|
||||
currentRasterState.enableQuadFill( );
|
||||
}
|
||||
else
|
||||
{
|
||||
currentRasterState.disableQuadFill( );
|
||||
}
|
||||
}
|
||||
|
||||
nvrhi::DepthStencilState::StencilOpDesc stencilOp;
|
||||
|
||||
//
|
||||
// stencil
|
||||
//
|
||||
if( diff & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) )
|
||||
{
|
||||
if( ( stateBits & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) ) != 0 )
|
||||
{
|
||||
currentDepthStencilState.enableStencil( );
|
||||
currentDepthStencilState.enableDepthWrite( );
|
||||
}
|
||||
else
|
||||
{
|
||||
currentDepthStencilState.disableStencil( );
|
||||
//currentDepthStencilState.disableDepthWrite( );
|
||||
}
|
||||
}
|
||||
if( diff & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_FUNC_REF_BITS | GLS_STENCIL_FUNC_MASK_BITS ) )
|
||||
{
|
||||
GLuint ref = GLuint( ( stateBits & GLS_STENCIL_FUNC_REF_BITS ) >> GLS_STENCIL_FUNC_REF_SHIFT );
|
||||
GLuint mask = GLuint( ( stateBits & GLS_STENCIL_FUNC_MASK_BITS ) >> GLS_STENCIL_FUNC_MASK_SHIFT );
|
||||
GLenum func = 0;
|
||||
|
||||
currentDepthStencilState.setStencilRefValue( ( stateBits & GLS_STENCIL_FUNC_REF_BITS ) >> GLS_STENCIL_FUNC_REF_SHIFT );
|
||||
currentDepthStencilState.setStencilReadMask( ( stateBits & GLS_STENCIL_FUNC_MASK_BITS ) >> GLS_STENCIL_FUNC_MASK_SHIFT );
|
||||
currentDepthStencilState.setStencilWriteMask( ( stateBits & GLS_STENCIL_FUNC_MASK_BITS ) >> GLS_STENCIL_FUNC_MASK_SHIFT );
|
||||
|
||||
switch( stateBits & GLS_STENCIL_FUNC_BITS )
|
||||
{
|
||||
case GLS_STENCIL_FUNC_NEVER:
|
||||
stencilOp.setStencilFunc( nvrhi::ComparisonFunc::Never );
|
||||
break;
|
||||
case GLS_STENCIL_FUNC_LESS:
|
||||
stencilOp.setStencilFunc( nvrhi::ComparisonFunc::Less );
|
||||
break;
|
||||
case GLS_STENCIL_FUNC_EQUAL:
|
||||
stencilOp.setStencilFunc( nvrhi::ComparisonFunc::Equal );
|
||||
break;
|
||||
case GLS_STENCIL_FUNC_LEQUAL:
|
||||
stencilOp.setStencilFunc( nvrhi::ComparisonFunc::LessOrEqual );
|
||||
break;
|
||||
case GLS_STENCIL_FUNC_GREATER:
|
||||
stencilOp.setStencilFunc( nvrhi::ComparisonFunc::Greater );
|
||||
break;
|
||||
case GLS_STENCIL_FUNC_NOTEQUAL:
|
||||
stencilOp.setStencilFunc( nvrhi::ComparisonFunc::NotEqual );
|
||||
break;
|
||||
case GLS_STENCIL_FUNC_GEQUAL:
|
||||
stencilOp.setStencilFunc( nvrhi::ComparisonFunc::GreaterOrEqual );
|
||||
break;
|
||||
case GLS_STENCIL_FUNC_ALWAYS:
|
||||
stencilOp.setStencilFunc( nvrhi::ComparisonFunc::Always );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( diff & ( GLS_STENCIL_OP_FAIL_BITS | GLS_STENCIL_OP_ZFAIL_BITS | GLS_STENCIL_OP_PASS_BITS ) )
|
||||
{
|
||||
GLenum sFail = 0;
|
||||
GLenum zFail = 0;
|
||||
GLenum pass = 0;
|
||||
|
||||
switch( stateBits & GLS_STENCIL_OP_FAIL_BITS )
|
||||
{
|
||||
case GLS_STENCIL_OP_FAIL_KEEP:
|
||||
stencilOp.setFailOp( nvrhi::StencilOp::Keep );
|
||||
break;
|
||||
case GLS_STENCIL_OP_FAIL_ZERO:
|
||||
stencilOp.setFailOp( nvrhi::StencilOp::Zero );
|
||||
break;
|
||||
case GLS_STENCIL_OP_FAIL_REPLACE:
|
||||
stencilOp.setFailOp( nvrhi::StencilOp::Replace );
|
||||
break;
|
||||
case GLS_STENCIL_OP_FAIL_INCR:
|
||||
stencilOp.setFailOp( nvrhi::StencilOp::IncrementAndClamp );
|
||||
break;
|
||||
case GLS_STENCIL_OP_FAIL_DECR:
|
||||
stencilOp.setFailOp( nvrhi::StencilOp::DecrementAndClamp );
|
||||
break;
|
||||
case GLS_STENCIL_OP_FAIL_INVERT:
|
||||
stencilOp.setFailOp( nvrhi::StencilOp::Invert );
|
||||
break;
|
||||
case GLS_STENCIL_OP_FAIL_INCR_WRAP:
|
||||
stencilOp.setFailOp( nvrhi::StencilOp::IncrementAndWrap );
|
||||
break;
|
||||
case GLS_STENCIL_OP_FAIL_DECR_WRAP:
|
||||
stencilOp.setFailOp( nvrhi::StencilOp::DecrementAndWrap );
|
||||
break;
|
||||
}
|
||||
switch( stateBits & GLS_STENCIL_OP_ZFAIL_BITS )
|
||||
{
|
||||
case GLS_STENCIL_OP_ZFAIL_KEEP:
|
||||
stencilOp.setDepthFailOp( nvrhi::StencilOp::Keep );
|
||||
break;
|
||||
case GLS_STENCIL_OP_ZFAIL_ZERO:
|
||||
stencilOp.setDepthFailOp( nvrhi::StencilOp::Zero );
|
||||
break;
|
||||
case GLS_STENCIL_OP_ZFAIL_REPLACE:
|
||||
stencilOp.setDepthFailOp( nvrhi::StencilOp::Replace );
|
||||
break;
|
||||
case GLS_STENCIL_OP_ZFAIL_INCR:
|
||||
stencilOp.setDepthFailOp( nvrhi::StencilOp::IncrementAndClamp );
|
||||
break;
|
||||
case GLS_STENCIL_OP_ZFAIL_DECR:
|
||||
stencilOp.setDepthFailOp( nvrhi::StencilOp::DecrementAndClamp );
|
||||
break;
|
||||
case GLS_STENCIL_OP_ZFAIL_INVERT:
|
||||
stencilOp.setDepthFailOp( nvrhi::StencilOp::Invert );
|
||||
break;
|
||||
case GLS_STENCIL_OP_ZFAIL_INCR_WRAP:
|
||||
stencilOp.setDepthFailOp( nvrhi::StencilOp::IncrementAndWrap );
|
||||
break;
|
||||
case GLS_STENCIL_OP_ZFAIL_DECR_WRAP:
|
||||
stencilOp.setDepthFailOp( nvrhi::StencilOp::DecrementAndWrap );
|
||||
break;
|
||||
}
|
||||
switch( stateBits & GLS_STENCIL_OP_PASS_BITS )
|
||||
{
|
||||
case GLS_STENCIL_OP_PASS_KEEP:
|
||||
stencilOp.setPassOp( nvrhi::StencilOp::Keep );
|
||||
break;
|
||||
case GLS_STENCIL_OP_PASS_ZERO:
|
||||
stencilOp.setPassOp( nvrhi::StencilOp::Zero );
|
||||
break;
|
||||
case GLS_STENCIL_OP_PASS_REPLACE:
|
||||
stencilOp.setPassOp( nvrhi::StencilOp::Replace );
|
||||
break;
|
||||
case GLS_STENCIL_OP_PASS_INCR:
|
||||
stencilOp.setPassOp( nvrhi::StencilOp::IncrementAndClamp );
|
||||
break;
|
||||
case GLS_STENCIL_OP_PASS_DECR:
|
||||
stencilOp.setPassOp( nvrhi::StencilOp::DecrementAndClamp );
|
||||
break;
|
||||
case GLS_STENCIL_OP_PASS_INVERT:
|
||||
stencilOp.setPassOp( nvrhi::StencilOp::Invert );
|
||||
break;
|
||||
case GLS_STENCIL_OP_PASS_INCR_WRAP:
|
||||
stencilOp.setPassOp( nvrhi::StencilOp::IncrementAndWrap );
|
||||
break;
|
||||
case GLS_STENCIL_OP_PASS_DECR_WRAP:
|
||||
stencilOp.setPassOp( nvrhi::StencilOp::DecrementAndWrap );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
currentDepthStencilState.setFrontFaceStencil( stencilOp );
|
||||
|
||||
glStateBits = stateBits;
|
||||
pipeline = nullptr;
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_SelectTexture( int imageParm )
|
||||
{
|
||||
currentImageParm = imageParm;
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_BindTexture( idImage* img )
|
||||
{
|
||||
imageParms[currentImageParm] = img;
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_BindFramebuffer( Framebuffer* framebuffer )
|
||||
{
|
||||
if( currentFramebuffer != framebuffer )
|
||||
{
|
||||
previousFramebuffer = currentFramebuffer;
|
||||
pipeline = nullptr;
|
||||
}
|
||||
currentFramebuffer = framebuffer;
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_BindGraphicsShader( int shaderIndex )
|
||||
{
|
||||
nvrhi::ShaderHandle shader = renderProgManager.GetShader( shaderIndex );
|
||||
if( shader->getDesc( ).shaderType == nvrhi::ShaderType::Vertex )
|
||||
{
|
||||
if( pipelineDesc.VS != shader )
|
||||
{
|
||||
pipeline = nullptr;
|
||||
}
|
||||
|
||||
pipelineDesc.setVertexShader( shader );
|
||||
}
|
||||
|
||||
if( shader->getDesc( ).shaderType == nvrhi::ShaderType::Pixel )
|
||||
{
|
||||
if( pipelineDesc.PS != shader )
|
||||
{
|
||||
pipeline = nullptr;
|
||||
}
|
||||
|
||||
pipelineDesc.setPixelShader( shader );
|
||||
}
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_DepthBoundsTest( const float zmin, const float zmax )
|
||||
{
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_PolygonOffset( float scale, float bias )
|
||||
{
|
||||
pipelineDesc.renderState.rasterState.setSlopeScaleDepthBias( scale ).setDepthBias( bias );
|
||||
pipeline = nullptr;
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_Viewport( int x, int y, int w, int h )
|
||||
{
|
||||
currentViewport.Clear( );
|
||||
currentViewport.AddPoint( x, y );
|
||||
currentViewport.AddPoint( x + w, y + h );
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_Scissor( int x, int y, int w, int h )
|
||||
{
|
||||
currentScissor.Clear( );
|
||||
currentScissor.AddPoint( x, y );
|
||||
currentScissor.AddPoint( x + w, y + h );
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_Color( const idVec4 color )
|
||||
{
|
||||
// TODO(Stephen): Hold local copy and then set in a constant buffer later.
|
||||
float parm[4];
|
||||
parm[0] = idMath::ClampFloat( 0.0f, 1.0f, color.x );
|
||||
parm[1] = idMath::ClampFloat( 0.0f, 1.0f, color.y );
|
||||
parm[2] = idMath::ClampFloat( 0.0f, 1.0f, color.z );
|
||||
parm[3] = idMath::ClampFloat( 0.0f, 1.0f, color.w );
|
||||
renderProgManager.SetRenderParm( RENDERPARM_COLOR, parm );
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_ClearColor( const idVec4 color )
|
||||
{
|
||||
clearColor = color;
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_ClearDepthStencilValue( float depthValue, byte stencilValue )
|
||||
{
|
||||
depthClearValue = depthValue;
|
||||
stencilClearValue = stencilValue;
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_ClearColor( nvrhi::ICommandList* commandList, int attachmentIndex )
|
||||
{
|
||||
nvrhi::utils::ClearColorAttachment(
|
||||
commandList,
|
||||
currentFramebuffer->GetApiObject( ),
|
||||
attachmentIndex,
|
||||
nvrhi::Color( clearColor.x, clearColor.y, clearColor.z, clearColor.w ) );
|
||||
}
|
||||
|
||||
void IGeometryPass::GL_ClearDepthStencil( nvrhi::ICommandList* commandList )
|
||||
{
|
||||
nvrhi::utils::ClearDepthStencilAttachment( commandList, currentFramebuffer->GetApiObject( ), depthClearValue, stencilClearValue );
|
||||
}
|
95
neo/renderer/Passes/GeometryPasses.h
Normal file
95
neo/renderer/Passes/GeometryPasses.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef RENDERER_PASSES_GEOMETRYPASSES_H_
|
||||
#define RENDERER_PASSES_GEOMETRYPASSES_H_
|
||||
|
||||
constexpr std::size_t MAX_IMAGE_PARMS = 16;
|
||||
|
||||
class IGeometryPass
|
||||
{
|
||||
public:
|
||||
virtual ~IGeometryPass( ) = default;
|
||||
|
||||
virtual void SetupView( nvrhi::ICommandList* commandList, viewDef_t* viewDef ) = 0;
|
||||
virtual bool SetupMaterial( const idMaterial* material, nvrhi::RasterCullMode cullMode, nvrhi::GraphicsState& state ) = 0;
|
||||
virtual void SetupInputBuffers( const drawSurf_t* drawSurf, nvrhi::GraphicsState& state ) = 0;
|
||||
virtual void SetPushConstants( nvrhi::ICommandList* commandList, nvrhi::GraphicsState& state, nvrhi::DrawArguments& args ) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
void PrepareStageTexturing( const shaderStage_t* stage, const drawSurf_t* surf );
|
||||
void FinishStageTexturing( const shaderStage_t* stage, const drawSurf_t* surf );
|
||||
|
||||
protected:
|
||||
|
||||
int currentImageParm = 0;
|
||||
idArray< idImage*, MAX_IMAGE_PARMS > imageParms;
|
||||
uint64 glStateBits;
|
||||
nvrhi::GraphicsPipelineDesc pipelineDesc;
|
||||
nvrhi::GraphicsPipelineHandle pipeline;
|
||||
BindingCache bindingCache;
|
||||
Framebuffer* previousFramebuffer;
|
||||
Framebuffer* currentFramebuffer;
|
||||
const viewDef_t* viewDef;
|
||||
const viewEntity_t* currentSpace;
|
||||
idScreenRect currentViewport;
|
||||
idScreenRect currentScissor;
|
||||
idVec4 clearColor;
|
||||
float depthClearValue;
|
||||
byte stencilClearValue;
|
||||
|
||||
// Updates state to bits in stateBits. Only updates the different bits.
|
||||
bool GL_State( uint64 stateBits, bool forceGlState = false );
|
||||
void GL_SelectTexture( int textureNum );
|
||||
void GL_BindTexture( idImage* img );
|
||||
void GL_BindFramebuffer( Framebuffer* framebuffer );
|
||||
void GL_BindGraphicsShader( int shader );
|
||||
void GL_DepthBoundsTest( const float zmin, const float zmax );
|
||||
void GL_PolygonOffset( float scale, float bias );
|
||||
void GL_Viewport( int x, int y, int w, int h );
|
||||
void GL_Scissor( int x, int y, int w, int h );
|
||||
void GL_Color( const idVec4 color );
|
||||
void GL_ClearColor( const idVec4 color );
|
||||
void GL_ClearDepthStencilValue( float depthValue, byte stencilValue = 0xF );
|
||||
void GL_ClearColor( nvrhi::ICommandList* commandList, int attachmentIndex = 0 );
|
||||
void GL_ClearDepthStencil( nvrhi::ICommandList* commandList );
|
||||
|
||||
ID_INLINE uint64 GL_GetCurrentState( ) const
|
||||
{
|
||||
return glStateBits;
|
||||
}
|
||||
|
||||
ID_INLINE void GL_ViewportAndScissor( int x, int y, int w, int h )
|
||||
{
|
||||
GL_Viewport( x, y, w, h );
|
||||
GL_Scissor( x, y, w, h );
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
278
neo/renderer/Passes/MipMapGenPass.cpp
Normal file
278
neo/renderer/Passes/MipMapGenPass.cpp
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "renderer/Passes/MipMapGenPass.h"
|
||||
|
||||
#include "renderer/RenderCommon.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
|
||||
#define GROUP_SIZE 16
|
||||
#define LOD0_TILE_SIZE 8
|
||||
#define NUM_LODS 4
|
||||
|
||||
// Number of compute dispatches needed to reduce all the
|
||||
// mip-levels at a maximum resolution of 16k :
|
||||
// (uint)(std::ceil(std::log2f(16384)/NUM_LODS)) = 4
|
||||
#define MAX_PASSES 4
|
||||
|
||||
#define MODE_COLOR 0
|
||||
#define MODE_MIN 1
|
||||
#define MODE_MAX 2
|
||||
#define MODE_MINMAX 3
|
||||
|
||||
struct MipmmapGenConstants
|
||||
{
|
||||
uint dispatch;
|
||||
uint numLODs;
|
||||
uint padding[2];
|
||||
};
|
||||
|
||||
// The compute shader reduces 'NUM_LODS' mip-levels at a time into an
|
||||
// array of NUM_LODS bound UAVs. For textures that have a number
|
||||
// of mip levels that is not a multiple of NUM_LODS, we need to bind
|
||||
// "something" to the UAV slots : a set of static dummy NullTextures.
|
||||
//
|
||||
// The set of NullTextures is shared by all the MipMapGen compute pass
|
||||
// instances and ownership is thread-safe.
|
||||
//
|
||||
|
||||
static nvrhi::TextureHandle createNullTexture( nvrhi::DeviceHandle device )
|
||||
{
|
||||
nvrhi::TextureDesc desc;
|
||||
desc.width = 1;
|
||||
desc.height = 1;
|
||||
desc.isRenderTarget = false;
|
||||
desc.useClearValue = false;
|
||||
desc.sampleCount = 1;
|
||||
desc.dimension = nvrhi::TextureDimension::Texture2D;
|
||||
desc.keepInitialState = true;
|
||||
desc.arraySize = 1;
|
||||
desc.isUAV = true;
|
||||
desc.format = nvrhi::Format::RGBA8_UNORM;
|
||||
|
||||
return device->createTexture( desc );
|
||||
}
|
||||
|
||||
struct MipMapGenPass::NullTextures
|
||||
{
|
||||
|
||||
nvrhi::TextureHandle lod[NUM_LODS];
|
||||
|
||||
static std::shared_ptr<NullTextures> get( nvrhi::DeviceHandle device )
|
||||
{
|
||||
static std::mutex _mutex;
|
||||
static std::weak_ptr<NullTextures> _nullTextures;
|
||||
|
||||
std::lock_guard<std::mutex> lock( _mutex );
|
||||
|
||||
std::shared_ptr<NullTextures> result = _nullTextures.lock();
|
||||
if( !result )
|
||||
{
|
||||
result = std::make_shared<NullTextures>();
|
||||
for( int i = 0; i < NUM_LODS; ++i )
|
||||
{
|
||||
result->lod[i] = createNullTexture( device );
|
||||
}
|
||||
_nullTextures = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
MipMapGenPass::MipMapGenPass(
|
||||
nvrhi::IDevice* device,
|
||||
nvrhi::TextureHandle input,
|
||||
Mode mode )
|
||||
: m_Device( device )
|
||||
, m_Texture( input )
|
||||
, m_BindingSets( MAX_PASSES )
|
||||
, m_BindingCache( )
|
||||
{
|
||||
assert( m_Texture );
|
||||
|
||||
m_BindingCache.Init( device );
|
||||
|
||||
m_NullTextures = NullTextures::get( m_Device );
|
||||
|
||||
uint nmipLevels = m_Texture->getDesc().mipLevels;
|
||||
|
||||
// Shader
|
||||
assert( mode >= 0 && mode <= MODE_MINMAX );
|
||||
|
||||
idList<shaderMacro_t> macros;
|
||||
macros.Append( shaderMacro_t( "MODE", std::to_string( mode ).c_str( ) ) );
|
||||
int index = renderProgManager.FindShader( "builtin/mipmapgen", SHADER_STAGE_COMPUTE, "", macros, true );
|
||||
m_Shader = renderProgManager.GetShader( index );
|
||||
|
||||
// Constants
|
||||
nvrhi::BufferDesc constantBufferDesc;
|
||||
constantBufferDesc.byteSize = sizeof( MipmmapGenConstants );
|
||||
constantBufferDesc.isConstantBuffer = true;
|
||||
constantBufferDesc.isVolatile = true;
|
||||
constantBufferDesc.debugName = "MipMapGenPass/Constants";
|
||||
constantBufferDesc.maxVersions = c_MaxRenderPassConstantBufferVersions;
|
||||
m_ConstantBuffer = m_Device->createBuffer( constantBufferDesc );
|
||||
|
||||
// BindingLayout
|
||||
nvrhi::BindingLayoutDesc layoutDesc;
|
||||
layoutDesc.visibility = nvrhi::ShaderType::Compute;
|
||||
layoutDesc.bindings.push_back( nvrhi::BindingLayoutItem::VolatileConstantBuffer( 0 ) ),
|
||||
layoutDesc.bindings.push_back( nvrhi::BindingLayoutItem::Texture_SRV( 0 ) );
|
||||
for( uint mipLevel = 1; mipLevel <= NUM_LODS; ++mipLevel )
|
||||
{
|
||||
layoutDesc.bindings.push_back( nvrhi::BindingLayoutItem::Texture_UAV( mipLevel - 1 ) );
|
||||
}
|
||||
m_BindingLayout = m_Device->createBindingLayout( layoutDesc );
|
||||
|
||||
// BindingSets
|
||||
m_BindingSets.SetNum( MAX_PASSES );
|
||||
nvrhi::BindingSetDesc setDesc;
|
||||
for( uint i = 0; i < ( uint )m_BindingSets.Num(); ++i )
|
||||
{
|
||||
// Create a unique binding set for each compute pass
|
||||
if( i * NUM_LODS >= nmipLevels )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
nvrhi::BindingSetHandle& set = m_BindingSets[i];
|
||||
|
||||
nvrhi::BindingSetDesc setDesc;
|
||||
setDesc.bindings.push_back( nvrhi::BindingSetItem::ConstantBuffer( 0, m_ConstantBuffer ) );
|
||||
setDesc.bindings.push_back( nvrhi::BindingSetItem::Texture_SRV( 0, m_Texture, nvrhi::Format::UNKNOWN, nvrhi::TextureSubresourceSet( i * NUM_LODS, 1, 0, 1 ) ) );
|
||||
for( uint mipLevel = 1; mipLevel <= NUM_LODS; ++mipLevel )
|
||||
{
|
||||
// output UAVs start after the mip-level UAV that was computed last
|
||||
if( i * NUM_LODS + mipLevel < nmipLevels )
|
||||
{
|
||||
setDesc.bindings.push_back( nvrhi::BindingSetItem::Texture_UAV( mipLevel - 1, m_Texture, nvrhi::Format::UNKNOWN, nvrhi::TextureSubresourceSet( i * NUM_LODS + mipLevel, 1, 0, 1 ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
setDesc.bindings.push_back( nvrhi::BindingSetItem::Texture_UAV( mipLevel - 1, m_NullTextures->lod[mipLevel - 1] ) );
|
||||
}
|
||||
}
|
||||
set = m_Device->createBindingSet( setDesc, m_BindingLayout );
|
||||
}
|
||||
|
||||
nvrhi::ComputePipelineDesc computePipelineDesc;
|
||||
computePipelineDesc.CS = m_Shader;
|
||||
computePipelineDesc.bindingLayouts = { m_BindingLayout };
|
||||
|
||||
m_Pso = device->createComputePipeline( computePipelineDesc );
|
||||
}
|
||||
|
||||
void MipMapGenPass::Dispatch( nvrhi::ICommandList* commandList, int maxLOD )
|
||||
{
|
||||
assert( m_Texture );
|
||||
|
||||
commandList->beginMarker( "MipMapGen::Dispatch" );
|
||||
|
||||
uint nmipLevels = m_Texture->getDesc().mipLevels;
|
||||
if( maxLOD > 0 && maxLOD < ( int )nmipLevels )
|
||||
{
|
||||
nmipLevels = maxLOD + 1;
|
||||
}
|
||||
|
||||
uint npasses = ( uint32_t )ceilf( ( float )nmipLevels / ( float )NUM_LODS );
|
||||
|
||||
uint width = m_Texture->getDesc().width,
|
||||
height = m_Texture->getDesc().height;
|
||||
|
||||
width = ( width + GROUP_SIZE - 1 ) / GROUP_SIZE;
|
||||
height = ( height + GROUP_SIZE - 1 ) / GROUP_SIZE;
|
||||
|
||||
for( uint i = 0; i < MAX_PASSES; ++i )
|
||||
{
|
||||
if( i * NUM_LODS >= nmipLevels )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
MipmmapGenConstants constants = {};
|
||||
constants.numLODs = std::min( nmipLevels - i * NUM_LODS - 1, ( uint32_t )NUM_LODS );
|
||||
constants.dispatch = i;
|
||||
commandList->writeBuffer( m_ConstantBuffer, &constants, sizeof( constants ) );
|
||||
|
||||
nvrhi::ComputeState state;
|
||||
state.pipeline = m_Pso;
|
||||
state.bindings = { m_BindingSets[i] };
|
||||
commandList->setComputeState( state );
|
||||
commandList->dispatch( width, height );
|
||||
}
|
||||
|
||||
commandList->endMarker(); // "MipMapGen::Dispatch"
|
||||
}
|
||||
|
||||
|
||||
void MipMapGenPass::Display( CommonRenderPasses& commonPasses, nvrhi::ICommandList* commandList, nvrhi::IFramebuffer* target )
|
||||
{
|
||||
assert( m_Texture );
|
||||
|
||||
commandList->beginMarker( "MipMapGen::Display" );
|
||||
|
||||
nvrhi::Viewport viewport = nvrhi::Viewport( ( float )target->getFramebufferInfo().width, ( float )target->getFramebufferInfo().height );
|
||||
|
||||
idVec2 size( m_Texture->getDesc().width / 2.f, m_Texture->getDesc().height / 2.f );
|
||||
idVec2 corner( 10.f, uint( viewport.maxY ) - 10.f );
|
||||
|
||||
for( uint level = 0; level < m_Texture->getDesc().mipLevels - 1; ++level )
|
||||
{
|
||||
BlitParameters blitParams;
|
||||
blitParams.targetFramebuffer = target;
|
||||
blitParams.sourceTexture = m_Texture;
|
||||
blitParams.sourceMip = level + 1;
|
||||
blitParams.targetViewport = nvrhi::Viewport(
|
||||
corner.x,
|
||||
corner.x + size.x,
|
||||
corner.y - size.y,
|
||||
corner.y, 0.f, 1.f
|
||||
);
|
||||
|
||||
commonPasses.BlitTexture( commandList, blitParams, &m_BindingCache );
|
||||
|
||||
// spiral pattern
|
||||
switch( level % 4 )
|
||||
{
|
||||
case 0:
|
||||
corner += idVec2( size.x + 10.f, 0.f );
|
||||
break;
|
||||
case 1:
|
||||
corner += idVec2( size.x / 2.f, -( size.y + 10.f ) );
|
||||
break;
|
||||
case 2:
|
||||
corner += idVec2( -size.x / 2.f - 10.f, -size.y / 2.f );
|
||||
break;
|
||||
case 3:
|
||||
corner += idVec2( 0.f, size.y );
|
||||
break;
|
||||
}
|
||||
size = idVec2( size.x / 2.f, size.y / 2.f );
|
||||
}
|
||||
|
||||
commandList->endMarker(); // "MipMapGen::Display"
|
||||
}
|
80
neo/renderer/Passes/MipMapGenPass.h
Normal file
80
neo/renderer/Passes/MipMapGenPass.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef RENDERER_PASSES_MIPMAPGENPASS_H_
|
||||
#define RENDERER_PASSES_MIPMAPGENPASS_H_
|
||||
|
||||
class CommonRenderPasses;
|
||||
|
||||
class MipMapGenPass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum Mode : uint8_t
|
||||
{
|
||||
MODE_COLOR = 0, // bilinear reduction of RGB channels
|
||||
MODE_MIN = 1, // min() reduction of R channel
|
||||
MODE_MAX = 2, // max() reduction of R channel
|
||||
MODE_MINMAX = 3, // min() and max() reductions of R channel into RG channels
|
||||
};
|
||||
|
||||
// note : 'texture' must have been allocated with some mip levels
|
||||
MipMapGenPass(
|
||||
nvrhi::IDevice* device,
|
||||
nvrhi::TextureHandle texture,
|
||||
Mode mode = Mode::MODE_MAX );
|
||||
|
||||
// Dispatches reduction kernel : reads LOD 0 and populates
|
||||
// LOD 1 and up
|
||||
void Dispatch( nvrhi::ICommandList* commandList, int maxLOD = -1 );
|
||||
|
||||
// debug : blits mip-map levels in spiral pattern to 'target'
|
||||
// (assumes 'target' texture resolution is high enough...)
|
||||
void Display(
|
||||
CommonRenderPasses& commonPasses,
|
||||
nvrhi::ICommandList* commandList,
|
||||
nvrhi::IFramebuffer* target );
|
||||
|
||||
private:
|
||||
|
||||
nvrhi::DeviceHandle m_Device;
|
||||
nvrhi::ShaderHandle m_Shader;
|
||||
nvrhi::TextureHandle m_Texture;
|
||||
nvrhi::BufferHandle m_ConstantBuffer;
|
||||
nvrhi::BindingLayoutHandle m_BindingLayout;
|
||||
idList<nvrhi::BindingSetHandle> m_BindingSets;
|
||||
nvrhi::ComputePipelineHandle m_Pso;
|
||||
|
||||
// Set of unique dummy textures - see details in class implementation
|
||||
struct NullTextures;
|
||||
std::shared_ptr<NullTextures> m_NullTextures;
|
||||
|
||||
BindingCache m_BindingCache;
|
||||
};
|
||||
|
||||
#endif
|
280
neo/renderer/Passes/SsaoPass.cpp
Normal file
280
neo/renderer/Passes/SsaoPass.cpp
Normal file
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#include <precompiled.h>
|
||||
#pragma hdrstop
|
||||
|
||||
#include "renderer/RenderCommon.h"
|
||||
|
||||
#include "SsaoPass.h"
|
||||
|
||||
struct SsaoConstants
|
||||
{
|
||||
idVec2 clipToView;
|
||||
idVec2 invQuantizedGbufferSize;
|
||||
|
||||
idVec2i quantizedViewportOrigin;
|
||||
float amount;
|
||||
float invBackgroundViewDepth;
|
||||
float radiusWorld;
|
||||
float surfaceBias;
|
||||
|
||||
float radiusToScreen;
|
||||
float powerExponent;
|
||||
};
|
||||
|
||||
SsaoPass::SsaoPass(
|
||||
nvrhi::IDevice* device,
|
||||
const CreateParameters& params,
|
||||
CommonRenderPasses* commonPasses )
|
||||
: commonRenderPasses( commonPasses )
|
||||
, m_Device( device )
|
||||
{
|
||||
nvrhi::BufferDesc constantBufferDesc;
|
||||
constantBufferDesc.byteSize = sizeof( SsaoConstants );
|
||||
constantBufferDesc.debugName = "SsaoConstants";
|
||||
constantBufferDesc.isConstantBuffer = true;
|
||||
constantBufferDesc.isVolatile = true;
|
||||
constantBufferDesc.maxVersions = c_MaxRenderPassConstantBufferVersions;
|
||||
m_ConstantBuffer = device->createBuffer( constantBufferDesc );
|
||||
|
||||
nvrhi::TextureDesc DeinterleavedTextureDesc;
|
||||
DeinterleavedTextureDesc.width = ( params.dimensions.x + 3 ) / 4;
|
||||
DeinterleavedTextureDesc.height = ( params.dimensions.y + 3 ) / 4;
|
||||
DeinterleavedTextureDesc.arraySize = 16;
|
||||
DeinterleavedTextureDesc.dimension = nvrhi::TextureDimension::Texture2DArray;
|
||||
DeinterleavedTextureDesc.isUAV = true;
|
||||
DeinterleavedTextureDesc.initialState = nvrhi::ResourceStates::ShaderResource;
|
||||
DeinterleavedTextureDesc.keepInitialState = true;
|
||||
DeinterleavedTextureDesc.debugName = "SSAO/DeinterleavedDepth";
|
||||
DeinterleavedTextureDesc.format = nvrhi::Format::R32_FLOAT;
|
||||
m_DeinterleavedDepth = device->createTexture( DeinterleavedTextureDesc );
|
||||
|
||||
m_QuantizedGbufferTextureSize = idVec2( float( DeinterleavedTextureDesc.width ), float( DeinterleavedTextureDesc.height ) ) * 4.f;
|
||||
|
||||
DeinterleavedTextureDesc.debugName = "SSAO/DeinterleavedOcclusion";
|
||||
DeinterleavedTextureDesc.format = params.directionalOcclusion ? nvrhi::Format::RGBA16_FLOAT : nvrhi::Format::R8_UNORM;
|
||||
m_DeinterleavedOcclusion = device->createTexture( DeinterleavedTextureDesc );
|
||||
|
||||
{
|
||||
idList<shaderMacro_t> macros = { { "LINEAR_DEPTH", params.inputLinearDepth ? "1" : "0" } };
|
||||
int shaderIdx = renderProgManager.FindShader( "builtin/SSAO/ssao_deinterleave", SHADER_STAGE_COMPUTE, "", macros, true, LAYOUT_DRAW_VERT );
|
||||
m_Deinterleave.Shader = renderProgManager.GetShader( shaderIdx );
|
||||
|
||||
nvrhi::BindingLayoutDesc DeinterleaveBindings;
|
||||
DeinterleaveBindings.visibility = nvrhi::ShaderType::Compute;
|
||||
DeinterleaveBindings.bindings =
|
||||
{
|
||||
nvrhi::BindingLayoutItem::VolatileConstantBuffer( 0 ),
|
||||
nvrhi::BindingLayoutItem::VolatileConstantBuffer( 1 ),
|
||||
nvrhi::BindingLayoutItem::Texture_SRV( 0 ),
|
||||
nvrhi::BindingLayoutItem::Texture_UAV( 0 ),
|
||||
};
|
||||
m_Deinterleave.BindingLayout = m_Device->createBindingLayout( DeinterleaveBindings );
|
||||
|
||||
nvrhi::ComputePipelineDesc DeinterleavePipelineDesc;
|
||||
DeinterleavePipelineDesc.bindingLayouts = { m_Deinterleave.BindingLayout };
|
||||
DeinterleavePipelineDesc.CS = m_Deinterleave.Shader;
|
||||
m_Deinterleave.Pipeline = device->createComputePipeline( DeinterleavePipelineDesc );
|
||||
|
||||
m_Deinterleave.BindingSets.resize( params.numBindingSets );
|
||||
}
|
||||
|
||||
{
|
||||
idList<shaderMacro_t> macros =
|
||||
{
|
||||
{ "OCT_ENCODED_NORMALS", params.octEncodedNormals ? "1" : "0" },
|
||||
{ "DIRECTIONAL_OCCLUSION", params.directionalOcclusion ? "1" : "0" }
|
||||
};
|
||||
int shaderIdx = renderProgManager.FindShader( "builtin/SSAO/ssao_compute", SHADER_STAGE_COMPUTE, "", macros, true, LAYOUT_DRAW_VERT );
|
||||
m_Compute.Shader = renderProgManager.GetShader( shaderIdx );
|
||||
|
||||
nvrhi::BindingLayoutDesc ComputeBindings;
|
||||
ComputeBindings.visibility = nvrhi::ShaderType::Compute;
|
||||
ComputeBindings.bindings =
|
||||
{
|
||||
nvrhi::BindingLayoutItem::VolatileConstantBuffer( 0 ),
|
||||
nvrhi::BindingLayoutItem::VolatileConstantBuffer( 1 ),
|
||||
nvrhi::BindingLayoutItem::Texture_SRV( 0 ),
|
||||
nvrhi::BindingLayoutItem::Texture_SRV( 1 ),
|
||||
nvrhi::BindingLayoutItem::Texture_UAV( 0 ),
|
||||
};
|
||||
m_Compute.BindingLayout = m_Device->createBindingLayout( ComputeBindings );
|
||||
|
||||
nvrhi::ComputePipelineDesc ComputePipeline;
|
||||
ComputePipeline.bindingLayouts = { m_Compute.BindingLayout };
|
||||
ComputePipeline.CS = m_Compute.Shader;
|
||||
m_Compute.Pipeline = device->createComputePipeline( ComputePipeline );
|
||||
|
||||
m_Compute.BindingSets.resize( params.numBindingSets );
|
||||
}
|
||||
|
||||
{
|
||||
idList<shaderMacro_t> macros =
|
||||
{
|
||||
{ "DIRECTIONAL_OCCLUSION", params.directionalOcclusion ? "1" : "0" }
|
||||
};
|
||||
int shaderIdx = renderProgManager.FindShader( "builtin/SSAO/ssao_blur", SHADER_STAGE_COMPUTE, "", macros, true, LAYOUT_DRAW_VERT );
|
||||
m_Blur.Shader = renderProgManager.GetShader( shaderIdx );
|
||||
|
||||
nvrhi::BindingLayoutDesc BlurBindings;
|
||||
BlurBindings.visibility = nvrhi::ShaderType::Compute;
|
||||
BlurBindings.bindings =
|
||||
{
|
||||
nvrhi::BindingLayoutItem::VolatileConstantBuffer( 0 ),
|
||||
nvrhi::BindingLayoutItem::VolatileConstantBuffer( 1 ),
|
||||
nvrhi::BindingLayoutItem::Texture_SRV( 0 ),
|
||||
nvrhi::BindingLayoutItem::Texture_SRV( 1 ),
|
||||
nvrhi::BindingLayoutItem::Texture_UAV( 0 ),
|
||||
nvrhi::BindingLayoutItem::Sampler( 0 ),
|
||||
};
|
||||
m_Blur.BindingLayout = m_Device->createBindingLayout( BlurBindings );
|
||||
|
||||
nvrhi::ComputePipelineDesc BlurPipeline;
|
||||
BlurPipeline.bindingLayouts = { m_Blur.BindingLayout };
|
||||
BlurPipeline.CS = m_Blur.Shader;
|
||||
m_Blur.Pipeline = device->createComputePipeline( BlurPipeline );
|
||||
|
||||
m_Blur.BindingSets.resize( params.numBindingSets );
|
||||
}
|
||||
}
|
||||
|
||||
// Backwards compatibility constructor
|
||||
SsaoPass::SsaoPass(
|
||||
nvrhi::IDevice* device,
|
||||
CommonRenderPasses* commonPasses,
|
||||
nvrhi::ITexture* gbufferDepth,
|
||||
nvrhi::ITexture* gbufferNormals,
|
||||
nvrhi::ITexture* destinationTexture )
|
||||
: SsaoPass( device, CreateParameters{ idVec2( gbufferDepth->getDesc().width, gbufferDepth->getDesc().height ), false, false, false, 1 }, commonPasses )
|
||||
{
|
||||
const nvrhi::TextureDesc& depthDesc = gbufferDepth->getDesc();
|
||||
const nvrhi::TextureDesc& normalsDesc = gbufferNormals->getDesc();
|
||||
assert( depthDesc.sampleCount == normalsDesc.sampleCount );
|
||||
assert( depthDesc.sampleCount == 1 ); // more is currently unsupported
|
||||
assert( depthDesc.dimension == nvrhi::TextureDimension::Texture2D ); // arrays are currently unsupported
|
||||
|
||||
CreateBindingSet( gbufferDepth, gbufferNormals, destinationTexture, 0 );
|
||||
}
|
||||
|
||||
void SsaoPass::CreateBindingSet(
|
||||
nvrhi::ITexture* gbufferDepth,
|
||||
nvrhi::ITexture* gbufferNormals,
|
||||
nvrhi::ITexture* destinationTexture,
|
||||
int bindingSetIndex )
|
||||
{
|
||||
nvrhi::BindingSetDesc DeinterleaveBindings;
|
||||
DeinterleaveBindings.bindings =
|
||||
{
|
||||
nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.GetConstantBuffer() ),
|
||||
nvrhi::BindingSetItem::ConstantBuffer( 1, m_ConstantBuffer ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 0, gbufferDepth ),
|
||||
nvrhi::BindingSetItem::Texture_UAV( 0, m_DeinterleavedDepth )
|
||||
};
|
||||
m_Deinterleave.BindingSets[bindingSetIndex] = m_Device->createBindingSet( DeinterleaveBindings, m_Deinterleave.BindingLayout );
|
||||
|
||||
nvrhi::BindingSetDesc ComputeBindings;
|
||||
ComputeBindings.bindings =
|
||||
{
|
||||
nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.GetConstantBuffer( ) ),
|
||||
nvrhi::BindingSetItem::ConstantBuffer( 1, m_ConstantBuffer ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 0, m_DeinterleavedDepth ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 1, gbufferNormals ),
|
||||
nvrhi::BindingSetItem::Texture_UAV( 0, m_DeinterleavedOcclusion )
|
||||
};
|
||||
m_Compute.BindingSets[bindingSetIndex] = m_Device->createBindingSet( ComputeBindings, m_Compute.BindingLayout );
|
||||
|
||||
nvrhi::BindingSetDesc BlurBindings;
|
||||
BlurBindings.bindings =
|
||||
{
|
||||
nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.GetConstantBuffer( ) ),
|
||||
nvrhi::BindingSetItem::ConstantBuffer( 1, m_ConstantBuffer ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 0, m_DeinterleavedDepth ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 1, m_DeinterleavedOcclusion ),
|
||||
nvrhi::BindingSetItem::Texture_UAV( 0, destinationTexture ),
|
||||
nvrhi::BindingSetItem::Sampler( 0, commonRenderPasses->m_PointClampSampler )
|
||||
};
|
||||
m_Blur.BindingSets[bindingSetIndex] = m_Device->createBindingSet( BlurBindings, m_Blur.BindingLayout );
|
||||
}
|
||||
|
||||
void SsaoPass::Render(
|
||||
nvrhi::ICommandList* commandList,
|
||||
const SsaoParameters& params,
|
||||
viewDef_t* viewDef,
|
||||
int bindingSetIndex )
|
||||
{
|
||||
assert( m_Deinterleave.BindingSets[bindingSetIndex] );
|
||||
assert( m_Compute.BindingSets[bindingSetIndex] );
|
||||
assert( m_Blur.BindingSets[bindingSetIndex] );
|
||||
|
||||
commandList->beginMarker( "SSAO" );
|
||||
|
||||
nvrhi::Rect viewExtent( viewDef->viewport.x1, viewDef->viewport.x2, viewDef->viewport.y1, viewDef->viewport.y2 );
|
||||
nvrhi::Rect quarterResExtent = viewExtent;
|
||||
quarterResExtent.minX /= 4;
|
||||
quarterResExtent.minY /= 4;
|
||||
quarterResExtent.maxX = ( quarterResExtent.maxX + 3 ) / 4;
|
||||
quarterResExtent.maxY = ( quarterResExtent.maxY + 3 ) / 4;
|
||||
|
||||
SsaoConstants ssaoConstants = {};
|
||||
ssaoConstants.clipToView = idVec2(
|
||||
viewDef->projectionMatrix[2 * 4 + 3] / viewDef->projectionMatrix[0 * 4 + 0],
|
||||
viewDef->projectionMatrix[2 * 4 + 3] / viewDef->projectionMatrix[0 * 4 + 1] );
|
||||
ssaoConstants.invQuantizedGbufferSize = 1.f / m_QuantizedGbufferTextureSize;
|
||||
ssaoConstants.quantizedViewportOrigin = idVec2i( quarterResExtent.minX, quarterResExtent.minY ) * 4;
|
||||
ssaoConstants.amount = params.amount;
|
||||
ssaoConstants.invBackgroundViewDepth = ( params.backgroundViewDepth > 0.f ) ? 1.f / params.backgroundViewDepth : 0.f;
|
||||
ssaoConstants.radiusWorld = params.radiusWorld;
|
||||
ssaoConstants.surfaceBias = params.surfaceBias;
|
||||
ssaoConstants.powerExponent = params.powerExponent;
|
||||
ssaoConstants.radiusToScreen = 0.5f * viewDef->viewport.GetHeight() * abs( viewDef->projectionMatrix[1 * 4 + 1] );
|
||||
commandList->writeBuffer( m_ConstantBuffer, &ssaoConstants, sizeof( ssaoConstants ) );
|
||||
|
||||
uint32_t dispatchWidth = ( quarterResExtent.width() + 7 ) / 8;
|
||||
uint32_t dispatchHeight = ( quarterResExtent.height() + 7 ) / 8;
|
||||
|
||||
nvrhi::ComputeState state;
|
||||
state.pipeline = m_Deinterleave.Pipeline;
|
||||
state.bindings = { m_Deinterleave.BindingSets[bindingSetIndex] };
|
||||
commandList->setComputeState( state );
|
||||
commandList->dispatch( dispatchWidth, dispatchHeight, 1 );
|
||||
|
||||
state.pipeline = m_Compute.Pipeline;
|
||||
state.bindings = { m_Compute.BindingSets[bindingSetIndex] };
|
||||
commandList->setComputeState( state );
|
||||
commandList->dispatch( dispatchWidth, dispatchHeight, 16 );
|
||||
|
||||
dispatchWidth = ( viewExtent.width() + 15 ) / 16;
|
||||
dispatchHeight = ( viewExtent.height() + 15 ) / 16;
|
||||
|
||||
state.pipeline = m_Blur.Pipeline;
|
||||
state.bindings = { m_Blur.BindingSets[bindingSetIndex] };
|
||||
commandList->setComputeState( state );
|
||||
commandList->dispatch( dispatchWidth, dispatchHeight, 1 );
|
||||
|
||||
commandList->endMarker();
|
||||
}
|
100
neo/renderer/Passes/SsaoPass.h
Normal file
100
neo/renderer/Passes/SsaoPass.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef RENDERER_PASSES_SSAOPASS_H_
|
||||
#define RENDERER_PASSES_SSAOPASS_H_
|
||||
|
||||
struct SsaoParameters
|
||||
{
|
||||
float amount = 2.f;
|
||||
float backgroundViewDepth = 100.f;
|
||||
float radiusWorld = 0.5f;
|
||||
float surfaceBias = 0.1f;
|
||||
float powerExponent = 2.f;
|
||||
bool enableBlur = true;
|
||||
float blurSharpness = 16.f;
|
||||
};
|
||||
|
||||
class SsaoPass
|
||||
{
|
||||
private:
|
||||
struct SubPass
|
||||
{
|
||||
nvrhi::ShaderHandle Shader;
|
||||
nvrhi::BindingLayoutHandle BindingLayout;
|
||||
std::vector<nvrhi::BindingSetHandle> BindingSets;
|
||||
nvrhi::ComputePipelineHandle Pipeline;
|
||||
};
|
||||
|
||||
SubPass m_Deinterleave;
|
||||
SubPass m_Compute;
|
||||
SubPass m_Blur;
|
||||
|
||||
nvrhi::DeviceHandle m_Device;
|
||||
nvrhi::BufferHandle m_ConstantBuffer;
|
||||
CommonRenderPasses* commonRenderPasses;
|
||||
|
||||
nvrhi::TextureHandle m_DeinterleavedDepth;
|
||||
nvrhi::TextureHandle m_DeinterleavedOcclusion;
|
||||
idVec2 m_QuantizedGbufferTextureSize;
|
||||
|
||||
public:
|
||||
struct CreateParameters
|
||||
{
|
||||
idVec2 dimensions;
|
||||
bool inputLinearDepth = false;
|
||||
bool octEncodedNormals = false;
|
||||
bool directionalOcclusion = false;
|
||||
int numBindingSets = 1;
|
||||
};
|
||||
|
||||
SsaoPass(
|
||||
nvrhi::IDevice* device,
|
||||
const CreateParameters& params,
|
||||
CommonRenderPasses* commonRenderPasses );
|
||||
|
||||
SsaoPass(
|
||||
nvrhi::IDevice* device,
|
||||
CommonRenderPasses* commonPasses,
|
||||
nvrhi::ITexture* gbufferDepth,
|
||||
nvrhi::ITexture* gbufferNormals,
|
||||
nvrhi::ITexture* destinationTexture );
|
||||
|
||||
void CreateBindingSet(
|
||||
nvrhi::ITexture* gbufferDepth,
|
||||
nvrhi::ITexture* gbufferNormals,
|
||||
nvrhi::ITexture* destinationTexture,
|
||||
int bindingSetIndex = 0 );
|
||||
|
||||
void Render(
|
||||
nvrhi::ICommandList* commandList,
|
||||
const SsaoParameters& params,
|
||||
viewDef_t* viewDef,
|
||||
int bindingSetIndex = 0 );
|
||||
};
|
||||
|
||||
#endif
|
|
@ -227,7 +227,8 @@ struct vulkanContext_t
|
|||
|
||||
extern vulkanContext_t vkcontext;
|
||||
|
||||
#else //if defined( ID_OPENGL )
|
||||
//#elif !defined( USE_NVRHI )
|
||||
#else
|
||||
|
||||
struct glContext_t
|
||||
{
|
||||
|
|
|
@ -40,6 +40,26 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#include "Font.h"
|
||||
#include "Framebuffer.h"
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
|
||||
#if USE_DX11 || USE_DX12
|
||||
#include <DXGI.h>
|
||||
#endif
|
||||
|
||||
#if USE_DX11
|
||||
#include <d3d11.h>
|
||||
#endif
|
||||
|
||||
#if USE_DX12
|
||||
#include <d3d12.h>
|
||||
#endif
|
||||
|
||||
#if USE_VK
|
||||
#include <nvrhi/vulkan.h>
|
||||
#endif
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
#endif
|
||||
|
||||
// maximum texture units
|
||||
const int MAX_PROG_TEXTURE_PARMS = 16;
|
||||
|
|
350
neo/renderer/RenderPass.cpp
Normal file
350
neo/renderer/RenderPass.cpp
Normal file
|
@ -0,0 +1,350 @@
|
|||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "RenderPass.h"
|
||||
#include "Passes/CommonPasses.h"
|
||||
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
static triIndex_t quadPicIndexes[6] = { 3, 0, 2, 2, 0, 1 };
|
||||
|
||||
#define MAX_VERTS 8000
|
||||
#define MAX_INDEXES 120000
|
||||
|
||||
idDrawVert* BasicTriangle::AllocVerts( int vertCount, triIndex_t* tempIndexes, int indexCount )
|
||||
{
|
||||
if( numIndexes + indexCount > MAX_INDEXES )
|
||||
{
|
||||
static int warningFrame = 0;
|
||||
if( warningFrame != tr.frameCount )
|
||||
{
|
||||
warningFrame = tr.frameCount;
|
||||
idLib::Warning( "idGuiModel::AllocTris: MAX_INDEXES exceeded" );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( numVerts + vertCount > MAX_VERTS )
|
||||
{
|
||||
static int warningFrame = 0;
|
||||
if( warningFrame != tr.frameCount )
|
||||
{
|
||||
warningFrame = tr.frameCount;
|
||||
idLib::Warning( "idGuiModel::AllocTris: MAX_VERTS exceeded" );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int startVert = numVerts;
|
||||
int startIndex = numIndexes;
|
||||
|
||||
numVerts += vertCount;
|
||||
numIndexes += indexCount;
|
||||
|
||||
if( ( startIndex & 1 ) || ( indexCount & 1 ) )
|
||||
{
|
||||
// slow for write combined memory!
|
||||
// this should be very rare, since quads are always an even index count
|
||||
for( int i = 0; i < indexCount; i++ )
|
||||
{
|
||||
indexPointer[startIndex + i] = startVert + tempIndexes[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < indexCount; i += 2 )
|
||||
{
|
||||
WriteIndexPair( indexPointer + startIndex + i, startVert + tempIndexes[i], startVert + tempIndexes[i + 1] );
|
||||
}
|
||||
}
|
||||
|
||||
return vertexPointer + startVert;
|
||||
}
|
||||
|
||||
bool BasicTriangle::Init()
|
||||
{
|
||||
int v = renderProgManager.FindShader( "vertbuffershaders.hlsl", SHADER_STAGE_VERTEX );
|
||||
int f = renderProgManager.FindShader( "vertbuffershaders.hlsl", SHADER_STAGE_FRAGMENT );
|
||||
|
||||
vertexShader = renderProgManager.GetShader( v );
|
||||
pixelShader = renderProgManager.GetShader( f );
|
||||
|
||||
if( !vertexShader || !pixelShader )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
commandList = GetDevice()->createCommandList();
|
||||
|
||||
nvrhi::VertexAttributeDesc attributes[] =
|
||||
{
|
||||
nvrhi::VertexAttributeDesc()
|
||||
.setName( "POSITION" )
|
||||
.setFormat( nvrhi::Format::RGB32_FLOAT )
|
||||
.setOffset( offsetof( idDrawVert, xyz ) )
|
||||
.setElementStride( sizeof( idDrawVert ) ),
|
||||
//nvrhi::VertexAttributeDesc()
|
||||
// .setName( "NORMAL" )
|
||||
// .setFormat( nvrhi::Format::RGBA8_UINT )
|
||||
// .setOffset( offsetof( idDrawVert, normal ) )
|
||||
// .setElementStride( sizeof( idDrawVert ) ),
|
||||
//nvrhi::VertexAttributeDesc()
|
||||
// .setName( "COLOR" )
|
||||
// .setFormat( nvrhi::Format::RGBA8_UINT )
|
||||
// .setOffset( offsetof( idDrawVert, color ) )
|
||||
// .setElementStride( sizeof( idDrawVert ) ),
|
||||
//nvrhi::VertexAttributeDesc()
|
||||
// .setName( "COLOR2" )
|
||||
// .setFormat( nvrhi::Format::RGBA8_UINT )
|
||||
// .setOffset( offsetof( idDrawVert, color2 ) )
|
||||
// .setElementStride( sizeof( idDrawVert ) ),
|
||||
nvrhi::VertexAttributeDesc()
|
||||
.setName( "UV" )
|
||||
.setFormat( nvrhi::Format::RG16_FLOAT )
|
||||
.setOffset( offsetof( idDrawVert, st ) )
|
||||
.setElementStride( sizeof( idDrawVert ) ),
|
||||
//nvrhi::VertexAttributeDesc()
|
||||
// .setName( "TANGENT" )
|
||||
// .setFormat( nvrhi::Format::RGBA8_UINT )
|
||||
// .setOffset( offsetof( idDrawVert, tangent ) )
|
||||
// .setElementStride( sizeof( idDrawVert ) ),
|
||||
};
|
||||
|
||||
inputLayout = GetDevice()->createInputLayout( attributes, uint32_t( std::size( attributes ) ), vertexShader );
|
||||
|
||||
material = declManager->FindMaterial( "guis/rml/shell/textures/invader" );
|
||||
|
||||
commandList->open();
|
||||
for( int i = 0; i < material->GetNumStages(); i++ )
|
||||
{
|
||||
material->GetStage( i )->texture.image->FinalizeImage( true, commandList );
|
||||
}
|
||||
commandList->close();
|
||||
GetDevice()->executeCommandList( commandList );
|
||||
GetDevice()->runGarbageCollection();
|
||||
|
||||
nvrhi::ITexture* texture = ( nvrhi::ITexture* )material->GetStage( 0 )->texture.image->GetTextureID();
|
||||
|
||||
CommonRenderPasses commonPasses;
|
||||
commonPasses.Init( GetDevice() );
|
||||
|
||||
nvrhi::BindingSetDesc bindingSetDesc;
|
||||
bindingSetDesc.bindings =
|
||||
{
|
||||
nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.ConstantBuffer() ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 0, texture ),
|
||||
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler )
|
||||
};
|
||||
|
||||
if( !nvrhi::utils::CreateBindingSetAndLayout( GetDevice(), nvrhi::ShaderType::All, 0, bindingSetDesc, bindingLayout, bindingSet ) )
|
||||
{
|
||||
common->Error( "Couldn't create the binding set or layout" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BasicTriangle::BackBufferResizing()
|
||||
{
|
||||
pipeline = nullptr;
|
||||
}
|
||||
|
||||
void BasicTriangle::Animate( float fElapsedTimeSeconds )
|
||||
{
|
||||
}
|
||||
|
||||
void BasicTriangle::RenderFrontend()
|
||||
{
|
||||
vertexBlock = vertexCache.AllocVertex( NULL, MAX_VERTS, sizeof( idDrawVert ), commandList );
|
||||
indexBlock = vertexCache.AllocIndex( NULL, MAX_INDEXES, sizeof( triIndex_t ), commandList );
|
||||
|
||||
vertexPointer = ( idDrawVert* )vertexCache.MappedVertexBuffer( vertexBlock );
|
||||
indexPointer = ( triIndex_t* )vertexCache.MappedIndexBuffer( indexBlock );
|
||||
numVerts = 0;
|
||||
numIndexes = 0;
|
||||
|
||||
idDrawVert* verts = AllocVerts( 4, quadPicIndexes, 6 );
|
||||
|
||||
uint32_t currentColorNativeBytesOrder = LittleLong( PackColor( idVec4( 255, 255, 255, 255 ) ) );
|
||||
|
||||
float x = 0.f;
|
||||
float y = 0.f;
|
||||
float w = renderSystem->GetWidth();
|
||||
float h = renderSystem->GetHeight();
|
||||
float s1 = 0.0f, t1 = 0.0f, s2 = 1.0f, t2 = 1.0f;
|
||||
|
||||
idVec4 topLeft( x, y, s1, t1 );
|
||||
idVec4 topRight( x + w, y, s2, t1 );
|
||||
idVec4 bottomRight( x + w, y + h, s2, t2 );
|
||||
idVec4 bottomLeft( x, y + h, s1, t2 );
|
||||
|
||||
float z = 0.0f;
|
||||
|
||||
ALIGNTYPE16 idDrawVert localVerts[4];
|
||||
|
||||
localVerts[0].Clear();
|
||||
localVerts[0].xyz[0] = x;
|
||||
localVerts[0].xyz[1] = y;
|
||||
localVerts[0].xyz[2] = 0.f;
|
||||
localVerts[0].SetTexCoord( s1, t1 );
|
||||
localVerts[0].SetNativeOrderColor( currentColorNativeBytesOrder );
|
||||
localVerts[0].ClearColor2();
|
||||
|
||||
localVerts[1].Clear();
|
||||
localVerts[1].xyz[0] = x + w;
|
||||
localVerts[1].xyz[1] = y;
|
||||
localVerts[1].xyz[2] = 0.f;
|
||||
localVerts[1].SetTexCoord( s2, t1 );
|
||||
localVerts[1].SetNativeOrderColor( currentColorNativeBytesOrder );
|
||||
localVerts[1].ClearColor2();
|
||||
|
||||
localVerts[2].Clear();
|
||||
localVerts[2].xyz[0] = x + w;
|
||||
localVerts[2].xyz[1] = y + h;
|
||||
localVerts[2].xyz[2] = 0.f;
|
||||
localVerts[2].SetTexCoord( s2, t2 );
|
||||
localVerts[2].SetNativeOrderColor( currentColorNativeBytesOrder );
|
||||
localVerts[2].ClearColor2();
|
||||
|
||||
localVerts[3].Clear();
|
||||
localVerts[3].xyz[0] = x;
|
||||
localVerts[3].xyz[1] = y + h;
|
||||
localVerts[3].xyz[2] = 0.f;
|
||||
localVerts[3].SetTexCoord( s1, t2 );
|
||||
localVerts[3].SetNativeOrderColor( currentColorNativeBytesOrder );
|
||||
localVerts[3].ClearColor2();
|
||||
|
||||
WriteDrawVerts16( verts, localVerts, 4 );
|
||||
|
||||
for( int i = 0; i < 6; i += 2 )
|
||||
{
|
||||
WriteIndexPair( indexPointer + i, quadPicIndexes[i], quadPicIndexes[i + 1] );
|
||||
}
|
||||
}
|
||||
|
||||
void BasicTriangle::Render( nvrhi::IFramebuffer* framebuffer )
|
||||
{
|
||||
if( !pipeline )
|
||||
{
|
||||
nvrhi::GraphicsPipelineDesc psoDesc;
|
||||
psoDesc.VS = vertexShader;
|
||||
psoDesc.PS = pixelShader;
|
||||
psoDesc.inputLayout = inputLayout;
|
||||
psoDesc.bindingLayouts = { bindingLayout };
|
||||
psoDesc.primType = nvrhi::PrimitiveType::TriangleList;
|
||||
psoDesc.renderState.depthStencilState.depthTestEnable = false;
|
||||
//psoDesc.renderState.rasterState.frontCounterClockwise = true;
|
||||
|
||||
pipeline = GetDevice()->createGraphicsPipeline( psoDesc, framebuffer );
|
||||
}
|
||||
|
||||
commandList->open();
|
||||
commandList->beginMarker( "Basic" );
|
||||
|
||||
RenderFrontend();
|
||||
|
||||
nvrhi::utils::ClearColorAttachment( commandList, framebuffer, 0, nvrhi::Color( 0.f ) );
|
||||
|
||||
float w = framebuffer->getFramebufferInfo().width;
|
||||
float h = framebuffer->getFramebufferInfo().height;
|
||||
|
||||
idRenderMatrix projectionMatrix;
|
||||
{
|
||||
// orthographic matrix
|
||||
float xScale = 1.0f / w;
|
||||
float yScale = -1.0f / h; // flip y
|
||||
float zScale = 1.0f;
|
||||
|
||||
float projMat[16];
|
||||
projMat[0 * 4 + 0] = 2.f * xScale;
|
||||
projMat[0 * 4 + 1] = 0.0f;
|
||||
projMat[0 * 4 + 2] = 0.0f;
|
||||
projMat[0 * 4 + 3] = 0.0f;
|
||||
|
||||
projMat[1 * 4 + 0] = 0.0f;
|
||||
projMat[1 * 4 + 1] = 2.f * yScale;
|
||||
projMat[1 * 4 + 2] = 0.0f;
|
||||
projMat[1 * 4 + 3] = 0.0f;
|
||||
|
||||
projMat[2 * 4 + 0] = 0.0f;
|
||||
projMat[2 * 4 + 1] = 0.0f;
|
||||
projMat[2 * 4 + 2] = zScale;
|
||||
projMat[2 * 4 + 3] = 0.0f;
|
||||
|
||||
projMat[3 * 4 + 0] = -( w * xScale );
|
||||
projMat[3 * 4 + 1] = -( h * yScale );
|
||||
projMat[3 * 4 + 2] = 0.0f;
|
||||
projMat[3 * 4 + 3] = 1.0f;
|
||||
|
||||
float projMatT[16];
|
||||
R_MatrixTranspose( projMat, projMatT );
|
||||
|
||||
renderProgManager.SetRenderParm( renderParm_t::RENDERPARM_PROJMATRIX_X, &projMat[0] );
|
||||
renderProgManager.SetRenderParm( renderParm_t::RENDERPARM_PROJMATRIX_Y, &projMat[4] );
|
||||
renderProgManager.SetRenderParm( renderParm_t::RENDERPARM_PROJMATRIX_Z, &projMat[8] );
|
||||
renderProgManager.SetRenderParm( renderParm_t::RENDERPARM_PROJMATRIX_W, &projMat[12] );
|
||||
}
|
||||
|
||||
renderProgManager.CommitConstantBuffer( commandList );
|
||||
|
||||
idVertexBuffer* vertexBuffer;
|
||||
uint vertOffset = 0;
|
||||
{
|
||||
if( vertexCache.CacheIsStatic( vertexBlock ) )
|
||||
{
|
||||
vertexBuffer = &vertexCache.staticData.vertexBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint64 frameNum = ( int )( vertexBlock >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
|
||||
if( frameNum != ( ( vertexCache.currentFrame ) & VERTCACHE_FRAME_MASK ) )
|
||||
{
|
||||
idLib::Warning( "RB_DrawElementsWithCounters, vertexBuffer == NULL" );
|
||||
return;
|
||||
}
|
||||
vertexBuffer = &vertexCache.frameData[vertexCache.drawListNum].vertexBuffer;
|
||||
}
|
||||
vertOffset = ( uint )( vertexBlock >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
|
||||
}
|
||||
|
||||
vertCacheHandle_t indexBlockTemp = indexBlock + ( ( int64 )( 0 * sizeof( triIndex_t ) ) << VERTCACHE_OFFSET_SHIFT );
|
||||
|
||||
idIndexBuffer* indexBuffer;
|
||||
uint indexOffset = 0;
|
||||
if( vertexCache.CacheIsStatic( indexBlockTemp ) )
|
||||
{
|
||||
indexBuffer = &vertexCache.staticData.indexBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint64 frameNum = ( int )( indexBlockTemp >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
|
||||
if( frameNum != ( ( vertexCache.currentFrame ) & VERTCACHE_FRAME_MASK ) )
|
||||
{
|
||||
idLib::Warning( "RB_DrawElementsWithCounters, indexBuffer == NULL" );
|
||||
return;
|
||||
}
|
||||
indexBuffer = &vertexCache.frameData[vertexCache.drawListNum].indexBuffer;
|
||||
}
|
||||
indexOffset = ( uint )( indexBlock >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
|
||||
|
||||
nvrhi::GraphicsState state;
|
||||
state.bindings = { bindingSet };
|
||||
state.indexBuffer = { indexBuffer->GetAPIObject(), nvrhi::Format::R16_UINT, indexOffset };
|
||||
state.vertexBuffers = { { vertexBuffer->GetAPIObject(), 0, vertOffset } };
|
||||
state.pipeline = pipeline;
|
||||
state.framebuffer = framebuffer;
|
||||
state.viewport.addViewportAndScissorRect( framebuffer->getFramebufferInfo().getViewport() );
|
||||
|
||||
commandList->setGraphicsState( state );
|
||||
|
||||
nvrhi::DrawArguments args;
|
||||
args.vertexCount = 6;
|
||||
commandList->drawIndexed( args );
|
||||
|
||||
commandList->endMarker();
|
||||
commandList->close();
|
||||
|
||||
GetDevice()->executeCommandList( commandList );
|
||||
}
|
71
neo/renderer/RenderPass.h
Normal file
71
neo/renderer/RenderPass.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
#ifndef RENDER_PASS_H_
|
||||
#define RENDER_PASS_H_
|
||||
|
||||
#include "sys/DeviceManager.h"
|
||||
|
||||
class IRenderPass
|
||||
{
|
||||
private:
|
||||
DeviceManager* deviceManager;
|
||||
|
||||
public:
|
||||
explicit IRenderPass( DeviceManager* deviceManager )
|
||||
: deviceManager( deviceManager )
|
||||
{ }
|
||||
|
||||
virtual ~IRenderPass() = default;
|
||||
|
||||
virtual void RenderFrontend() { }
|
||||
virtual void Render( nvrhi::IFramebuffer* framebuffer ) { }
|
||||
virtual void Animate( float fElapsedTimeSeconds ) { }
|
||||
virtual void BackBufferResizing() { }
|
||||
virtual void BackBufferResized( const uint32_t width, const uint32_t height, const uint32_t sampleCount ) { }
|
||||
|
||||
[[nodiscard]] DeviceManager* GetDeviceManager() const
|
||||
{
|
||||
return deviceManager;
|
||||
}
|
||||
[[nodiscard]] nvrhi::IDevice* GetDevice() const
|
||||
{
|
||||
return deviceManager->GetDevice();
|
||||
}
|
||||
[[nodiscard]] uint32_t GetFrameIndex() const
|
||||
{
|
||||
return deviceManager->GetFrameIndex();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BasicTriangle : public IRenderPass
|
||||
{
|
||||
private:
|
||||
nvrhi::ShaderHandle vertexShader;
|
||||
nvrhi::ShaderHandle pixelShader;
|
||||
nvrhi::GraphicsPipelineHandle pipeline;
|
||||
nvrhi::CommandListHandle commandList;
|
||||
nvrhi::InputLayoutHandle inputLayout;
|
||||
nvrhi::BindingLayoutHandle bindingLayout;
|
||||
nvrhi::BindingSetHandle bindingSet;
|
||||
|
||||
vertCacheHandle_t vertexBlock;
|
||||
vertCacheHandle_t indexBlock;
|
||||
idDrawVert* vertexPointer;
|
||||
triIndex_t* indexPointer;
|
||||
const idMaterial* material;
|
||||
|
||||
int numVerts;
|
||||
int numIndexes;
|
||||
|
||||
idDrawVert* AllocVerts( int vertCount, triIndex_t* tempIndexes, int indexCount );
|
||||
|
||||
public:
|
||||
using IRenderPass::IRenderPass;
|
||||
|
||||
bool Init();
|
||||
void BackBufferResizing() override;
|
||||
void Animate( float fElapsedTimeSeconds ) override;
|
||||
void RenderFrontend() override;
|
||||
void Render( nvrhi::IFramebuffer* framebuffer ) override;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -35,6 +35,12 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#include "../framework/Common_local.h"
|
||||
#include "../imgui/BFGimgui.h"
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
#include <sys/DeviceManager.h>
|
||||
extern DeviceManager* deviceManager;
|
||||
#endif
|
||||
|
||||
|
||||
idRenderSystemLocal tr;
|
||||
idRenderSystem* renderSystem = &tr;
|
||||
|
||||
|
@ -307,9 +313,9 @@ void idRenderSystemLocal::DrawFilled( const idVec4& color, float x, float y, flo
|
|||
idRenderSystemLocal::DrawStretchPic
|
||||
=============
|
||||
*/
|
||||
void idRenderSystemLocal::DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial* material )
|
||||
void idRenderSystemLocal::DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial* material, float z )
|
||||
{
|
||||
DrawStretchPic( idVec4( x, y, s1, t1 ), idVec4( x + w, y, s2, t1 ), idVec4( x + w, y + h, s2, t2 ), idVec4( x, y + h, s1, t2 ), material );
|
||||
DrawStretchPic( idVec4( x, y, s1, t1 ), idVec4( x + w, y, s2, t1 ), idVec4( x + w, y + h, s2, t2 ), idVec4( x, y + h, s1, t2 ), material, z );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -318,7 +324,7 @@ idRenderSystemLocal::DrawStretchPic
|
|||
=============
|
||||
*/
|
||||
static triIndex_t quadPicIndexes[6] = { 3, 0, 2, 2, 0, 1 };
|
||||
void idRenderSystemLocal::DrawStretchPic( const idVec4& topLeft, const idVec4& topRight, const idVec4& bottomRight, const idVec4& bottomLeft, const idMaterial* material )
|
||||
void idRenderSystemLocal::DrawStretchPic( const idVec4& topLeft, const idVec4& topRight, const idVec4& bottomRight, const idVec4& bottomLeft, const idMaterial* material, float z )
|
||||
{
|
||||
if( !IsInitialized() )
|
||||
{
|
||||
|
@ -340,6 +346,7 @@ void idRenderSystemLocal::DrawStretchPic( const idVec4& topLeft, const idVec4& t
|
|||
localVerts[0].Clear();
|
||||
localVerts[0].xyz[0] = topLeft.x;
|
||||
localVerts[0].xyz[1] = topLeft.y;
|
||||
localVerts[0].xyz[2] = z;
|
||||
localVerts[0].SetTexCoord( topLeft.z, topLeft.w );
|
||||
localVerts[0].SetNativeOrderColor( currentColorNativeBytesOrder );
|
||||
localVerts[0].ClearColor2();
|
||||
|
@ -347,6 +354,7 @@ void idRenderSystemLocal::DrawStretchPic( const idVec4& topLeft, const idVec4& t
|
|||
localVerts[1].Clear();
|
||||
localVerts[1].xyz[0] = topRight.x;
|
||||
localVerts[1].xyz[1] = topRight.y;
|
||||
localVerts[1].xyz[2] = z;
|
||||
localVerts[1].SetTexCoord( topRight.z, topRight.w );
|
||||
localVerts[1].SetNativeOrderColor( currentColorNativeBytesOrder );
|
||||
localVerts[1].ClearColor2();
|
||||
|
@ -354,6 +362,7 @@ void idRenderSystemLocal::DrawStretchPic( const idVec4& topLeft, const idVec4& t
|
|||
localVerts[2].Clear();
|
||||
localVerts[2].xyz[0] = bottomRight.x;
|
||||
localVerts[2].xyz[1] = bottomRight.y;
|
||||
localVerts[2].xyz[2] = z;
|
||||
localVerts[2].SetTexCoord( bottomRight.z, bottomRight.w );
|
||||
localVerts[2].SetNativeOrderColor( currentColorNativeBytesOrder );
|
||||
localVerts[2].ClearColor2();
|
||||
|
@ -361,6 +370,7 @@ void idRenderSystemLocal::DrawStretchPic( const idVec4& topLeft, const idVec4& t
|
|||
localVerts[3].Clear();
|
||||
localVerts[3].xyz[0] = bottomLeft.x;
|
||||
localVerts[3].xyz[1] = bottomLeft.y;
|
||||
localVerts[3].xyz[2] = z;
|
||||
localVerts[3].SetTexCoord( bottomLeft.z, bottomLeft.w );
|
||||
localVerts[3].SetNativeOrderColor( currentColorNativeBytesOrder );
|
||||
localVerts[3].ClearColor2();
|
||||
|
@ -623,7 +633,6 @@ const emptyCommand_t* idRenderSystemLocal::SwapCommandBuffers(
|
|||
performanceCounters_t* pc
|
||||
)
|
||||
{
|
||||
|
||||
SwapCommandBuffers_FinishRendering( frontEndMicroSec, backEndMicroSec, shadowMicroSec, gpuMicroSec, bc, pc );
|
||||
|
||||
return SwapCommandBuffers_FinishCommandBuffers();
|
||||
|
@ -674,7 +683,7 @@ void idRenderSystemLocal::SwapCommandBuffers_FinishRendering(
|
|||
backend.GL_BlockingSwapBuffers();
|
||||
}
|
||||
|
||||
#if defined(USE_VULKAN)
|
||||
#if defined( USE_NVRHI ) || defined( USE_VULKAN )
|
||||
if( gpuMicroSec != NULL )
|
||||
{
|
||||
*gpuMicroSec = backend.pc.gpuMicroSec;
|
||||
|
@ -887,8 +896,13 @@ const emptyCommand_t* idRenderSystemLocal::SwapCommandBuffers_FinishCommandBuffe
|
|||
// PC
|
||||
UpdateStereo3DMode();
|
||||
|
||||
if( !commandList )
|
||||
{
|
||||
commandList = deviceManager->GetDevice()->createCommandList();
|
||||
}
|
||||
|
||||
// prepare the new command buffer
|
||||
guiModel->BeginFrame();
|
||||
guiModel->BeginFrame( commandList );
|
||||
|
||||
//------------------------------
|
||||
// Make sure that geometry used by code is present in the buffer cache.
|
||||
|
@ -899,10 +913,10 @@ const emptyCommand_t* idRenderSystemLocal::SwapCommandBuffers_FinishCommandBuffe
|
|||
// scene generation, the basic surfaces needed for drawing the buffers will
|
||||
// always be present.
|
||||
//------------------------------
|
||||
R_InitDrawSurfFromTri( tr.unitSquareSurface_, *tr.unitSquareTriangles );
|
||||
R_InitDrawSurfFromTri( tr.zeroOneCubeSurface_, *tr.zeroOneCubeTriangles );
|
||||
R_InitDrawSurfFromTri( tr.zeroOneSphereSurface_, *tr.zeroOneSphereTriangles );
|
||||
R_InitDrawSurfFromTri( tr.testImageSurface_, *tr.testImageTriangles );
|
||||
R_InitDrawSurfFromTri( tr.unitSquareSurface_, *tr.unitSquareTriangles, commandList );
|
||||
R_InitDrawSurfFromTri( tr.zeroOneCubeSurface_, *tr.zeroOneCubeTriangles, commandList );
|
||||
R_InitDrawSurfFromTri( tr.zeroOneSphereSurface_, *tr.zeroOneSphereTriangles, commandList );
|
||||
R_InitDrawSurfFromTri( tr.testImageSurface_, *tr.testImageTriangles, commandList );
|
||||
|
||||
// Reset render crop to be the full screen
|
||||
renderCrops[0].x1 = 0;
|
||||
|
@ -1053,6 +1067,53 @@ void idRenderSystemLocal::CropRenderSize( int width, int height )
|
|||
current.y2 = previous.y2;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idRenderSystemLocal::CropRenderSize
|
||||
================
|
||||
*/
|
||||
void idRenderSystemLocal::CropRenderSize( int x, int y, int width, int height )
|
||||
{
|
||||
if( !IsInitialized() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// close any gui drawing before changing the size
|
||||
guiModel->EmitFullScreen();
|
||||
guiModel->Clear();
|
||||
|
||||
|
||||
if( width < 1 || height < 1 )
|
||||
{
|
||||
common->Error( "CropRenderSize: bad sizes" );
|
||||
}
|
||||
|
||||
if( common->WriteDemo() )
|
||||
{
|
||||
common->WriteDemo()->WriteInt( DS_RENDER );
|
||||
common->WriteDemo()->WriteInt( DC_CROP_RENDER );
|
||||
common->WriteDemo()->WriteInt( width );
|
||||
common->WriteDemo()->WriteInt( height );
|
||||
|
||||
if( r_showDemo.GetBool() )
|
||||
{
|
||||
common->Printf( "write DC_CROP_RENDER\n" );
|
||||
}
|
||||
}
|
||||
|
||||
idScreenRect& previous = renderCrops[currentRenderCrop];
|
||||
|
||||
currentRenderCrop++;
|
||||
|
||||
idScreenRect& current = renderCrops[currentRenderCrop];
|
||||
|
||||
current.x1 = x;
|
||||
current.x2 = previous.x1 + width - 1;
|
||||
current.y1 = y;
|
||||
current.y2 = previous.y2;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idRenderSystemLocal::UnCrop
|
||||
|
|
|
@ -354,7 +354,7 @@ public:
|
|||
{
|
||||
DrawStretchPic( rect.x, rect.y, rect.z, rect.w, st.x, st.y, st.z, st.w, material, z );
|
||||
}
|
||||
virtual void DrawStretchPic( const idVec4& topLeft, const idVec4& topRight, const idVec4& bottomRight, const idVec4& bottomLeft, const idMaterial* material ) = 0;
|
||||
virtual void DrawStretchPic( const idVec4& topLeft, const idVec4& topRight, const idVec4& bottomRight, const idVec4& bottomLeft, const idMaterial* material, float z = 0.0f ) = 0;
|
||||
virtual void DrawStretchTri( const idVec2& p1, const idVec2& p2, const idVec2& p3, const idVec2& t1, const idVec2& t2, const idVec2& t3, const idMaterial* material ) = 0;
|
||||
virtual idDrawVert* AllocTris( int numVerts, const triIndex_t* indexes, int numIndexes, const idMaterial* material, const stereoDepthType_t stereoType = STEREO_DEPTH_TYPE_NONE ) = 0;
|
||||
|
||||
|
|
|
@ -1966,6 +1966,10 @@ void idRenderWorldLocal::GenerateAllInteractions()
|
|||
int size = interactionTableWidth * interactionTableHeight * sizeof( *interactionTable );
|
||||
interactionTable = ( idInteraction** )R_ClearedStaticAlloc( size );
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
tr.commandList->open();
|
||||
#endif
|
||||
|
||||
// iterate through all lights
|
||||
int count = 0;
|
||||
for( int i = 0; i < this->lightDefs.Num(); i++ )
|
||||
|
@ -2012,13 +2016,18 @@ void idRenderWorldLocal::GenerateAllInteractions()
|
|||
count++;
|
||||
|
||||
// the interaction may create geometry
|
||||
inter->CreateStaticInteraction();
|
||||
inter->CreateStaticInteraction( tr.commandList );
|
||||
}
|
||||
}
|
||||
|
||||
session->Pump();
|
||||
}
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
tr.commandList->close();
|
||||
deviceManager->GetDevice()->executeCommandList( tr.commandList );
|
||||
#endif
|
||||
|
||||
int end = Sys_Milliseconds();
|
||||
int msec = end - start;
|
||||
|
||||
|
|
|
@ -35,6 +35,11 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#include "CmdlineProgressbar.h"
|
||||
#include "../framework/Common_local.h" // commonLocal.WaitGameThread();
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
#include <sys/DeviceManager.h>
|
||||
extern DeviceManager* deviceManager;
|
||||
#endif
|
||||
|
||||
|
||||
#define LGRID_FILE_EXT "lightgrid"
|
||||
#define LGRID_BINARYFILE_EXT "blightgrid"
|
||||
|
@ -414,6 +419,12 @@ void idRenderWorldLocal::LoadLightGridImages()
|
|||
|
||||
idStr filename;
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
nvrhi::CommandListHandle commandList = deviceManager->GetDevice()->createCommandList();
|
||||
|
||||
commandList->open();
|
||||
#endif
|
||||
|
||||
// try to load existing lightgrid image data
|
||||
for( int i = 0; i < numPortalAreas; i++ )
|
||||
{
|
||||
|
@ -429,6 +440,12 @@ void idRenderWorldLocal::LoadLightGridImages()
|
|||
area->lightGrid.irradianceImage->Reload( true, commandList );
|
||||
}
|
||||
}
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
commandList->close();
|
||||
|
||||
deviceManager->GetDevice()->executeCommandList( commandList );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -418,7 +418,7 @@ void LightEditor::LoadLightTextures()
|
|||
idImage* editorImage = mat->GetLightEditorImage();
|
||||
if( !editorImage->IsLoaded() )
|
||||
{
|
||||
editorImage->ActuallyLoadImage( false );
|
||||
editorImage->DeferredLoadImage();
|
||||
}
|
||||
|
||||
if( !editorImage->IsDefaulted() )
|
||||
|
|
Loading…
Reference in a new issue