mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-11-24 21:11:47 +00:00
added the Cinematic Rendering Pipeline
This commit is contained in:
parent
0884a857da
commit
ad3f942a8d
102 changed files with 9129 additions and 1649 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -8,7 +8,6 @@
|
|||
*.idb
|
||||
code/qcommon/git.h
|
||||
code/win32/winquake.res
|
||||
code/renderer/hlsl/*.h
|
||||
makefiles/windows_vs*/*sdf
|
||||
makefiles/*/obj
|
||||
.build
|
||||
|
|
|
@ -65,21 +65,55 @@ add: r_shadingRate <0 to 6> (default: 0) sets the variable-rate shading (VRS) mo
|
|||
prefer horizontal subsampling as many maps have textures with thin horizontal lines
|
||||
which become an aliased mess when vertically subsampled
|
||||
|
||||
add: Cinematic Rendering Pipeline CVars
|
||||
depth of field:
|
||||
crp_dof <0|1|2> (default: 1) selects the depth of field mode
|
||||
0 - disabled
|
||||
1 - scatter-as-gather
|
||||
2 - accumulation
|
||||
crp_dof_overlay <0|1|2> (default: 0) draws a debug overlay mode
|
||||
0 - disabled
|
||||
1 - colorized blur
|
||||
2 - focus plane
|
||||
crp_dof_blades <0 to 16> (default: 6) is the aperture's blade count
|
||||
set to less than 3 for a disk shape
|
||||
crp_dof_angle <0 to 360> (default: 20) is the aperture's angle, in degrees
|
||||
scatter-as-gather depth of field (fast, doesn't handle transparency properly):
|
||||
crp_gatherDof_focusNearDist <1 to 2048> (default: 192) is the near-field's focus distance
|
||||
crp_gatherDof_focusNearRange <1 to 2048> (default: 256) is the near-field's focus range
|
||||
crp_gatherDof_focusFarDist <1 to 2048> (default: 512) is the far-field's focus distance
|
||||
crp_gatherDof_focusFarRange <1 to 2048> (default: 384) is the far-field's focus range
|
||||
crp_gatherDof_brightness <0 to 8> (default: 2) is the blur brightness' weight
|
||||
accumulation depth of field (extremely slow, looks perfect with enough samples):
|
||||
crp_accumDof_focusDist <2 to 2048> (default: 256) is the focus distance
|
||||
crp_accumDof_radius <0.001 to 20> (default: 0.1) is the aperture radius in world units
|
||||
crp_accumDof_samples <1 to 12> (default: 2) is per-axis sampling density
|
||||
density N means (2N + 1)^2 scene renders in total, so be careful or you'll trigger TDR
|
||||
crp_accumDof_preview <0|1|2> (default: 0) selects the real-time preview mode
|
||||
0 - disabled
|
||||
1 - 1/4 pixel count, 9 samples total
|
||||
2 - 1/16 pixel count, 25 samples total
|
||||
|
||||
chg: dropped 32-bit support
|
||||
|
||||
chg: dropped Linux/FreeBSD client
|
||||
|
||||
chg: Windows support is limited to 10 and 11
|
||||
|
||||
chg: much improved rendering:
|
||||
- removed all Direct3D 11 and OpenGL code
|
||||
- rendering with Direct3D 12 (improved performance and better worst case input latency)
|
||||
chg: reworked renderer with 2 new rendering pipelines
|
||||
- removed all the Direct3D 11 and OpenGL code, now using Direct3D 12
|
||||
- much improved input latency when V-Sync is enabled
|
||||
- improved frame-time consistency
|
||||
- surfaces are sorted and rendered more efficiently
|
||||
- improved frame-time consistency ("frame pacing")
|
||||
- fog handling has been completely overhauled (faster, simpler, decoupled from surfaces)
|
||||
- MSAA and alpha-to-coverage have been removed
|
||||
- added SMAA for anti-aliasing (gamma-corrected and not applied to UI for best results)
|
||||
- Gameplay Rendering Pipeline (GRP)
|
||||
- improved performance and better worst case input latency
|
||||
- added SMAA for anti-aliasing (gamma-corrected and not applied to UI for best results)
|
||||
- added VRS (Variable Rate Shading) support
|
||||
- Cinematic Rendering Pipeline (CRP)
|
||||
- order-independent transparency
|
||||
- depth of field (scatter-as-gather or accumulation)
|
||||
- all corresponding CVars have the "crp_" prefix
|
||||
|
||||
chg: removed cl_drawMouseLag, r_backend, r_frameSleep, r_gpuMipGen, r_alphaToCoverage, r_alphaToCoverageMipBoost
|
||||
removed r_d3d11_syncOffsets, r_d3d11_presentMode, r_gl3_geoStream, r_ignoreGLErrors, r_finish, r_khr_debug
|
||||
|
|
|
@ -1591,12 +1591,35 @@ static void CL_CheckUserinfo()
|
|||
}
|
||||
|
||||
|
||||
static void CL_CheckCRP()
|
||||
{
|
||||
// demo playback and listen servers are always OK
|
||||
if ( Cvar_VariableIntegerValue( "r_pipeline" ) != 1 ||
|
||||
CL_DemoPlaying() ||
|
||||
Cvar_VariableIntegerValue( "sv_running" ) )
|
||||
return;
|
||||
|
||||
switch ( cls.state ) {
|
||||
case CA_CHALLENGING:
|
||||
case CA_CONNECTING:
|
||||
case CA_CONNECTED:
|
||||
Cbuf_AddText( "r_pipeline 0\nvid_restart\nreconnect\n" );
|
||||
Com_Printf( "^3WARNING: switched to GRP (r_pipeline 0) for online play\n" );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CL_Frame( int msec )
|
||||
{
|
||||
if ( !com_cl_running->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
CL_CheckCRP();
|
||||
|
||||
if ( cls.cddialog ) {
|
||||
// bring up the cd error dialog if needed
|
||||
cls.cddialog = qfalse;
|
||||
|
@ -3014,3 +3037,9 @@ void CL_SetMenuData( qboolean typeOnly )
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
qbool CL_DemoPlaying()
|
||||
{
|
||||
return clc.demoplaying;
|
||||
}
|
||||
|
|
|
@ -1222,10 +1222,3 @@ qbool UI_GameCommand()
|
|||
{
|
||||
return (uivm && VM_Call( uivm, UI_CONSOLE_COMMAND, cls.realtime ));
|
||||
}
|
||||
|
||||
|
||||
qbool CL_DemoPlaying()
|
||||
{
|
||||
return clc.demoplaying;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include "q_shared.h"
|
||||
|
||||
|
||||
const vec3_t vec2_zero = { 0, 0 };
|
||||
const vec3_t vec2_one = { 1, 1 };
|
||||
const vec3_t vec3_origin = { 0, 0, 0 };
|
||||
const vec3_t vec3_zero = { 0, 0, 0 };
|
||||
const vec3_t vec3_one = { 1, 1, 1 };
|
||||
const vec4_t vec4_zero = { 0, 0, 0, 0 };
|
||||
const vec4_t vec4_one = { 1, 1, 1, 1 };
|
||||
|
||||
#if defined(Q3_VM) // lcc can't cope with "const vec3_t []"
|
||||
vec3_t axisDefault[3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
|
||||
#else
|
||||
|
|
|
@ -178,6 +178,13 @@ typedef int clipHandle_t;
|
|||
#define STRINGIZE_NE(x) #x // no expansion
|
||||
#define STRINGIZE(x) STRINGIZE_NE(x) // with expansion
|
||||
|
||||
// #define A 42
|
||||
// #define B 69
|
||||
// CONCAT_NE(A, B) -> AB
|
||||
// CONCAT(A, B) -> 4269
|
||||
#define CONCAT_NE(x, y) x ## y // no expansion
|
||||
#define CONCAT(x, y) CONCAT_NE(x, y) // with expansion
|
||||
|
||||
// angle indexes
|
||||
#define PITCH 0 // up / down
|
||||
#define YAW 1 // left / right
|
||||
|
@ -259,13 +266,25 @@ typedef float vec_t;
|
|||
typedef vec_t vec2_t[2];
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
extern const vec3_t vec2_zero;
|
||||
extern const vec3_t vec2_one;
|
||||
extern const vec3_t vec3_origin;
|
||||
extern const vec3_t vec3_zero;
|
||||
extern const vec3_t vec3_one;
|
||||
extern const vec4_t vec4_zero;
|
||||
extern const vec4_t vec4_one;
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846f // matches value in gcc v2 math.h
|
||||
#endif
|
||||
|
||||
#define M_PI_D2 (M_PI / 2.0f)
|
||||
#define M_PI_D4 (M_PI / 4.0f)
|
||||
#define M_PI_D8 (M_PI / 8.0f)
|
||||
#define M_PI_M2 (M_PI * 2.0f)
|
||||
#define M_PI_M4 (M_PI * 4.0f)
|
||||
#define M_PI_M8 (M_PI * 8.0f)
|
||||
|
||||
|
||||
// all drawing is done to a 640*480 virtual screen size
|
||||
// and will be automatically scaled to the real resolution
|
||||
|
|
2
code/renderer/compshaders/.gitignore
vendored
Normal file
2
code/renderer/compshaders/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*.h
|
||||
*.temp
|
366
code/renderer/crp_dof_accum.cpp
Normal file
366
code/renderer/crp_dof_accum.cpp
Normal file
|
@ -0,0 +1,366 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - accumulation depth of field
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
namespace dof_accum
|
||||
{
|
||||
#include "compshaders/crp/accumdof_accum_vs.h"
|
||||
#include "compshaders/crp/accumdof_accum_ps.h"
|
||||
}
|
||||
namespace dof_norm
|
||||
{
|
||||
#include "compshaders/crp/accumdof_norm_vs.h"
|
||||
#include "compshaders/crp/accumdof_norm_ps.h"
|
||||
}
|
||||
namespace dof_debug
|
||||
{
|
||||
#include "compshaders/crp/accumdof_debug_vs.h"
|
||||
#include "compshaders/crp/accumdof_debug_ps.h"
|
||||
}
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
struct DOFAccumRC
|
||||
{
|
||||
uint32_t textureIndex;
|
||||
};
|
||||
|
||||
struct DOFNormRC
|
||||
{
|
||||
uint32_t textureIndex;
|
||||
};
|
||||
|
||||
struct DOFDebugRC
|
||||
{
|
||||
float mvp[16]; // displaced view, to project to CS
|
||||
float invMvp[16]; // main view, to unproject to WS
|
||||
uint32_t colorTextureIndex;
|
||||
uint32_t depthTextureIndex;
|
||||
uint32_t debugMode; // 1: colorized coc, 2: constant intensity far field
|
||||
uint32_t tcScale;
|
||||
float focusDist;
|
||||
float linearDepthA; // main view, to unproject to WS
|
||||
float linearDepthB;
|
||||
float maxNearCocCS;
|
||||
float maxFarCocCS;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
// the input is in [0,1]^2, the output polygon is centered at the origin
|
||||
static void MapUnitSquareToPolygon(const vec2_t square01, float apertureBladeCount, float apertureAngleRad, vec2_t polygon)
|
||||
{
|
||||
// needed to avoid inf/nan propagation through theta for samples
|
||||
// that are exactly in the middle of the quad on either axis
|
||||
// (i.e. square.x|y == 0.5f gets remapped to 0.0f)
|
||||
const float epsilon = 0.000001f;
|
||||
|
||||
// morph into a square in [-1,1]^2
|
||||
vec2_t square;
|
||||
square[0] = square01[0] * 2.0f - 1.0f;
|
||||
square[1] = square01[1] * 2.0f - 1.0f;
|
||||
|
||||
// morph the square into a disk
|
||||
// "A Low Distortion Map Between Disk and Square" by Peter Shirley and Kenneth Chiu
|
||||
float radius, angle;
|
||||
vec2_t square2;
|
||||
square2[0] = square[0] * square[0];
|
||||
square2[1] = square[1] * square[1];
|
||||
if(square2[0] > square2[1])
|
||||
{
|
||||
// left and right quadrants
|
||||
radius = square[0];
|
||||
angle = (square[1] * M_PI_D4) / (square[0] + epsilon);
|
||||
}
|
||||
else
|
||||
{
|
||||
// top and bottom quadrants
|
||||
radius = square[1];
|
||||
angle = M_PI_D2 - (square[0] * M_PI_D4) / (square[1] + epsilon);
|
||||
}
|
||||
if(radius < 0.0f)
|
||||
{
|
||||
radius = -radius;
|
||||
angle += M_PI;
|
||||
}
|
||||
|
||||
// morph the disk into a polygon
|
||||
// "Graphics Gems from CryENGINE 3" by Tiago Sousa
|
||||
const float edgeCount = apertureBladeCount;
|
||||
if(edgeCount >= 3.0f)
|
||||
{
|
||||
const float num = cosf(M_PI / edgeCount);
|
||||
const float den0 = M_PI_M2 / edgeCount;
|
||||
const float den1 = (angle * edgeCount + M_PI) / M_PI_M2;
|
||||
const float den = angle - (den0 * floorf(den1));
|
||||
radius *= num / cosf(den);
|
||||
angle += apertureAngleRad;
|
||||
}
|
||||
|
||||
polygon[0] = cosf(angle) * radius;
|
||||
polygon[1] = sinf(angle) * radius;
|
||||
}
|
||||
|
||||
static int GetResolutionScale()
|
||||
{
|
||||
switch(crp_accumDof_preview->integer)
|
||||
{
|
||||
case 0: return 1;
|
||||
case 1: return 2;
|
||||
case 2: return 4;
|
||||
default: Q_assert(0); return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AccumDepthOfField::Init()
|
||||
{
|
||||
{
|
||||
GraphicsPipelineDesc desc("DOF Accumulate");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(dof_accum::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(dof_accum::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE, crp.renderTargetFormat);
|
||||
accumPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("DOF Normalize");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(dof_norm::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(dof_norm::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
normPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("DOF Debug");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(dof_debug::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(dof_debug::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
debugPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("DOF accumulation", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit;
|
||||
Vector4Clear(desc.clearColor);
|
||||
desc.usePreferredClearValue = true;
|
||||
desc.committedResource = true;
|
||||
desc.format = crp.renderTargetFormat;
|
||||
desc.shortLifeTime = true;
|
||||
accumTexture = CreateTexture(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void AccumDepthOfField::Begin(const drawSceneViewCommand_t& cmd)
|
||||
{
|
||||
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
||||
const TextureBarrier texBarriers[] =
|
||||
{
|
||||
TextureBarrier(accumTexture, ResourceStates::RenderTargetBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(texBarriers), texBarriers);
|
||||
|
||||
CmdClearColorTarget(accumTexture, vec4_zero);
|
||||
|
||||
// project a point a few units in front of the main view onto a viewpoint with maximum displacement
|
||||
// the distance to the clip space center (i.e. the 2D origin) is the maximum expected CoC
|
||||
vec3_t testPoint;
|
||||
VectorMA(cmd.viewParms.world.viewOrigin, 16.0f, cmd.viewParms.orient.axis[0], testPoint);
|
||||
drawSceneViewCommand_t newCmd;
|
||||
FixCommand(newCmd, cmd, 0, 0);
|
||||
vec4_t eye, clip;
|
||||
R_TransformModelToClip(testPoint, newCmd.viewParms.world.modelMatrix, newCmd.viewParms.projectionMatrix, eye, clip);
|
||||
Vector4Scale(clip, 1.0f / clip[3], clip);
|
||||
maxNearCocCS = sqrtf(clip[0] * clip[0] + clip[1] * clip[1]);
|
||||
|
||||
// same thing for a point far away
|
||||
VectorMA(cmd.viewParms.world.viewOrigin, 69420.0f, cmd.viewParms.orient.axis[0], testPoint);
|
||||
FixCommand(newCmd, cmd, 0, 0);
|
||||
R_TransformModelToClip(testPoint, newCmd.viewParms.world.modelMatrix, newCmd.viewParms.projectionMatrix, eye, clip);
|
||||
Vector4Scale(clip, 1.0f / clip[3], clip);
|
||||
maxFarCocCS = sqrtf(clip[0] * clip[0] + clip[1] * clip[1]);
|
||||
}
|
||||
|
||||
uint32_t AccumDepthOfField::GetSampleCount()
|
||||
{
|
||||
switch(crp_accumDof_preview->integer)
|
||||
{
|
||||
case 1: return 3;
|
||||
case 2: return 5;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return 2 * crp_accumDof_samples->integer + 1;
|
||||
}
|
||||
|
||||
void AccumDepthOfField::FixCommand(drawSceneViewCommand_t& newCmd, const drawSceneViewCommand_t& cmd, uint32_t x, uint32_t y)
|
||||
{
|
||||
const float radius = crp_accumDof_radius->value;
|
||||
const float tcScale = 1.0f / (float)(GetSampleCount() - 1);
|
||||
|
||||
vec2_t square01;
|
||||
square01[0] = x * tcScale;
|
||||
square01[1] = y * tcScale;
|
||||
vec2_t polygon;
|
||||
MapUnitSquareToPolygon(square01, crp_dof_blades->value, DEG2RAD(crp_dof_angle->value), polygon);
|
||||
|
||||
// 0=forward, 1=left, 2=up
|
||||
vec3_t axis[3];
|
||||
VectorCopy(cmd.viewParms.orient.axis[0], axis[0]);
|
||||
VectorCopy(cmd.viewParms.orient.axis[1], axis[1]);
|
||||
VectorCopy(cmd.viewParms.orient.axis[2], axis[2]);
|
||||
|
||||
vec3_t origin;
|
||||
VectorMA(cmd.viewParms.world.viewOrigin, radius * polygon[0], axis[1], origin);
|
||||
VectorMA(origin, radius * polygon[1], axis[2], origin);
|
||||
|
||||
vec3_t focusPoint;
|
||||
VectorMA(cmd.viewParms.world.viewOrigin, crp_accumDof_focusDist->value, axis[0], focusPoint);
|
||||
VectorSubtract(focusPoint, origin, axis[0]); // forward
|
||||
VectorNormalize(axis[0]);
|
||||
CrossProduct(axis[2], axis[0], axis[1]); // left
|
||||
VectorNormalize(axis[1]);
|
||||
CrossProduct(axis[0], axis[1], axis[2]); // up
|
||||
VectorNormalize(axis[2]);
|
||||
|
||||
newCmd = cmd;
|
||||
VectorCopy(origin, newCmd.viewParms.orient.origin);
|
||||
VectorCopy(origin, newCmd.viewParms.world.viewOrigin);
|
||||
R_CreateWorldModelMatrix(origin, axis, newCmd.viewParms.world.modelMatrix);
|
||||
newCmd.viewParms.viewportWidth /= GetResolutionScale();
|
||||
newCmd.viewParms.viewportHeight /= GetResolutionScale();
|
||||
|
||||
if(x == 0 && y == 0)
|
||||
{
|
||||
memcpy(modelViewMatrix, newCmd.viewParms.world.modelMatrix, sizeof(modelViewMatrix));
|
||||
memcpy(projMatrix, newCmd.viewParms.projectionMatrix, sizeof(projMatrix));
|
||||
}
|
||||
}
|
||||
|
||||
void AccumDepthOfField::Accumulate()
|
||||
{
|
||||
srp.renderMode = RenderMode::None;
|
||||
|
||||
SCOPED_RENDER_PASS("DOF Accum", 0.5f, 1.0f, 0.5f);
|
||||
|
||||
const TextureBarrier texBarriers[] =
|
||||
{
|
||||
TextureBarrier(crp.renderTarget, ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(accumTexture, ResourceStates::RenderTargetBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(texBarriers), texBarriers);
|
||||
|
||||
DOFAccumRC rc = {};
|
||||
rc.textureIndex = GetTextureIndexSRV(crp.renderTarget);
|
||||
|
||||
CmdBindRenderTargets(1, &accumTexture, NULL);
|
||||
CmdBindPipeline(accumPipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
|
||||
}
|
||||
|
||||
void AccumDepthOfField::Normalize()
|
||||
{
|
||||
srp.renderMode = RenderMode::None;
|
||||
|
||||
{
|
||||
SCOPED_RENDER_PASS("DOF Norm", 0.5f, 1.0f, 0.5f);
|
||||
|
||||
const TextureBarrier texBarriers[] =
|
||||
{
|
||||
TextureBarrier(accumTexture, ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.renderTarget, ResourceStates::RenderTargetBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(texBarriers), texBarriers);
|
||||
|
||||
DOFNormRC rc = {};
|
||||
rc.textureIndex = GetTextureIndexSRV(accumTexture);
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
CmdBindPipeline(normPipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
|
||||
if(crp_accumDof_preview->integer)
|
||||
{
|
||||
crp.SwapRenderTargets();
|
||||
const float scale = 1.0f / (float)GetResolutionScale();
|
||||
const vec2_t tcScale = { scale, scale };
|
||||
crp.Blit(crp.GetWriteRenderTarget(), crp.GetReadRenderTarget(), "DOF Upscale", true, tcScale, vec2_zero);
|
||||
}
|
||||
}
|
||||
|
||||
void AccumDepthOfField::DrawDebug()
|
||||
{
|
||||
if(crp_dof_overlay->integer == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
srp.renderMode = RenderMode::None;
|
||||
|
||||
SCOPED_RENDER_PASS("DOF Debug", 0.5f, 1.0f, 0.5f);
|
||||
|
||||
crp.SwapRenderTargets();
|
||||
const TextureBarrier texBarriers[] =
|
||||
{
|
||||
TextureBarrier(crp.GetReadRenderTarget(), ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.depthTexture, ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.GetWriteRenderTarget(), ResourceStates::RenderTargetBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(texBarriers), texBarriers);
|
||||
|
||||
float mvp[16];
|
||||
DOFDebugRC rc = {};
|
||||
rc.colorTextureIndex = GetTextureIndexSRV(crp.GetReadRenderTarget());
|
||||
rc.depthTextureIndex = GetTextureIndexSRV(crp.depthTexture);
|
||||
rc.debugMode = crp_dof_overlay->integer;
|
||||
rc.focusDist = crp_accumDof_focusDist->value;
|
||||
rc.maxNearCocCS = maxNearCocCS;
|
||||
rc.maxFarCocCS = maxFarCocCS;
|
||||
rc.tcScale = GetResolutionScale();
|
||||
R_MultMatrix(modelViewMatrix, projMatrix, rc.mvp);
|
||||
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
||||
R_MultMatrix(backEnd.viewParms.world.modelMatrix, backEnd.viewParms.projectionMatrix, mvp);
|
||||
R_InvMatrix(mvp, rc.invMvp);
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
CmdBindPipeline(debugPipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
479
code/renderer/crp_dof_gather.cpp
Normal file
479
code/renderer/crp_dof_gather.cpp
Normal file
|
@ -0,0 +1,479 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - scatter-as-gather depth of field
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
namespace debug
|
||||
{
|
||||
#include "compshaders/crp/gatherdof_debug_vs.h"
|
||||
#include "compshaders/crp/gatherdof_debug_ps.h"
|
||||
}
|
||||
namespace split
|
||||
{
|
||||
#include "compshaders/crp/gatherdof_split.h"
|
||||
}
|
||||
namespace near_coc_tile_gen
|
||||
{
|
||||
#include "compshaders/crp/gatherdof_coc_tile_gen.h"
|
||||
}
|
||||
namespace near_coc_tile_max
|
||||
{
|
||||
#include "compshaders/crp/gatherdof_coc_tile_max.h"
|
||||
}
|
||||
namespace blur
|
||||
{
|
||||
#include "compshaders/crp/gatherdof_blur.h"
|
||||
}
|
||||
namespace fill
|
||||
{
|
||||
#include "compshaders/crp/gatherdof_fill.h"
|
||||
}
|
||||
namespace combine
|
||||
{
|
||||
#include "compshaders/crp/gatherdof_combine_vs.h"
|
||||
#include "compshaders/crp/gatherdof_combine_ps.h"
|
||||
}
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
struct DOFDebugRC
|
||||
{
|
||||
uint32_t colorTextureIndex;
|
||||
uint32_t depthTextureIndex;
|
||||
uint32_t debugMode;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float focusNearMin;
|
||||
float focusNearMax;
|
||||
float focusFarMin;
|
||||
float focusFarMax;
|
||||
float focusDist;
|
||||
};
|
||||
|
||||
struct DOFSplitRC
|
||||
{
|
||||
uint32_t depthTextureIndex;
|
||||
uint32_t colorTextureIndex;
|
||||
uint32_t nearColorTextureIndex;
|
||||
uint32_t farColorTextureIndex;
|
||||
uint32_t nearCocTextureIndex;
|
||||
uint32_t farCocTextureIndex;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float focusNearMin;
|
||||
float focusNearMax;
|
||||
float focusFarMin;
|
||||
float focusFarMax;
|
||||
float brightnessScale;
|
||||
};
|
||||
|
||||
struct DOFNearCocMaxRC
|
||||
{
|
||||
uint32_t inputTextureIndex;
|
||||
uint32_t outputTextureIndex;
|
||||
uint32_t samplerIndex;
|
||||
int32_t kernelRadius;
|
||||
float kernelDirectionX;
|
||||
float kernelDirectionY;
|
||||
};
|
||||
|
||||
struct DOFNearCocBlurRC
|
||||
{
|
||||
uint32_t inputTextureIndex;
|
||||
uint32_t outputTextureIndex;
|
||||
uint32_t samplerIndex;
|
||||
int32_t kernelRadius;
|
||||
float kernelDirectionX;
|
||||
float kernelDirectionY;
|
||||
};
|
||||
|
||||
struct DOFNearCocTileGenRC
|
||||
{
|
||||
uint32_t inputTextureIndex;
|
||||
uint32_t outputTextureIndex;
|
||||
};
|
||||
|
||||
struct DOFNearCocTileMaxRC
|
||||
{
|
||||
uint32_t inputTextureIndex;
|
||||
uint32_t outputTextureIndex;
|
||||
uint32_t samplerIndex; // point/clamp
|
||||
};
|
||||
|
||||
struct DOFBlurRC
|
||||
{
|
||||
uint32_t colorTextureIndex;
|
||||
uint32_t nearColorTextureIndex;
|
||||
uint32_t nearMaxCocTextureIndex;
|
||||
uint32_t nearCocTextureIndex; // blurry
|
||||
uint32_t nearOutputTextureIndex;
|
||||
uint32_t farColorTextureIndex;
|
||||
uint32_t farCocTextureIndex; // sharp
|
||||
uint32_t farOutputTextureIndex;
|
||||
uint32_t samplerIndex; // linear/clamp
|
||||
float brightnessScale;
|
||||
float bladeCount;
|
||||
float bokehAngleRad;
|
||||
};
|
||||
|
||||
struct DOFFillRC
|
||||
{
|
||||
uint32_t nearInputTextureIndex;
|
||||
uint32_t nearOutputTextureIndex;
|
||||
uint32_t farInputTextureIndex;
|
||||
uint32_t farOutputTextureIndex;
|
||||
uint32_t samplerIndex; // point/clamp
|
||||
};
|
||||
|
||||
struct DOFCombineRC
|
||||
{
|
||||
uint32_t nearTextureIndex;
|
||||
uint32_t farTextureIndex;
|
||||
uint32_t nearCocTextureIndex;
|
||||
uint32_t farCocTextureIndex;
|
||||
uint32_t sharpTextureIndex;
|
||||
uint32_t samplerIndex; // point/clamp
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
void GatherDepthOfField::Init()
|
||||
{
|
||||
const TextureFormat::Id renderTargetFormat = TextureFormat::RGBA64_Float;
|
||||
|
||||
tileWidth = (uint32_t)(glConfig.vidWidth + 15) / 16;
|
||||
tileHeight = (uint32_t)(glConfig.vidHeight + 15) / 16;
|
||||
|
||||
{
|
||||
ComputePipelineDesc desc("DOF split");
|
||||
desc.shortLifeTime = true;
|
||||
desc.shader = ShaderByteCode(split::g_cs);
|
||||
splitPipeline = CreateComputePipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
ComputePipelineDesc desc("DOF near CoC tile generation");
|
||||
desc.shortLifeTime = true;
|
||||
desc.shader = ShaderByteCode(near_coc_tile_gen::g_cs);
|
||||
nearCocTileGenPipeline = CreateComputePipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
ComputePipelineDesc desc("DOF near CoC tile dilation");
|
||||
desc.shortLifeTime = true;
|
||||
desc.shader = ShaderByteCode(near_coc_tile_max::g_cs);
|
||||
nearCocTileMaxPipeline = CreateComputePipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
ComputePipelineDesc desc("DOF blur");
|
||||
desc.shortLifeTime = true;
|
||||
desc.shader = ShaderByteCode(blur::g_cs);
|
||||
blurPipeline = CreateComputePipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
ComputePipelineDesc desc("DOF fill");
|
||||
desc.shortLifeTime = true;
|
||||
desc.shader = ShaderByteCode(fill::g_cs);
|
||||
fillPipeline = CreateComputePipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("DOF combine");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(combine::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(combine::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, renderTargetFormat);
|
||||
combinePipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("DOF viz");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(debug::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(debug::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, renderTargetFormat);
|
||||
debugPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("DOF far field color", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.shortLifeTime = true;
|
||||
desc.committedResource = true;
|
||||
desc.initialState = ResourceStates::UnorderedAccessBit;
|
||||
desc.allowedState = ResourceStates::UnorderedAccessBit | ResourceStates::ComputeShaderAccessBit | ResourceStates::PixelShaderAccessBit;
|
||||
desc.format = renderTargetFormat;
|
||||
farColorTexture = CreateTexture(desc);
|
||||
desc.name = "DOF near field color";
|
||||
nearColorTexture = CreateTexture(desc);
|
||||
desc.name = "DOF near field blurred color";
|
||||
nearBlurTexture = CreateTexture(desc);
|
||||
desc.name = "DOF far field blurred color";
|
||||
farBlurTexture = CreateTexture(desc);
|
||||
|
||||
desc.format = TextureFormat::R8_UNorm;
|
||||
desc.name = "DOF near field CoC #1";
|
||||
nearCocTexture = CreateTexture(desc);
|
||||
desc.name = "DOF near field CoC #2";
|
||||
nearCocTexture2 = CreateTexture(desc);
|
||||
desc.name = "DOF far field CoC";
|
||||
farCocTexture = CreateTexture(desc);
|
||||
|
||||
desc.width = tileWidth;
|
||||
desc.height = tileHeight;
|
||||
desc.name = "DOF near field CoC tile #1";
|
||||
nearCocTileTexture = CreateTexture(desc);
|
||||
desc.name = "DOF near field CoC tile #2";
|
||||
nearCocTileTexture2 = CreateTexture(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void GatherDepthOfField::Draw()
|
||||
{
|
||||
if(crp_dof->integer != DOFMethod::Gather)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(backEnd.viewParms.viewportX != 0 ||
|
||||
backEnd.viewParms.viewportY != 0 ||
|
||||
backEnd.viewParms.viewportWidth != glConfig.vidWidth ||
|
||||
backEnd.viewParms.viewportHeight != glConfig.vidHeight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DrawSplit();
|
||||
DrawNearCocTileGen();
|
||||
DrawNearCocTileMax();
|
||||
DrawBlur();
|
||||
DrawFill();
|
||||
DrawCombine();
|
||||
DrawDebug();
|
||||
}
|
||||
|
||||
void GatherDepthOfField::DrawDebug()
|
||||
{
|
||||
if(crp_dof_overlay->integer == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPED_RENDER_PASS("DOF Debug", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
crp.SwapRenderTargets();
|
||||
const TextureBarrier barriers[] =
|
||||
{
|
||||
TextureBarrier(crp.GetReadRenderTarget(), ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.depthTexture, ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.GetWriteRenderTarget(), ResourceStates::RenderTargetBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(barriers), barriers);
|
||||
|
||||
DOFDebugRC rc = {};
|
||||
rc.colorTextureIndex = GetTextureIndexSRV(crp.GetReadRenderTarget());
|
||||
rc.depthTextureIndex = GetTextureIndexSRV(crp.depthTexture);
|
||||
rc.debugMode = crp_dof_overlay->integer;
|
||||
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
||||
rc.focusNearMin = crp_gatherDof_focusNearDist->value - 0.5f * crp_gatherDof_focusNearRange->value;
|
||||
rc.focusNearMax = crp_gatherDof_focusNearDist->value + 0.5f * crp_gatherDof_focusNearRange->value;
|
||||
rc.focusFarMin = crp_gatherDof_focusFarDist->value - 0.5f * crp_gatherDof_focusFarRange->value;
|
||||
rc.focusFarMax = crp_gatherDof_focusFarDist->value + 0.5f * crp_gatherDof_focusFarRange->value;
|
||||
rc.focusDist = 0.5f * (rc.focusNearMax + rc.focusFarMin);
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
CmdBindPipeline(debugPipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
|
||||
void GatherDepthOfField::DrawSplit()
|
||||
{
|
||||
SCOPED_RENDER_PASS("DOF Split", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
const TextureBarrier barriers[] =
|
||||
{
|
||||
TextureBarrier(crp.depthTexture, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(crp.renderTarget, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(nearColorTexture, ResourceStates::UnorderedAccessBit),
|
||||
TextureBarrier(farColorTexture, ResourceStates::UnorderedAccessBit),
|
||||
TextureBarrier(nearCocTexture, ResourceStates::UnorderedAccessBit),
|
||||
TextureBarrier(farCocTexture, ResourceStates::UnorderedAccessBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(barriers), barriers);
|
||||
|
||||
DOFSplitRC rc = {};
|
||||
rc.depthTextureIndex = GetTextureIndexSRV(crp.depthTexture);
|
||||
rc.colorTextureIndex = GetTextureIndexSRV(crp.renderTarget);
|
||||
rc.nearColorTextureIndex = GetTextureIndexUAV(nearColorTexture, 0);
|
||||
rc.farColorTextureIndex = GetTextureIndexUAV(farColorTexture, 0);
|
||||
rc.nearCocTextureIndex = GetTextureIndexUAV(nearCocTexture, 0);
|
||||
rc.farCocTextureIndex = GetTextureIndexUAV(farCocTexture, 0);
|
||||
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
||||
rc.focusNearMin = crp_gatherDof_focusNearDist->value - 0.5f * crp_gatherDof_focusNearRange->value;
|
||||
rc.focusNearMax = crp_gatherDof_focusNearDist->value + 0.5f * crp_gatherDof_focusNearRange->value;
|
||||
rc.focusFarMin = crp_gatherDof_focusFarDist->value - 0.5f * crp_gatherDof_focusFarRange->value;
|
||||
rc.focusFarMax = crp_gatherDof_focusFarDist->value + 0.5f * crp_gatherDof_focusFarRange->value;
|
||||
rc.brightnessScale = crp_gatherDof_brightness->value;
|
||||
|
||||
CmdBindPipeline(splitPipeline);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDispatch((glConfig.vidWidth + 7) / 8, (glConfig.vidHeight + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void GatherDepthOfField::DrawNearCocTileGen()
|
||||
{
|
||||
SCOPED_RENDER_PASS("DOF Tile Gen", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
const TextureBarrier barriers[] =
|
||||
{
|
||||
TextureBarrier(nearCocTexture, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(nearCocTileTexture, ResourceStates::UnorderedAccessBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(barriers), barriers);
|
||||
|
||||
DOFNearCocTileGenRC rc = {};
|
||||
rc.inputTextureIndex = GetTextureIndexSRV(nearCocTexture);
|
||||
rc.outputTextureIndex = GetTextureIndexUAV(nearCocTileTexture, 0);
|
||||
|
||||
CmdBindPipeline(nearCocTileGenPipeline);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDispatch((tileWidth + 7) / 8, (tileHeight + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void GatherDepthOfField::DrawNearCocTileMax()
|
||||
{
|
||||
SCOPED_RENDER_PASS("DOF Tile Max", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
const TextureBarrier barriers[] =
|
||||
{
|
||||
TextureBarrier(nearCocTileTexture, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(nearCocTileTexture2, ResourceStates::UnorderedAccessBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(barriers), barriers);
|
||||
|
||||
DOFNearCocTileMaxRC rc = {};
|
||||
rc.inputTextureIndex = GetTextureIndexSRV(nearCocTileTexture);
|
||||
rc.outputTextureIndex = GetTextureIndexUAV(nearCocTileTexture2, 0);
|
||||
rc.samplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Point);
|
||||
|
||||
CmdBindPipeline(nearCocTileMaxPipeline);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDispatch((tileWidth + 7) / 8, (tileHeight + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void GatherDepthOfField::DrawBlur()
|
||||
{
|
||||
SCOPED_RENDER_PASS("DOF Blur", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
const TextureBarrier barriers[] =
|
||||
{
|
||||
TextureBarrier(crp.renderTarget, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(nearColorTexture, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(farColorTexture, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(nearCocTexture, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(nearCocTileTexture2, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(farCocTexture, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(nearBlurTexture, ResourceStates::UnorderedAccessBit),
|
||||
TextureBarrier(farBlurTexture, ResourceStates::UnorderedAccessBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(barriers), barriers);
|
||||
|
||||
DOFBlurRC rc = {};
|
||||
rc.colorTextureIndex = GetTextureIndexSRV(crp.renderTarget);
|
||||
rc.nearColorTextureIndex = GetTextureIndexSRV(nearColorTexture);
|
||||
rc.nearMaxCocTextureIndex = GetTextureIndexSRV(nearCocTileTexture2);
|
||||
rc.nearCocTextureIndex = GetTextureIndexSRV(nearCocTexture);
|
||||
rc.nearOutputTextureIndex = GetTextureIndexUAV(nearBlurTexture, 0);
|
||||
rc.farColorTextureIndex = GetTextureIndexSRV(farColorTexture);
|
||||
rc.farCocTextureIndex = GetTextureIndexSRV(farCocTexture);
|
||||
rc.farOutputTextureIndex = GetTextureIndexUAV(farBlurTexture, 0);
|
||||
rc.samplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Linear);
|
||||
rc.brightnessScale = crp_gatherDof_brightness->value;
|
||||
rc.bladeCount = crp_dof_blades->value;
|
||||
rc.bokehAngleRad = DEG2RAD(crp_dof_angle->value);
|
||||
|
||||
CmdBindPipeline(blurPipeline);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDispatch((glConfig.vidWidth + 7) / 8, (glConfig.vidHeight + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void GatherDepthOfField::DrawFill()
|
||||
{
|
||||
SCOPED_RENDER_PASS("DOF Fill", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
const TextureBarrier barriers[] =
|
||||
{
|
||||
TextureBarrier(nearBlurTexture, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(farBlurTexture, ResourceStates::ComputeShaderAccessBit),
|
||||
TextureBarrier(nearColorTexture, ResourceStates::UnorderedAccessBit),
|
||||
TextureBarrier(farColorTexture, ResourceStates::UnorderedAccessBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(barriers), barriers);
|
||||
|
||||
DOFFillRC rc = {};
|
||||
rc.nearInputTextureIndex = GetTextureIndexSRV(nearBlurTexture);
|
||||
rc.farInputTextureIndex = GetTextureIndexSRV(farBlurTexture);
|
||||
rc.nearOutputTextureIndex = GetTextureIndexUAV(nearColorTexture, 0);
|
||||
rc.farOutputTextureIndex = GetTextureIndexUAV(farColorTexture, 0);
|
||||
rc.samplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Point);
|
||||
|
||||
CmdBindPipeline(fillPipeline);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDispatch((glConfig.vidWidth + 7) / 8, (glConfig.vidHeight + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void GatherDepthOfField::DrawCombine()
|
||||
{
|
||||
SCOPED_RENDER_PASS("DOF Combine", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
const TextureBarrier barriers[] =
|
||||
{
|
||||
TextureBarrier(nearColorTexture, ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(farColorTexture, ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(nearCocTexture, ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(farCocTexture, ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.GetReadRenderTarget(), ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.GetWriteRenderTarget(), ResourceStates::RenderTargetBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(barriers), barriers);
|
||||
|
||||
DOFCombineRC rc = {};
|
||||
rc.nearTextureIndex = GetTextureIndexSRV(nearColorTexture);
|
||||
rc.farTextureIndex = GetTextureIndexSRV(farColorTexture);
|
||||
rc.nearCocTextureIndex = GetTextureIndexSRV(nearCocTexture);
|
||||
rc.farCocTextureIndex = GetTextureIndexSRV(farCocTexture);
|
||||
rc.sharpTextureIndex = GetTextureIndexSRV(crp.renderTarget);
|
||||
rc.samplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Point);
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
CmdBindPipeline(combinePipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
208
code/renderer/crp_fog.cpp
Normal file
208
code/renderer/crp_fog.cpp
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - fog volumes
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
namespace fog_outside
|
||||
{
|
||||
#include "compshaders/crp/fog_outside_vs.h"
|
||||
#include "compshaders/crp/fog_outside_ps.h"
|
||||
}
|
||||
namespace fog_inside
|
||||
{
|
||||
#include "compshaders/crp/fog_inside_vs.h"
|
||||
#include "compshaders/crp/fog_inside_ps.h"
|
||||
}
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct FogRC
|
||||
{
|
||||
float modelViewMatrix[16];
|
||||
float projectionMatrix[16];
|
||||
float boxMin[4];
|
||||
float boxMax[4];
|
||||
float color[4];
|
||||
float depth;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
uint32_t depthTextureIndex;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
void Fog::Init()
|
||||
{
|
||||
{
|
||||
const uint32_t indices[] =
|
||||
{
|
||||
0, 1, 2, 2, 1, 3,
|
||||
4, 0, 6, 6, 0, 2,
|
||||
7, 5, 6, 6, 5, 4,
|
||||
3, 1, 7, 7, 1, 5,
|
||||
4, 5, 0, 0, 5, 1,
|
||||
3, 7, 2, 2, 7, 6
|
||||
};
|
||||
|
||||
BufferDesc desc("box index", sizeof(indices), ResourceStates::IndexBufferBit);
|
||||
desc.shortLifeTime = true;
|
||||
boxIndexBuffer = CreateBuffer(desc);
|
||||
|
||||
uint8_t* mapped = BeginBufferUpload(boxIndexBuffer);
|
||||
memcpy(mapped, indices, sizeof(indices));
|
||||
EndBufferUpload(boxIndexBuffer);
|
||||
}
|
||||
{
|
||||
const float vertices[] =
|
||||
{
|
||||
0.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
0.0f, 0.0f, 1.0f,
|
||||
1.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
BufferDesc desc("box vertex", sizeof(vertices), ResourceStates::VertexBufferBit);
|
||||
desc.shortLifeTime = true;
|
||||
boxVertexBuffer = CreateBuffer(desc);
|
||||
|
||||
uint8_t* mapped = BeginBufferUpload(boxVertexBuffer);
|
||||
memcpy(mapped, vertices, sizeof(vertices));
|
||||
EndBufferUpload(boxVertexBuffer);
|
||||
}
|
||||
{
|
||||
GraphicsPipelineDesc desc("fog outside");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(fog_outside::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(fog_outside::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_BACK_SIDED;
|
||||
desc.rasterizer.polygonOffset = false;
|
||||
desc.rasterizer.clampDepth = true;
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, crp.renderTargetFormat);
|
||||
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
||||
fogOutsidePipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
{
|
||||
GraphicsPipelineDesc desc("fog inside");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(fog_inside::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(fog_inside::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_FRONT_SIDED;
|
||||
desc.rasterizer.polygonOffset = false;
|
||||
desc.rasterizer.clampDepth = true;
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, crp.renderTargetFormat);
|
||||
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
||||
fogInsidePipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void Fog::Draw()
|
||||
{
|
||||
// @NOTE: fog 0 is invalid, it must be skipped
|
||||
if(tr.world == NULL ||
|
||||
tr.world->numfogs <= 1 ||
|
||||
(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPED_RENDER_PASS("Fog", 0.25f, 0.125f, 0.0f);
|
||||
|
||||
srp.renderMode = RenderMode::World;
|
||||
|
||||
const uint32_t stride = sizeof(vec3_t);
|
||||
CmdBindVertexBuffers(1, &boxVertexBuffer, &stride, NULL);
|
||||
CmdBindIndexBuffer(boxIndexBuffer, IndexType::UInt32, 0);
|
||||
|
||||
const TextureBarrier barriers[] =
|
||||
{
|
||||
TextureBarrier(crp.depthTexture, ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.renderTarget, ResourceStates::RenderTargetBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(barriers), barriers);
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
|
||||
int insideIndex = -1;
|
||||
for(int f = 1; f < tr.world->numfogs; ++f)
|
||||
{
|
||||
const fog_t& fog = tr.world->fogs[f];
|
||||
|
||||
bool inside = true;
|
||||
for(int a = 0; a < 3; ++a)
|
||||
{
|
||||
if(backEnd.viewParms.orient.origin[a] <= fog.bounds[0][a] ||
|
||||
backEnd.viewParms.orient.origin[a] >= fog.bounds[1][a])
|
||||
{
|
||||
inside = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(inside)
|
||||
{
|
||||
insideIndex = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FogRC rc = {};
|
||||
memcpy(rc.modelViewMatrix, backEnd.viewParms.world.modelMatrix, sizeof(rc.modelViewMatrix));
|
||||
memcpy(rc.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(rc.projectionMatrix));
|
||||
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
||||
rc.depthTextureIndex = GetTextureIndexSRV(crp.depthTexture);
|
||||
|
||||
CmdBindPipeline(fogOutsidePipeline);
|
||||
for(int f = 1; f < tr.world->numfogs; ++f)
|
||||
{
|
||||
if(f == insideIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const fog_t& fog = tr.world->fogs[f];
|
||||
VectorScale(fog.parms.color, tr.identityLight, rc.color);
|
||||
rc.depth = fog.parms.depthForOpaque;
|
||||
VectorCopy(fog.bounds[0], rc.boxMin);
|
||||
VectorCopy(fog.bounds[1], rc.boxMax);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDrawIndexed(36, 0, 0);
|
||||
}
|
||||
|
||||
if(insideIndex > 0)
|
||||
{
|
||||
CmdBindPipeline(fogInsidePipeline);
|
||||
|
||||
const fog_t& fog = tr.world->fogs[insideIndex];
|
||||
VectorScale(fog.parms.color, tr.identityLight, rc.color);
|
||||
rc.depth = fog.parms.depthForOpaque;
|
||||
VectorCopy(fog.bounds[0], rc.boxMin);
|
||||
VectorCopy(fog.bounds[1], rc.boxMax);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDrawIndexed(36, 0, 0);
|
||||
}
|
||||
}
|
155
code/renderer/crp_geometry.cpp
Normal file
155
code/renderer/crp_geometry.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - vertex and index buffer management
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
|
||||
|
||||
void GeoBuffers::Create(const char* name, uint32_t vertexCount, uint32_t indexCount)
|
||||
{
|
||||
baseVertexBuffers[BaseBufferId::Position].CreateVertexBuffer(
|
||||
va("%s position", name), MemoryUsage::Upload, vertexCount, sizeof(vec3_t));
|
||||
baseVertexBuffers[BaseBufferId::Normal].CreateVertexBuffer(
|
||||
va("%s normal", name), MemoryUsage::Upload, vertexCount, sizeof(vec3_t));
|
||||
stageVertexBuffers[StageBufferId::TexCoords].CreateVertexBuffer(
|
||||
va("%s tc", name), MemoryUsage::Upload, vertexCount * MAX_SHADER_STAGES, sizeof(vec2_t));
|
||||
stageVertexBuffers[StageBufferId::Color].CreateVertexBuffer(
|
||||
va("%s color", name), MemoryUsage::Upload, vertexCount * MAX_SHADER_STAGES, sizeof(color4ub_t));
|
||||
indexBuffer.Create(name, MemoryUsage::Upload, indexCount);
|
||||
|
||||
vertexBuffers[0] = baseVertexBuffers[BaseBufferId::Position].buffer;
|
||||
vertexBuffers[1] = baseVertexBuffers[BaseBufferId::Normal].buffer;
|
||||
vertexBuffers[2] = stageVertexBuffers[StageBufferId::TexCoords].buffer;
|
||||
vertexBuffers[3] = stageVertexBuffers[StageBufferId::Color].buffer;
|
||||
vertexBufferStrides[0] = sizeof(vec3_t);
|
||||
vertexBufferStrides[1] = sizeof(vec3_t);
|
||||
vertexBufferStrides[2] = sizeof(vec2_t);
|
||||
vertexBufferStrides[3] = sizeof(color4ub_t);
|
||||
}
|
||||
|
||||
void GeoBuffers::Rewind()
|
||||
{
|
||||
for(uint32_t b = 0; b < ARRAY_LEN(baseVertexBuffers); ++b)
|
||||
{
|
||||
baseVertexBuffers[b].Rewind();
|
||||
}
|
||||
for(uint32_t b = 0; b < ARRAY_LEN(stageVertexBuffers); ++b)
|
||||
{
|
||||
stageVertexBuffers[b].Rewind();
|
||||
}
|
||||
indexBuffer.Rewind();
|
||||
}
|
||||
|
||||
void GeoBuffers::BeginUpload()
|
||||
{
|
||||
for(uint32_t b = 0; b < ARRAY_LEN(baseVertexBuffers); ++b)
|
||||
{
|
||||
baseVertexBuffers[b].BeginUpload();
|
||||
}
|
||||
for(uint32_t b = 0; b < ARRAY_LEN(stageVertexBuffers); ++b)
|
||||
{
|
||||
stageVertexBuffers[b].BeginUpload();
|
||||
}
|
||||
indexBuffer.BeginUpload();
|
||||
}
|
||||
|
||||
void GeoBuffers::EndUpload()
|
||||
{
|
||||
for(uint32_t b = 0; b < ARRAY_LEN(baseVertexBuffers); ++b)
|
||||
{
|
||||
baseVertexBuffers[b].EndUpload();
|
||||
}
|
||||
for(uint32_t b = 0; b < ARRAY_LEN(stageVertexBuffers); ++b)
|
||||
{
|
||||
stageVertexBuffers[b].EndUpload();
|
||||
}
|
||||
indexBuffer.EndUpload();
|
||||
}
|
||||
|
||||
void GeoBuffers::UploadBase()
|
||||
{
|
||||
indexBuffer.Upload();
|
||||
|
||||
const uint32_t batchOffset = baseVertexBuffers[0].batchFirst + baseVertexBuffers[0].batchCount;
|
||||
|
||||
float* pos = (float*)baseVertexBuffers[BaseBufferId::Position].mapped + 3 * batchOffset;
|
||||
for(int v = 0; v < tess.numVertexes; ++v)
|
||||
{
|
||||
pos[0] = tess.xyz[v][0];
|
||||
pos[1] = tess.xyz[v][1];
|
||||
pos[2] = tess.xyz[v][2];
|
||||
pos += 3;
|
||||
}
|
||||
|
||||
float* nor = (float*)baseVertexBuffers[BaseBufferId::Normal].mapped + 3 * batchOffset;
|
||||
for(int v = 0; v < tess.numVertexes; ++v)
|
||||
{
|
||||
nor[0] = tess.normal[v][0];
|
||||
nor[1] = tess.normal[v][1];
|
||||
nor[2] = tess.normal[v][2];
|
||||
nor += 3;
|
||||
}
|
||||
}
|
||||
|
||||
void GeoBuffers::UploadStage(uint32_t svarsIndex)
|
||||
{
|
||||
const uint32_t batchOffset = stageVertexBuffers[0].batchFirst + stageVertexBuffers[0].batchCount;
|
||||
const stageVars_t& sv = tess.svars[svarsIndex];
|
||||
|
||||
uint8_t* const tcBuffer = stageVertexBuffers[StageBufferId::TexCoords].mapped;
|
||||
float* tc = (float*)tcBuffer + 2 * batchOffset;
|
||||
memcpy(tc, &sv.texcoords[0], tess.numVertexes * sizeof(vec2_t));
|
||||
|
||||
uint8_t* const colBuffer = stageVertexBuffers[StageBufferId::Color].mapped;
|
||||
uint32_t* col = (uint32_t*)colBuffer + batchOffset;
|
||||
memcpy(col, &sv.colors[0], tess.numVertexes * sizeof(color4ub_t));
|
||||
}
|
||||
|
||||
void GeoBuffers::EndBaseBatch(uint32_t vertexCount)
|
||||
{
|
||||
baseVertexBuffers[BaseBufferId::Position].EndBatch(vertexCount);
|
||||
baseVertexBuffers[BaseBufferId::Normal].EndBatch(vertexCount);
|
||||
indexBuffer.EndBatch(tess.numIndexes);
|
||||
}
|
||||
|
||||
bool GeoBuffers::CanAdd(uint32_t vertexCount, uint32_t indexCount, uint32_t stageCount)
|
||||
{
|
||||
return
|
||||
baseVertexBuffers[0].CanAdd(vertexCount) &&
|
||||
stageVertexBuffers[0].CanAdd(vertexCount * stageCount) &&
|
||||
indexBuffer.CanAdd(indexCount);
|
||||
}
|
||||
|
||||
void GeoBuffers::DrawStage(uint32_t vertexCount, uint32_t indexCount)
|
||||
{
|
||||
const uint32_t vertexOffset = stageVertexBuffers[0].batchFirst - baseVertexBuffers[0].batchFirst;
|
||||
uint32_t byteOffsets[BaseBufferId::Count + StageBufferId::Count] = {};
|
||||
byteOffsets[BaseBufferId::Count + StageBufferId::TexCoords] = vertexOffset * sizeof(vec2_t);
|
||||
byteOffsets[BaseBufferId::Count + StageBufferId::Color] = vertexOffset * sizeof(color4ub_t);
|
||||
CmdBindVertexBuffers(ARRAY_LEN(vertexBuffers), vertexBuffers, vertexBufferStrides, byteOffsets);
|
||||
|
||||
CmdDrawIndexed(indexCount, indexBuffer.batchFirst, baseVertexBuffers[0].batchFirst);
|
||||
|
||||
// @NOTE: must happen after the final vertex buffer byte offsets have been computed
|
||||
stageVertexBuffers[StageBufferId::TexCoords].EndBatch(vertexCount);
|
||||
stageVertexBuffers[StageBufferId::Color].EndBatch(vertexCount);
|
||||
}
|
330
code/renderer/crp_local.h
Normal file
330
code/renderer/crp_local.h
Normal file
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - private declarations
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "srp_local.h"
|
||||
|
||||
|
||||
extern cvar_t* crp_dof;
|
||||
extern cvar_t* crp_dof_overlay;
|
||||
extern cvar_t* crp_dof_blades;
|
||||
extern cvar_t* crp_dof_angle;
|
||||
extern cvar_t* crp_gatherDof_focusNearDist;
|
||||
extern cvar_t* crp_gatherDof_focusNearRange;
|
||||
extern cvar_t* crp_gatherDof_focusFarDist;
|
||||
extern cvar_t* crp_gatherDof_focusFarRange;
|
||||
extern cvar_t* crp_gatherDof_brightness;
|
||||
extern cvar_t* crp_accumDof_focusDist;
|
||||
extern cvar_t* crp_accumDof_radius;
|
||||
extern cvar_t* crp_accumDof_samples;
|
||||
extern cvar_t* crp_accumDof_preview;
|
||||
|
||||
struct DOFMethod
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
None,
|
||||
Gather,
|
||||
Accumulation,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
struct Tessellator
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
None,
|
||||
Opaque,
|
||||
Transp,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
using namespace RHI;
|
||||
|
||||
|
||||
struct WorldVertexRC
|
||||
{
|
||||
float modelViewMatrix[16];
|
||||
float projectionMatrix[16];
|
||||
float clipPlane[4];
|
||||
};
|
||||
|
||||
struct PSOCache
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
GraphicsPipelineDesc desc;
|
||||
HPipeline handle;
|
||||
};
|
||||
|
||||
void Init(Entry* entries, uint32_t maxEntryCount);
|
||||
int AddPipeline(const GraphicsPipelineDesc& desc, const char* name);
|
||||
|
||||
Entry* entries = NULL;
|
||||
uint32_t maxEntryCount = 0;
|
||||
uint32_t entryCount = 1; // we treat index 0 as invalid
|
||||
};
|
||||
|
||||
struct WorldOpaque
|
||||
{
|
||||
void Init();
|
||||
void Draw(const drawSceneViewCommand_t& cmd);
|
||||
void ProcessShader(shader_t& shader);
|
||||
void TessellationOverflow();
|
||||
void DrawSkyBox();
|
||||
void DrawClouds();
|
||||
|
||||
private:
|
||||
void BeginBatch(const shader_t* shader);
|
||||
void EndBatch();
|
||||
void EndSkyBatch();
|
||||
|
||||
PSOCache::Entry psoCacheEntries[128];
|
||||
PSOCache psoCache;
|
||||
|
||||
float clipPlane[4];
|
||||
bool batchOldDepthHack;
|
||||
bool batchDepthHack;
|
||||
};
|
||||
|
||||
struct WorldTransp
|
||||
{
|
||||
void Init();
|
||||
void Draw(const drawSceneViewCommand_t& cmd);
|
||||
void ProcessShader(shader_t& shader);
|
||||
void TessellationOverflow();
|
||||
|
||||
private:
|
||||
void BeginBatch(const shader_t* shader);
|
||||
void EndBatch();
|
||||
|
||||
PSOCache::Entry psoCacheEntries[32];
|
||||
PSOCache psoCache;
|
||||
|
||||
float clipPlane[4];
|
||||
bool batchOldDepthHack;
|
||||
bool batchDepthHack;
|
||||
};
|
||||
|
||||
struct Fog
|
||||
{
|
||||
void Init();
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
HBuffer boxIndexBuffer;
|
||||
HBuffer boxVertexBuffer;
|
||||
HPipeline fogInsidePipeline;
|
||||
HPipeline fogOutsidePipeline;
|
||||
};
|
||||
|
||||
struct TranspResolve
|
||||
{
|
||||
void Init();
|
||||
void Draw(const drawSceneViewCommand_t& cmd);
|
||||
|
||||
private:
|
||||
HPipeline pipeline;
|
||||
};
|
||||
|
||||
struct ToneMap
|
||||
{
|
||||
void Init();
|
||||
void DrawToneMap();
|
||||
void DrawInverseToneMap();
|
||||
|
||||
private:
|
||||
HPipeline pipeline;
|
||||
HPipeline inversePipeline;
|
||||
};
|
||||
|
||||
struct AccumDepthOfField
|
||||
{
|
||||
void Init();
|
||||
void Begin(const drawSceneViewCommand_t& cmd);
|
||||
uint32_t GetSampleCount();
|
||||
void FixCommand(drawSceneViewCommand_t& newCmd, const drawSceneViewCommand_t& cmd, uint32_t x, uint32_t y);
|
||||
void Accumulate();
|
||||
void Normalize();
|
||||
void DrawDebug();
|
||||
|
||||
private:
|
||||
HPipeline accumPipeline;
|
||||
HPipeline normPipeline;
|
||||
HPipeline debugPipeline;
|
||||
HTexture accumTexture;
|
||||
float maxNearCocCS;
|
||||
float maxFarCocCS;
|
||||
float modelViewMatrix[16];
|
||||
float projMatrix[16];
|
||||
};
|
||||
|
||||
struct GatherDepthOfField
|
||||
{
|
||||
void Init();
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
void DrawDebug();
|
||||
void DrawSplit();
|
||||
void DrawNearCocTileGen();
|
||||
void DrawNearCocTileMax();
|
||||
void DrawBlur();
|
||||
void DrawFill();
|
||||
void DrawCombine();
|
||||
|
||||
HPipeline debugPipeline;
|
||||
HPipeline splitPipeline;
|
||||
HPipeline nearCocTileGenPipeline;
|
||||
HPipeline nearCocTileMaxPipeline;
|
||||
HPipeline blurPipeline;
|
||||
HPipeline fillPipeline;
|
||||
HPipeline combinePipeline;
|
||||
HTexture nearColorTexture;
|
||||
HTexture farColorTexture;
|
||||
HTexture nearBlurTexture;
|
||||
HTexture farBlurTexture;
|
||||
HTexture nearCocTexture;
|
||||
HTexture nearCocTexture2;
|
||||
HTexture nearCocTileTexture;
|
||||
HTexture nearCocTileTexture2;
|
||||
HTexture farCocTexture;
|
||||
uint32_t tileWidth;
|
||||
uint32_t tileHeight;
|
||||
};
|
||||
|
||||
struct BaseBufferId
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
Position,
|
||||
Normal,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
struct StageBufferId
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
TexCoords,
|
||||
Color,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
struct GeoBuffers
|
||||
{
|
||||
void Create(const char* name, uint32_t vertexCount, uint32_t indexCount);
|
||||
void Rewind();
|
||||
void BeginUpload();
|
||||
void EndUpload();
|
||||
void UploadBase();
|
||||
void UploadStage(uint32_t svarsIndex);
|
||||
void EndBaseBatch(uint32_t vertexCount);
|
||||
bool CanAdd(uint32_t vertexCount, uint32_t indexCount, uint32_t stageCount);
|
||||
void DrawStage(uint32_t vertexCount, uint32_t indexCount);
|
||||
|
||||
GeometryBuffer baseVertexBuffers[BaseBufferId::Count];
|
||||
GeometryBuffer stageVertexBuffers[StageBufferId::Count];
|
||||
IndexBuffer indexBuffer;
|
||||
HBuffer vertexBuffers[BaseBufferId::Count + StageBufferId::Count];
|
||||
uint32_t vertexBufferStrides[BaseBufferId::Count + StageBufferId::Count];
|
||||
};
|
||||
|
||||
struct CRP : IRenderPipeline
|
||||
{
|
||||
void Init() override;
|
||||
void ShutDown(bool fullShutDown) override;
|
||||
|
||||
void ProcessWorld(world_t& world) override;
|
||||
void ProcessModel(model_t& model) override;
|
||||
void ProcessShader(shader_t& shader) override;
|
||||
|
||||
void CreateTexture(image_t* image, int mipCount, int width, int height) override;
|
||||
void UpoadTextureAndGenerateMipMaps(image_t* image, const byte* data) override;
|
||||
void BeginTextureUpload(MappedTexture& mappedTexture, image_t* image) override;
|
||||
void EndTextureUpload() override;
|
||||
|
||||
void ExecuteRenderCommands(const byte* data, bool readbackRequested) override;
|
||||
void TessellationOverflow() override;
|
||||
void DrawSkyBox() override { opaque.DrawSkyBox(); }
|
||||
void DrawClouds() override { opaque.DrawClouds(); }
|
||||
void ReadPixels(int w, int h, int alignment, colorSpace_t colorSpace, void* out) override;
|
||||
|
||||
uint32_t GetSamplerDescriptorIndexFromBaseIndex(uint32_t baseIndex) override;
|
||||
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
|
||||
void Blit(HTexture destination, HTexture source, const char* passName, bool hdr, const vec2_t tcScale, const vec2_t tcBias);
|
||||
void BlitRenderTarget(HTexture destination, const char* passName);
|
||||
void DrawSceneView(const drawSceneViewCommand_t& cmd);
|
||||
|
||||
HTexture GetReadRenderTarget();
|
||||
HTexture GetWriteRenderTarget();
|
||||
void SwapRenderTargets();
|
||||
|
||||
// general
|
||||
float frameSeed;
|
||||
HTexture readbackRenderTarget;
|
||||
HTexture depthTexture;
|
||||
HTexture renderTarget;
|
||||
TextureFormat::Id renderTargetFormat;
|
||||
HTexture renderTargets[2];
|
||||
uint32_t renderTargetIndex; // the one to write to
|
||||
HSampler samplers[BASE_SAMPLER_COUNT]; // all base samplers
|
||||
uint32_t samplerIndices[BASE_SAMPLER_COUNT]; // descriptor heap indices
|
||||
|
||||
// blit
|
||||
HPipeline blitPipelineLDR;
|
||||
HPipeline blitPipelineHDR;
|
||||
|
||||
// world geometry
|
||||
GeoBuffers dynBuffers[FrameCount]; // for rendering world surfaces
|
||||
|
||||
// for rendering transparent world surfaces
|
||||
HTexture oitIndexTexture;
|
||||
HBuffer oitFragmentBuffer;
|
||||
HBuffer oitCounterBuffer;
|
||||
HBuffer oitCounterStagingBuffer;
|
||||
|
||||
UI ui;
|
||||
MipMapGenerator mipMapGen;
|
||||
ImGUI imgui;
|
||||
Nuklear nuklear;
|
||||
WorldOpaque opaque;
|
||||
WorldTransp transp;
|
||||
TranspResolve transpResolve;
|
||||
ToneMap toneMap;
|
||||
GatherDepthOfField gatherDof;
|
||||
AccumDepthOfField accumDof;
|
||||
Fog fog;
|
||||
};
|
||||
|
||||
extern CRP crp;
|
677
code/renderer/crp_main.cpp
Normal file
677
code/renderer/crp_main.cpp
Normal file
|
@ -0,0 +1,677 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - main interface
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
#include "../client/cl_imgui.h"
|
||||
#include "shaders/crp/oit.h.hlsli"
|
||||
namespace blit
|
||||
{
|
||||
#include "compshaders/crp/blit_vs.h"
|
||||
#include "compshaders/crp/blit_ps.h"
|
||||
}
|
||||
namespace ui
|
||||
{
|
||||
#include "compshaders/crp/ui_vs.h"
|
||||
#include "compshaders/crp/ui_ps.h"
|
||||
}
|
||||
namespace imgui
|
||||
{
|
||||
#include "compshaders/crp/imgui_vs.h"
|
||||
#include "compshaders/crp/imgui_ps.h"
|
||||
}
|
||||
namespace nuklear
|
||||
{
|
||||
#include "compshaders/crp/nuklear_vs.h"
|
||||
#include "compshaders/crp/nuklear_ps.h"
|
||||
}
|
||||
namespace mip_1
|
||||
{
|
||||
#include "compshaders/crp/mip_1_cs.h"
|
||||
}
|
||||
namespace mip_2
|
||||
{
|
||||
#include "compshaders/crp/mip_2_cs.h"
|
||||
}
|
||||
namespace mip_3
|
||||
{
|
||||
#include "compshaders/crp/mip_3_cs.h"
|
||||
}
|
||||
|
||||
|
||||
CRP crp;
|
||||
IRenderPipeline* crpp = &crp;
|
||||
|
||||
cvar_t* crp_dof;
|
||||
cvar_t* crp_dof_overlay;
|
||||
cvar_t* crp_dof_blades;
|
||||
cvar_t* crp_dof_angle;
|
||||
cvar_t* crp_gatherDof_focusNearDist;
|
||||
cvar_t* crp_gatherDof_focusNearRange;
|
||||
cvar_t* crp_gatherDof_focusFarDist;
|
||||
cvar_t* crp_gatherDof_focusFarRange;
|
||||
cvar_t* crp_gatherDof_brightness;
|
||||
cvar_t* crp_accumDof_focusDist;
|
||||
cvar_t* crp_accumDof_radius;
|
||||
cvar_t* crp_accumDof_samples;
|
||||
cvar_t* crp_accumDof_preview;
|
||||
|
||||
static const cvarTableItem_t crp_cvars[] =
|
||||
{
|
||||
{
|
||||
&crp_dof, "crp_dof", "1", CVAR_ARCHIVE, CVART_INTEGER, "0", "2",
|
||||
"enables depth of field\n"
|
||||
S_COLOR_VAL " 0 " S_COLOR_HELP "= Disabled\n"
|
||||
S_COLOR_VAL " 1 " S_COLOR_HELP "= Gather (fast, more flexible, issues with transparency)\n"
|
||||
S_COLOR_VAL " 2 " S_COLOR_HELP "= Accumulation (slow, less flexible, great IQ)\n",
|
||||
"DoF mode", CVARCAT_GRAPHICS, "Depth of field mode", "",
|
||||
CVAR_GUI_VALUE("0", "Disabled", "")
|
||||
CVAR_GUI_VALUE("1", "Gather", "Fast, lower IQ")
|
||||
CVAR_GUI_VALUE("2", "Accumulation", "Very slow, great IQ")
|
||||
},
|
||||
{
|
||||
&crp_dof_overlay, "crp_dof_overlay", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "2",
|
||||
"debug overlay mode\n"
|
||||
S_COLOR_VAL " 0 " S_COLOR_HELP "= Disabled\n"
|
||||
S_COLOR_VAL " 1 " S_COLOR_HELP "= Colorized Blur\n"
|
||||
S_COLOR_VAL " 2 " S_COLOR_HELP "= Focus Plane",
|
||||
"DoF overlay mode", CVARCAT_GRAPHICS, "Debug overlay mode", "",
|
||||
CVAR_GUI_VALUE("0", "Disabled", "")
|
||||
CVAR_GUI_VALUE("1", "Colorized Blur", "")
|
||||
CVAR_GUI_VALUE("2", "Focus Plane", "")
|
||||
},
|
||||
{
|
||||
&crp_dof_blades, "crp_dof_blades", "6", CVAR_ARCHIVE, CVART_FLOAT, "0", "16",
|
||||
"aperture blade count\n"
|
||||
"Set to less than 3 for a disk shape.",
|
||||
"DoF blade count", CVARCAT_GRAPHICS, "Aperture blade count", "Set to less than 3 for a disk shape."
|
||||
},
|
||||
{
|
||||
&crp_dof_angle, "crp_dof_angle", "20", CVAR_ARCHIVE, CVART_FLOAT, "0", "360", "aperture angle, in degrees",
|
||||
"DoF aperture angle", CVARCAT_GRAPHICS, "Aperture angle, in degrees", ""
|
||||
},
|
||||
{
|
||||
&crp_accumDof_focusDist, "crp_accumDof_focusDist", "256", CVAR_ARCHIVE, CVART_FLOAT, "2", "2048", "focus distance",
|
||||
"Accum DoF focus distance", CVARCAT_GRAPHICS, "Focus distance", ""
|
||||
},
|
||||
{
|
||||
&crp_accumDof_radius, "crp_accumDof_blurRadius", "0.1", CVAR_ARCHIVE, CVART_FLOAT, "0.001", "20", "aperture radius in world units",
|
||||
"Accum DoF aperture radius", CVARCAT_GRAPHICS, "Aperture radius in world units", ""
|
||||
},
|
||||
{
|
||||
&crp_accumDof_samples, "crp_accumDof_samples", "2", CVAR_ARCHIVE, CVART_INTEGER, "1", "12",
|
||||
"per-axis sampling density\n"
|
||||
"Density N means (2N + 1)(2N + 1) scene renders in total.",
|
||||
"Accum DoF sample count", CVARCAT_GRAPHICS, "Per-axis sampling density", "Density N means (2N + 1)^2 scene renders in total."
|
||||
},
|
||||
{
|
||||
&crp_accumDof_preview, "crp_accumDof_preview", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "2",
|
||||
"low-res preview mode\n"
|
||||
S_COLOR_VAL " 0 " S_COLOR_HELP "= Disabled\n"
|
||||
S_COLOR_VAL " 1 " S_COLOR_HELP "= 1/4 pixel count, 9 samples total\n"
|
||||
S_COLOR_VAL " 2 " S_COLOR_HELP "= 1/16 pixel count, 25 samples total",
|
||||
"Accum DoF preview mode", CVARCAT_GRAPHICS, "Low-resolution preview modes", "",
|
||||
CVAR_GUI_VALUE("0", "Disabled", "")
|
||||
CVAR_GUI_VALUE("1", "1/4 pixel count", "9 samples total")
|
||||
CVAR_GUI_VALUE("2", "1/16 pixel count", "25 samples total")
|
||||
},
|
||||
{
|
||||
&crp_gatherDof_focusNearDist, "crp_gatherDof_focusNearDist", "192", CVAR_ARCHIVE, CVART_FLOAT, "1", "2048", "near focus distance",
|
||||
"Gather DoF near focus distance", CVARCAT_GRAPHICS, "Near focus distance", ""
|
||||
},
|
||||
{
|
||||
&crp_gatherDof_focusNearRange, "crp_gatherDof_focusNearRange", "256", CVAR_ARCHIVE, CVART_FLOAT, "1", "2048", "near focus range",
|
||||
"Gather DoF near focus range", CVARCAT_GRAPHICS, "Near focus range", ""
|
||||
},
|
||||
{
|
||||
&crp_gatherDof_focusFarDist, "crp_gatherDof_focusFarDist", "512", CVAR_ARCHIVE, CVART_FLOAT, "1", "2048", "far focus distance",
|
||||
"Gather DoF far focus distance", CVARCAT_GRAPHICS, "Far focus distance", ""
|
||||
},
|
||||
{
|
||||
&crp_gatherDof_focusFarRange, "crp_gatherDof_focusFarRange", "384", CVAR_ARCHIVE, CVART_FLOAT, "1", "2048", "far focus range",
|
||||
"Gather DoF far focus range", CVARCAT_GRAPHICS, "Far focus range", ""
|
||||
},
|
||||
{
|
||||
&crp_gatherDof_brightness, "crp_gatherDof_brightness", "2", CVAR_ARCHIVE, CVART_FLOAT, "0", "8", "blur brightness weight",
|
||||
"Gather DoF bokeh brightness", CVARCAT_GRAPHICS, "Blur brightness weight", ""
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void PSOCache::Init(Entry* entries_, uint32_t maxEntryCount_)
|
||||
{
|
||||
entries = entries_;
|
||||
maxEntryCount = maxEntryCount_;
|
||||
entryCount = 1; // we treat index 0 as invalid
|
||||
}
|
||||
|
||||
int PSOCache::AddPipeline(const GraphicsPipelineDesc& desc, const char* name)
|
||||
{
|
||||
// we treat index 0 as invalid, so start at 1
|
||||
for(uint32_t i = 1; i < entryCount; ++i)
|
||||
{
|
||||
Entry& entry = entries[i];
|
||||
if(memcmp(&entry.desc, &desc, sizeof(desc)) == 0)
|
||||
{
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_OR_DIE(entryCount < maxEntryCount, "Not enough entries in the PSO cache");
|
||||
|
||||
GraphicsPipelineDesc namedDesc = desc;
|
||||
namedDesc.name = name;
|
||||
|
||||
const uint32_t index = entryCount++;
|
||||
Entry& entry = entries[index];
|
||||
entry.desc = desc; // keep the original desc for proper comparison results
|
||||
entry.handle = CreateGraphicsPipeline(namedDesc);
|
||||
|
||||
return (int)index;
|
||||
}
|
||||
|
||||
void CRP::Init()
|
||||
{
|
||||
static bool veryFirstInit = true;
|
||||
if(veryFirstInit)
|
||||
{
|
||||
ri.Cvar_RegisterTable(crp_cvars, ARRAY_LEN(crp_cvars));
|
||||
veryFirstInit = false;
|
||||
}
|
||||
|
||||
InitDesc initDesc;
|
||||
initDesc.directDescriptorHeapIndexing = true;
|
||||
srp.firstInit = RHI::Init(initDesc);
|
||||
srp.psoStatsValid = false;
|
||||
|
||||
if(srp.firstInit)
|
||||
{
|
||||
srp.CreateShaderTraceBuffers();
|
||||
|
||||
for(uint32_t f = 0; f < FrameCount; ++f)
|
||||
{
|
||||
// the doubled index count is for the depth pre-pass
|
||||
const int MaxDynamicVertexCount = 16 << 20;
|
||||
const int MaxDynamicIndexCount = MaxDynamicVertexCount * 4;
|
||||
GeoBuffers& db = dynBuffers[f];
|
||||
db.Create(va("world #%d", f + 1), MaxDynamicVertexCount, MaxDynamicIndexCount);
|
||||
}
|
||||
}
|
||||
|
||||
// we recreate the samplers on every vid_restart to create the right level
|
||||
// of anisotropy based on the latched CVar
|
||||
for(uint32_t w = 0; w < TW_COUNT; ++w)
|
||||
{
|
||||
for(uint32_t f = 0; f < TextureFilter::Count; ++f)
|
||||
{
|
||||
for(uint32_t m = 0; m < MaxTextureMips; ++m)
|
||||
{
|
||||
const textureWrap_t wrap = (textureWrap_t)w;
|
||||
const TextureFilter::Id filter = (TextureFilter::Id)f;
|
||||
const uint32_t s = GetBaseSamplerIndex(wrap, filter, m);
|
||||
SamplerDesc desc(wrap, filter, (float)m);
|
||||
desc.shortLifeTime = true;
|
||||
samplers[s] = CreateSampler(desc);
|
||||
samplerIndices[s] = RHI::GetSamplerIndex(samplers[s]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
renderTargetFormat = TextureFormat::RGBA64_Float;
|
||||
|
||||
TextureDesc desc("render target #1", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit;
|
||||
Vector4Clear(desc.clearColor);
|
||||
desc.usePreferredClearValue = true;
|
||||
desc.committedResource = true;
|
||||
desc.format = renderTargetFormat;
|
||||
desc.shortLifeTime = true;
|
||||
renderTargets[0] = RHI::CreateTexture(desc);
|
||||
desc.name = "render target #2";
|
||||
renderTargets[1] = RHI::CreateTexture(desc);
|
||||
renderTargetIndex = 0;
|
||||
renderTarget = renderTargets[0];
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("readback render target", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit;
|
||||
Vector4Clear(desc.clearColor);
|
||||
desc.usePreferredClearValue = true;
|
||||
desc.committedResource = true;
|
||||
desc.format = TextureFormat::RGBA32_UNorm;
|
||||
desc.shortLifeTime = true;
|
||||
readbackRenderTarget = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("OIT index", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.initialState = ResourceStates::UnorderedAccessBit;
|
||||
desc.allowedState = ResourceStates::UnorderedAccessBit | ResourceStates::PixelShaderAccessBit | ResourceStates::ComputeShaderAccessBit;
|
||||
desc.committedResource = true;
|
||||
desc.format = TextureFormat::R32_UInt;
|
||||
desc.shortLifeTime = true;
|
||||
oitIndexTexture = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
||||
uint32_t oitMaxFragmentCount = 0;
|
||||
{
|
||||
const int byteCountPerFragment = sizeof(OIT_Fragment);
|
||||
const int fragmentCount = glConfig.vidWidth * glConfig.vidHeight * OIT_AVG_FRAGMENTS_PER_PIXEL;
|
||||
const int byteCount = byteCountPerFragment * fragmentCount;
|
||||
oitMaxFragmentCount = fragmentCount;
|
||||
|
||||
BufferDesc desc("OIT fragment", byteCount, ResourceStates::UnorderedAccessBit);
|
||||
desc.committedResource = true;
|
||||
desc.memoryUsage = MemoryUsage::GPU;
|
||||
desc.structureByteCount = byteCountPerFragment;
|
||||
desc.shortLifeTime = true;
|
||||
oitFragmentBuffer = CreateBuffer(desc);
|
||||
}
|
||||
|
||||
{
|
||||
const int byteCount = sizeof(OIT_Counter);
|
||||
|
||||
{
|
||||
BufferDesc desc("OIT counter", byteCount, ResourceStates::UnorderedAccessBit);
|
||||
desc.committedResource = true;
|
||||
desc.memoryUsage = MemoryUsage::GPU;
|
||||
desc.structureByteCount = byteCount;
|
||||
desc.shortLifeTime = true;
|
||||
oitCounterBuffer = CreateBuffer(desc);
|
||||
}
|
||||
{
|
||||
BufferDesc desc("OIT counter staging", byteCount, ResourceStates::Common);
|
||||
desc.committedResource = false;
|
||||
desc.memoryUsage = MemoryUsage::Upload;
|
||||
desc.structureByteCount = byteCount;
|
||||
desc.shortLifeTime = true;
|
||||
oitCounterStagingBuffer = CreateBuffer(desc);
|
||||
|
||||
uint32_t* dst = (uint32_t*)MapBuffer(oitCounterStagingBuffer);
|
||||
dst[0] = 1; // fragment index 0 is the end-of-list value
|
||||
dst[1] = oitMaxFragmentCount;
|
||||
dst[2] = 0;
|
||||
UnmapBuffer(oitCounterStagingBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("depth buffer", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.committedResource = true;
|
||||
desc.shortLifeTime = true;
|
||||
desc.initialState = ResourceStates::DepthWriteBit;
|
||||
desc.allowedState = ResourceStates::DepthAccessBits | ResourceStates::PixelShaderAccessBit;
|
||||
desc.format = TextureFormat::Depth32_Float;
|
||||
desc.SetClearDepthStencil(0.0f, 0);
|
||||
depthTexture = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("blit LDR");
|
||||
desc.vertexShader = ShaderByteCode(blit::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(blit::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, TextureFormat::RGBA32_UNorm);
|
||||
blitPipelineLDR = CreateGraphicsPipeline(desc);
|
||||
desc.name = "blit HDR";
|
||||
desc.renderTargets[0].format = TextureFormat::RGBA64_Float;
|
||||
blitPipelineHDR = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
ui.Init(true, ShaderByteCode(ui::g_vs), ShaderByteCode(ui::g_ps), renderTargetFormat, RHI_MAKE_NULL_HANDLE(), NULL);
|
||||
imgui.Init(true, ShaderByteCode(imgui::g_vs), ShaderByteCode(imgui::g_ps), renderTargetFormat, RHI_MAKE_NULL_HANDLE(), NULL);
|
||||
nuklear.Init(true, ShaderByteCode(nuklear::g_vs), ShaderByteCode(nuklear::g_ps), renderTargetFormat, RHI_MAKE_NULL_HANDLE(), NULL);
|
||||
mipMapGen.Init(true, ShaderByteCode(mip_1::g_cs), ShaderByteCode(mip_2::g_cs), ShaderByteCode(mip_3::g_cs));
|
||||
opaque.Init();
|
||||
transp.Init();
|
||||
transpResolve.Init();
|
||||
toneMap.Init();
|
||||
gatherDof.Init();
|
||||
accumDof.Init();
|
||||
fog.Init();
|
||||
|
||||
srp.firstInit = false;
|
||||
}
|
||||
|
||||
void CRP::ShutDown(bool fullShutDown)
|
||||
{
|
||||
RHI::ShutDown(fullShutDown);
|
||||
}
|
||||
|
||||
void CRP::BeginFrame()
|
||||
{
|
||||
renderTargetIndex = 0;
|
||||
renderTarget = renderTargets[0];
|
||||
|
||||
srp.BeginFrame();
|
||||
|
||||
// have it be first to we can use ImGUI in the other components too
|
||||
imgui.BeginFrame();
|
||||
|
||||
RHI::BeginFrame();
|
||||
ui.BeginFrame();
|
||||
nuklear.BeginFrame();
|
||||
|
||||
const float clearColor[4] = { 0.0f, 0.5f, 0.0f, 0.0f };
|
||||
const TextureBarrier barrier(renderTarget, ResourceStates::RenderTargetBit);
|
||||
CmdBarrier(1, &barrier);
|
||||
CmdClearColorTarget(renderTarget, clearColor);
|
||||
|
||||
frameSeed = (float)rand() / (float)RAND_MAX;
|
||||
|
||||
dynBuffers[GetFrameIndex()].Rewind();
|
||||
}
|
||||
|
||||
void CRP::EndFrame()
|
||||
{
|
||||
srp.DrawGUI();
|
||||
imgui.Draw(renderTarget);
|
||||
toneMap.DrawToneMap();
|
||||
BlitRenderTarget(GetSwapChainTexture(), "Blit to Swap Chain");
|
||||
BlitRenderTarget(readbackRenderTarget, "Blit to Readback Texture");
|
||||
srp.EndFrame();
|
||||
}
|
||||
|
||||
void CRP::Blit(HTexture destination, HTexture source, const char* passName, bool hdr, const vec2_t tcScale, const vec2_t tcBias)
|
||||
{
|
||||
SCOPED_RENDER_PASS(passName, 0.125f, 0.125f, 0.5f);
|
||||
|
||||
const TextureBarrier barriers[2] =
|
||||
{
|
||||
TextureBarrier(source, ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(destination, ResourceStates::RenderTargetBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(barriers), barriers);
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct BlitRC
|
||||
{
|
||||
uint32_t textureIndex;
|
||||
uint32_t samplerIndex;
|
||||
float tcScale[2];
|
||||
float tcBias[2];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
BlitRC rc;
|
||||
rc.textureIndex = GetTextureIndexSRV(source);
|
||||
rc.samplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Linear);
|
||||
rc.tcScale[0] = tcScale[0];
|
||||
rc.tcScale[1] = tcScale[1];
|
||||
rc.tcBias[0] = tcBias[0];
|
||||
rc.tcBias[1] = tcBias[0];
|
||||
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
CmdBindRenderTargets(1, &destination, NULL);
|
||||
CmdBindPipeline(hdr ? blitPipelineHDR : blitPipelineLDR);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
|
||||
void CRP::BlitRenderTarget(HTexture destination, const char* passName)
|
||||
{
|
||||
Blit(destination, crp.renderTarget, passName, false, vec2_one, vec2_zero);
|
||||
}
|
||||
|
||||
void CRP::CreateTexture(image_t* image, int mipCount, int width, int height)
|
||||
{
|
||||
TextureDesc desc(image->name, width, height, mipCount);
|
||||
desc.committedResource = width * height >= (1 << 20);
|
||||
desc.shortLifeTime = true;
|
||||
if(mipCount > 1)
|
||||
{
|
||||
desc.allowedState |= ResourceStates::UnorderedAccessBit; // for mip-map generation
|
||||
}
|
||||
|
||||
image->texture = ::RHI::CreateTexture(desc);
|
||||
image->textureIndex = GetTextureIndexSRV(image->texture);
|
||||
}
|
||||
|
||||
void CRP::UpoadTextureAndGenerateMipMaps(image_t* image, const byte* data)
|
||||
{
|
||||
MappedTexture texture;
|
||||
RHI::BeginTextureUpload(texture, image->texture);
|
||||
for(uint32_t r = 0; r < texture.rowCount; ++r)
|
||||
{
|
||||
memcpy(texture.mappedData + r * texture.dstRowByteCount, data + r * texture.srcRowByteCount, texture.srcRowByteCount);
|
||||
}
|
||||
RHI::EndTextureUpload();
|
||||
|
||||
mipMapGen.GenerateMipMaps(image->texture);
|
||||
}
|
||||
|
||||
void CRP::BeginTextureUpload(MappedTexture& mappedTexture, image_t* image)
|
||||
{
|
||||
RHI::BeginTextureUpload(mappedTexture, image->texture);
|
||||
}
|
||||
|
||||
void CRP::EndTextureUpload()
|
||||
{
|
||||
RHI::EndTextureUpload();
|
||||
}
|
||||
|
||||
void CRP::ProcessWorld(world_t&)
|
||||
{
|
||||
}
|
||||
|
||||
void CRP::ProcessModel(model_t&)
|
||||
{
|
||||
}
|
||||
|
||||
void CRP::ProcessShader(shader_t& shader)
|
||||
{
|
||||
if(shader.isOpaque)
|
||||
{
|
||||
opaque.ProcessShader(shader);
|
||||
}
|
||||
else
|
||||
{
|
||||
transp.ProcessShader(shader);
|
||||
}
|
||||
}
|
||||
|
||||
void CRP::ExecuteRenderCommands(const byte* data, bool /*readbackRequested*/)
|
||||
{
|
||||
// @NOTE: the CRP always blits the final result to the readback texture
|
||||
|
||||
for(;;)
|
||||
{
|
||||
const int commandId = ((const renderCommandBase_t*)data)->commandId;
|
||||
|
||||
if(commandId < 0 || commandId >= RC_COUNT)
|
||||
{
|
||||
assert(!"Invalid render command type");
|
||||
return;
|
||||
}
|
||||
|
||||
if(commandId == RC_END_OF_LIST)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(commandId)
|
||||
{
|
||||
case RC_UI_SET_COLOR:
|
||||
ui.CmdSetColor(*(const uiSetColorCommand_t*)data);
|
||||
break;
|
||||
case RC_UI_DRAW_QUAD:
|
||||
ui.CmdDrawQuad(*(const uiDrawQuadCommand_t*)data);
|
||||
break;
|
||||
case RC_UI_DRAW_TRIANGLE:
|
||||
ui.CmdDrawTriangle(*(const uiDrawTriangleCommand_t*)data);
|
||||
break;
|
||||
case RC_DRAW_SCENE_VIEW:
|
||||
DrawSceneView(*(const drawSceneViewCommand_t*)data);
|
||||
break;
|
||||
case RC_BEGIN_FRAME:
|
||||
BeginFrame();
|
||||
break;
|
||||
case RC_SWAP_BUFFERS:
|
||||
EndFrame();
|
||||
break;
|
||||
case RC_BEGIN_UI:
|
||||
ui.Begin(renderTarget);
|
||||
break;
|
||||
case RC_END_UI:
|
||||
ui.End();
|
||||
break;
|
||||
case RC_BEGIN_3D:
|
||||
// @TODO:
|
||||
srp.renderMode = RenderMode::None;
|
||||
break;
|
||||
case RC_END_3D:
|
||||
// @TODO:
|
||||
srp.renderMode = RenderMode::None;
|
||||
break;
|
||||
case RC_END_SCENE:
|
||||
// @TODO: post-processing
|
||||
break;
|
||||
case RC_BEGIN_NK:
|
||||
nuklear.Begin(renderTarget);
|
||||
break;
|
||||
case RC_END_NK:
|
||||
nuklear.End();
|
||||
break;
|
||||
case RC_NK_UPLOAD:
|
||||
nuklear.Upload(*(const nuklearUploadCommand_t*)data);
|
||||
break;
|
||||
case RC_NK_DRAW:
|
||||
nuklear.Draw(*(const nuklearDrawCommand_t*)data);
|
||||
break;
|
||||
default:
|
||||
Q_assert(!"Unsupported render command type");
|
||||
return;
|
||||
}
|
||||
|
||||
data += renderCommandSizes[commandId];
|
||||
}
|
||||
}
|
||||
|
||||
void CRP::TessellationOverflow()
|
||||
{
|
||||
switch(tess.tessellator)
|
||||
{
|
||||
case Tessellator::Opaque: opaque.TessellationOverflow(); break;
|
||||
case Tessellator::Transp: transp.TessellationOverflow(); break;
|
||||
default: break;
|
||||
}
|
||||
tess.numIndexes = 0;
|
||||
tess.numVertexes = 0;
|
||||
}
|
||||
|
||||
void CRP::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
||||
{
|
||||
const viewParms_t& vp = cmd.viewParms;
|
||||
if(cmd.shouldClearColor)
|
||||
{
|
||||
const Rect rect(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight);
|
||||
const TextureBarrier tb(renderTarget, ResourceStates::RenderTargetBit);
|
||||
CmdBarrier(1, &tb);
|
||||
CmdClearColorTarget(renderTarget, cmd.clearColor, &rect);
|
||||
}
|
||||
|
||||
if(cmd.numDrawSurfs <= 0 || !cmd.shouldDrawScene)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(crp_dof->integer == DOFMethod::Accumulation &&
|
||||
vp.viewportX == 0 &&
|
||||
vp.viewportY == 0 &&
|
||||
vp.viewportWidth == glConfig.vidWidth &&
|
||||
vp.viewportHeight == glConfig.vidHeight)
|
||||
{
|
||||
const Rect rect(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
accumDof.Begin(cmd);
|
||||
const uint32_t sampleCount = accumDof.GetSampleCount();
|
||||
for(uint32_t y = 0; y < sampleCount; y++)
|
||||
{
|
||||
for(uint32_t x = 0; x < sampleCount; x++)
|
||||
{
|
||||
srp.enableRenderPassQueries = x == 0 && y == 0;
|
||||
drawSceneViewCommand_t newCmd;
|
||||
accumDof.FixCommand(newCmd, cmd, x, y);
|
||||
const TextureBarrier tb(renderTarget, ResourceStates::RenderTargetBit);
|
||||
CmdBarrier(1, &tb);
|
||||
CmdClearColorTarget(renderTarget, cmd.clearColor, &rect);
|
||||
opaque.Draw(newCmd);
|
||||
fog.Draw();
|
||||
transp.Draw(newCmd);
|
||||
transpResolve.Draw(newCmd);
|
||||
accumDof.Accumulate();
|
||||
|
||||
// geometry allocation is a linear allocation instead of a ring buffer
|
||||
// we force a CPU-GPU sync point after every full scene render
|
||||
// that way, we can keep the buffer sizes at least somewhat reasonable
|
||||
SubmitAndContinue();
|
||||
dynBuffers[GetFrameIndex()].Rewind();
|
||||
}
|
||||
}
|
||||
CmdSetViewportAndScissor(backEnd.viewParms);
|
||||
srp.enableRenderPassQueries = true;
|
||||
accumDof.Normalize();
|
||||
backEnd.viewParms = cmd.viewParms;
|
||||
backEnd.refdef = cmd.refdef;
|
||||
accumDof.DrawDebug();
|
||||
}
|
||||
else
|
||||
{
|
||||
opaque.Draw(cmd);
|
||||
fog.Draw();
|
||||
transp.Draw(cmd);
|
||||
transpResolve.Draw(cmd);
|
||||
CmdSetViewportAndScissor(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight);
|
||||
gatherDof.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
void CRP::ReadPixels(int w, int h, int alignment, colorSpace_t colorSpace, void* outPixels)
|
||||
{
|
||||
ReadTextureImage(outPixels, readbackRenderTarget, w, h, alignment, colorSpace);
|
||||
}
|
||||
|
||||
uint32_t CRP::GetSamplerDescriptorIndexFromBaseIndex(uint32_t baseIndex)
|
||||
{
|
||||
Q_assert(baseIndex < ARRAY_LEN(samplerIndices));
|
||||
|
||||
return samplerIndices[baseIndex];
|
||||
}
|
||||
|
||||
HTexture CRP::GetReadRenderTarget()
|
||||
{
|
||||
return renderTargets[renderTargetIndex ^ 1];
|
||||
}
|
||||
|
||||
HTexture CRP::GetWriteRenderTarget()
|
||||
{
|
||||
return renderTargets[renderTargetIndex];
|
||||
}
|
||||
|
||||
void CRP::SwapRenderTargets()
|
||||
{
|
||||
renderTargetIndex ^= 1;
|
||||
renderTarget = GetWriteRenderTarget();
|
||||
}
|
376
code/renderer/crp_opaque.cpp
Normal file
376
code/renderer/crp_opaque.cpp
Normal file
|
@ -0,0 +1,376 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - opaque surfaces
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
namespace opaque
|
||||
{
|
||||
#include "compshaders/crp/opaque_vs.h"
|
||||
#include "compshaders/crp/opaque_ps.h"
|
||||
}
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
struct OpaqueVertexRC : WorldVertexRC
|
||||
{
|
||||
};
|
||||
|
||||
struct OpaquePixelRC
|
||||
{
|
||||
// general
|
||||
uint32_t textureIndex;
|
||||
uint32_t samplerIndex;
|
||||
uint32_t shaderIndexBufferIndex;
|
||||
uint32_t alphaTest;
|
||||
float greyscale;
|
||||
|
||||
// shader trace
|
||||
uint32_t shaderTrace; // shader index: 14 - frame index: 2 - enable: 1
|
||||
uint16_t centerPixelX;
|
||||
uint16_t centerPixelY;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
void WorldOpaque::Init()
|
||||
{
|
||||
psoCache.Init(psoCacheEntries, ARRAY_LEN(psoCacheEntries));
|
||||
}
|
||||
|
||||
void WorldOpaque::Draw(const drawSceneViewCommand_t& cmd)
|
||||
{
|
||||
if(cmd.numDrawSurfs - cmd.numTranspSurfs <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
srp.renderMode = RenderMode::World;
|
||||
|
||||
backEnd.refdef = cmd.refdef;
|
||||
backEnd.viewParms = cmd.viewParms;
|
||||
|
||||
if(backEnd.viewParms.isPortal)
|
||||
{
|
||||
float plane[4];
|
||||
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||||
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||||
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||||
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||||
|
||||
float plane2[4];
|
||||
plane2[0] = DotProduct(backEnd.viewParms.orient.axis[0], plane);
|
||||
plane2[1] = DotProduct(backEnd.viewParms.orient.axis[1], plane);
|
||||
plane2[2] = DotProduct(backEnd.viewParms.orient.axis[2], plane);
|
||||
plane2[3] = DotProduct(plane, backEnd.viewParms.orient.origin) - plane[3];
|
||||
|
||||
float* o = plane;
|
||||
const float* m = s_flipMatrix;
|
||||
const float* v = plane2;
|
||||
o[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3];
|
||||
o[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3];
|
||||
o[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3];
|
||||
o[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3];
|
||||
|
||||
memcpy(clipPlane, plane, sizeof(clipPlane));
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(clipPlane, 0, sizeof(clipPlane));
|
||||
}
|
||||
|
||||
CmdSetViewportAndScissor(backEnd.viewParms);
|
||||
batchOldDepthHack = false;
|
||||
batchDepthHack = false;
|
||||
|
||||
TextureBarrier tb(crp.depthTexture, ResourceStates::DepthWriteBit);
|
||||
BufferBarrier bb(srp.traceRenderBuffer, ResourceStates::UnorderedAccessBit);
|
||||
CmdBarrier(1, &tb, 1, &bb);
|
||||
|
||||
CmdClearDepthStencilTarget(crp.depthTexture, true, 0.0f);
|
||||
|
||||
GeoBuffers& db = crp.dynBuffers[GetFrameIndex()];
|
||||
db.BeginUpload();
|
||||
|
||||
SCOPED_RENDER_PASS("Opaque", 1.0f, 0.5f, 0.5f);
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, &crp.depthTexture);
|
||||
CmdBindVertexBuffers(ARRAY_LEN(db.vertexBuffers), db.vertexBuffers, db.vertexBufferStrides, NULL);
|
||||
CmdBindIndexBuffer(db.indexBuffer.buffer, IndexType::UInt32, 0);
|
||||
|
||||
const drawSurf_t* drawSurfs = cmd.drawSurfs;
|
||||
const int surfCount = cmd.numDrawSurfs - cmd.numTranspSurfs;
|
||||
const double originalTime = backEnd.refdef.floatTime;
|
||||
|
||||
const shader_t* shader = NULL;
|
||||
const shader_t* oldShader = NULL;
|
||||
int oldEntityNum = -1;
|
||||
backEnd.currentEntity = &tr.worldEntity;
|
||||
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
|
||||
int ds;
|
||||
const drawSurf_t* drawSurf;
|
||||
for(ds = 0, drawSurf = drawSurfs; ds < surfCount; ++ds, ++drawSurf)
|
||||
{
|
||||
int entityNum;
|
||||
R_DecomposeSort(drawSurf->sort, &entityNum, &shader);
|
||||
Q_assert(shader != NULL);
|
||||
Q_assert(shader->isOpaque);
|
||||
|
||||
// sky shaders can have no stages and be valid (box drawn with no clouds)
|
||||
if(!shader->isSky)
|
||||
{
|
||||
if(shader->numPipelines == 0 ||
|
||||
shader->pipelines[0].pipeline <= 0 ||
|
||||
shader->pipelines[0].numStages <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const bool shaderChanged = shader != oldShader;
|
||||
const bool entityChanged = entityNum != oldEntityNum;
|
||||
if(shaderChanged || entityChanged)
|
||||
{
|
||||
oldShader = shader;
|
||||
oldEntityNum = entityNum;
|
||||
EndSkyBatch();
|
||||
EndBatch();
|
||||
BeginBatch(shader);
|
||||
tess.greyscale = drawSurf->greyscale;
|
||||
}
|
||||
|
||||
if(entityChanged)
|
||||
{
|
||||
UpdateEntityData(batchDepthHack, entityNum, originalTime);
|
||||
}
|
||||
|
||||
R_TessellateSurface(drawSurf->surface);
|
||||
}
|
||||
|
||||
backEnd.refdef.floatTime = originalTime;
|
||||
|
||||
EndSkyBatch();
|
||||
EndBatch();
|
||||
|
||||
db.EndUpload();
|
||||
|
||||
// restores the potentially "hacked" depth range as well
|
||||
CmdSetViewportAndScissor(backEnd.viewParms);
|
||||
batchOldDepthHack = false;
|
||||
batchDepthHack = false;
|
||||
}
|
||||
|
||||
void WorldOpaque::ProcessShader(shader_t& shader)
|
||||
{
|
||||
Q_assert(shader.isOpaque || shader.isSky);
|
||||
|
||||
if(shader.numStages < 1)
|
||||
{
|
||||
shader.numPipelines = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const bool clampDepth = r_depthClamp->integer != 0 || shader.isSky;
|
||||
|
||||
for(int s = 0; s < shader.numStages; ++s)
|
||||
{
|
||||
const shaderStage_t& stage = *shader.stages[s];
|
||||
const unsigned int stateBits = stage.stateBits & (~GLS_POLYMODE_LINE);
|
||||
int a = 0;
|
||||
|
||||
// @NOTE: we are not using any CTOR because we deliberately want to 0-init the struct
|
||||
// this is necessary for padding bytes not to mess up comparisons in the PSO cache
|
||||
GraphicsPipelineDesc desc = {};
|
||||
desc.name = "opaque";
|
||||
desc.rootSignature = RHI_MAKE_NULL_HANDLE();
|
||||
desc.shortLifeTime = true; // the PSO cache is only valid for this map!
|
||||
desc.vertexShader = opaque::g_vs;
|
||||
desc.pixelShader = opaque::g_ps;
|
||||
desc.vertexLayout.AddAttribute(a++, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
||||
desc.vertexLayout.AddAttribute(a++, ShaderSemantic::Normal, DataType::Float32, 2, 0);
|
||||
desc.vertexLayout.AddAttribute(a++, ShaderSemantic::TexCoord, DataType::Float32, 2, 0);
|
||||
desc.vertexLayout.AddAttribute(a++, ShaderSemantic::Color, DataType::UNorm8, 4, 0);
|
||||
desc.depthStencil.depthStencilFormat = TextureFormat::Depth32_Float;
|
||||
desc.depthStencil.depthComparison =
|
||||
(stateBits & GLS_DEPTHFUNC_EQUAL) != 0 ?
|
||||
ComparisonFunction::Equal :
|
||||
ComparisonFunction::GreaterEqual;
|
||||
desc.depthStencil.enableDepthTest = (stateBits & GLS_DEPTHTEST_DISABLE) == 0;
|
||||
desc.depthStencil.enableDepthWrites = (stateBits & GLS_DEPTHMASK_TRUE) != 0;
|
||||
desc.rasterizer.cullMode = shader.cullType;
|
||||
desc.rasterizer.polygonOffset = shader.polygonOffset != 0;
|
||||
desc.rasterizer.clampDepth = clampDepth;
|
||||
desc.AddRenderTarget(stateBits & GLS_BLEND_BITS, crp.renderTargetFormat);
|
||||
|
||||
pipeline_t& p = shader.pipelines[s];
|
||||
p.firstStage = s;
|
||||
p.numStages = 1;
|
||||
p.pipeline = psoCache.AddPipeline(desc, va("opaque %d %d", psoCache.entryCount, s + 1));
|
||||
desc.rasterizer.cullMode = GetMirrorredCullType(desc.rasterizer.cullMode);
|
||||
p.mirrorPipeline = psoCache.AddPipeline(desc, va("opaque %d %d mirrored", psoCache.entryCount, s + 1));
|
||||
}
|
||||
|
||||
shader.numPipelines = shader.numStages;
|
||||
}
|
||||
|
||||
void WorldOpaque::TessellationOverflow()
|
||||
{
|
||||
EndBatch();
|
||||
BeginBatch(tess.shader);
|
||||
}
|
||||
|
||||
void WorldOpaque::BeginBatch(const shader_t* shader)
|
||||
{
|
||||
tess.tessellator = Tessellator::Opaque;
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
tess.depthFade = DFT_NONE;
|
||||
tess.deformsPreApplied = qfalse;
|
||||
tess.xstages = (const shaderStage_t**)shader->stages;
|
||||
tess.shader = shader;
|
||||
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
|
||||
if(tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime)
|
||||
{
|
||||
tess.shaderTime = tess.shader->clampTime;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldOpaque::EndBatch()
|
||||
{
|
||||
const int vertexCount = tess.numVertexes;
|
||||
const int indexCount = tess.numIndexes;
|
||||
if(vertexCount <= 0 ||
|
||||
indexCount <= 0 ||
|
||||
tess.shader->numStages == 0 ||
|
||||
tess.shader->numPipelines <= 0)
|
||||
{
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
const shader_t* const shader = tess.shader;
|
||||
|
||||
GeoBuffers& db = crp.dynBuffers[GetFrameIndex()];
|
||||
if(!db.CanAdd(vertexCount, indexCount, shader->numStages))
|
||||
{
|
||||
Q_assert(!"World surface geometry buffer too small!");
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
RB_DeformTessGeometry(0, vertexCount, 0, indexCount);
|
||||
db.UploadBase();
|
||||
|
||||
if(batchDepthHack != batchOldDepthHack)
|
||||
{
|
||||
const viewParms_t& vp = backEnd.viewParms;
|
||||
CmdSetViewport(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight, batchDepthHack ? 0.7f : 0.0f, 1.0f);
|
||||
batchOldDepthHack = batchDepthHack;
|
||||
}
|
||||
|
||||
OpaqueVertexRC vertexRC = {};
|
||||
memcpy(vertexRC.modelViewMatrix, backEnd.orient.modelMatrix, sizeof(vertexRC.modelViewMatrix));
|
||||
memcpy(vertexRC.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(vertexRC.projectionMatrix));
|
||||
memcpy(vertexRC.clipPlane, clipPlane, sizeof(vertexRC.clipPlane));
|
||||
CmdSetGraphicsRootConstants(0, sizeof(vertexRC), &vertexRC);
|
||||
|
||||
for(int s = 0; s < shader->numStages; ++s)
|
||||
{
|
||||
const shaderStage_t* const stage = shader->stages[s];
|
||||
|
||||
R_ComputeColors(stage, tess.svars[0], 0, vertexCount);
|
||||
R_ComputeTexCoords(stage, tess.svars[0], 0, vertexCount, qfalse);
|
||||
db.UploadStage(0);
|
||||
|
||||
const pipeline_t& pipeline = shader->pipelines[s];
|
||||
const int psoIndex = backEnd.viewParms.isMirror ? pipeline.mirrorPipeline : pipeline.pipeline;
|
||||
Q_assert(psoIndex > 0);
|
||||
CmdBindPipeline(psoCache.entries[psoIndex].handle);
|
||||
|
||||
const image_t* image = GetBundleImage(stage->bundle);
|
||||
const uint32_t texIdx = image->textureIndex;
|
||||
const uint32_t sampIdx = GetSamplerIndex(image);
|
||||
const uint32_t alphaTest = AlphaTestShaderConstFromStateBits(stage->stateBits);
|
||||
const uint32_t enableShaderTrace = tr.traceWorldShader && s == 0 ? 1 : 0;
|
||||
const uint32_t bufferIndex = GetBufferIndexUAV(srp.traceRenderBuffer);
|
||||
Q_assert(sampIdx < ARRAY_LEN(crp.samplers));
|
||||
|
||||
OpaquePixelRC pixelRC = {};
|
||||
pixelRC.textureIndex = texIdx;
|
||||
pixelRC.samplerIndex = sampIdx;
|
||||
pixelRC.shaderIndexBufferIndex = bufferIndex;
|
||||
pixelRC.alphaTest = alphaTest;
|
||||
pixelRC.greyscale = tess.greyscale;
|
||||
pixelRC.shaderTrace = ((uint32_t)shader->index << 3) | (RHI::GetFrameIndex() << 1) | enableShaderTrace;
|
||||
pixelRC.centerPixelX = glConfig.vidWidth / 2;
|
||||
pixelRC.centerPixelY = glConfig.vidHeight / 2;
|
||||
CmdSetGraphicsRootConstants(sizeof(vertexRC), sizeof(pixelRC), &pixelRC);
|
||||
|
||||
db.DrawStage(vertexCount, indexCount);
|
||||
}
|
||||
|
||||
db.EndBaseBatch(vertexCount);
|
||||
|
||||
clean_up:
|
||||
tess.tessellator = Tessellator::None;
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
}
|
||||
|
||||
void WorldOpaque::EndSkyBatch()
|
||||
{
|
||||
// this only exists as a separate function from EndBatch so that
|
||||
// we don't have to deal with recursion (through the call to RB_DrawSky)
|
||||
|
||||
if(tess.shader == NULL ||
|
||||
!tess.shader->isSky ||
|
||||
tess.numVertexes <= 0 ||
|
||||
tess.numIndexes <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPED_RENDER_PASS("Sky", 0.0, 0.5f, 1.0f);
|
||||
|
||||
const viewParms_t& vp = backEnd.viewParms;
|
||||
CmdSetViewport(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight, 0.0f, 0.0f);
|
||||
RB_DrawSky();
|
||||
CmdSetViewport(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight, 0.0f, 1.0f);
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
}
|
||||
|
||||
void WorldOpaque::DrawSkyBox()
|
||||
{
|
||||
// force creation of a PSO for the temp shader
|
||||
ProcessShader((shader_t&)*tess.shader);
|
||||
|
||||
tess.deformsPreApplied = qtrue;
|
||||
EndBatch();
|
||||
}
|
||||
|
||||
void WorldOpaque::DrawClouds()
|
||||
{
|
||||
EndBatch();
|
||||
}
|
139
code/renderer/crp_tone_map.cpp
Normal file
139
code/renderer/crp_tone_map.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - tone mapping
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
namespace tone_map
|
||||
{
|
||||
#include "compshaders/crp/tone_map_vs.h"
|
||||
#include "compshaders/crp/tone_map_ps.h"
|
||||
}
|
||||
namespace inverse_tone_map
|
||||
{
|
||||
#include "compshaders/crp/tone_map_inverse_vs.h"
|
||||
#include "compshaders/crp/tone_map_inverse_ps.h"
|
||||
}
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
struct ToneMapRC
|
||||
{
|
||||
uint32_t textureIndex;
|
||||
uint32_t samplerIndex;
|
||||
float invGamma;
|
||||
float brightness;
|
||||
float greyscale;
|
||||
};
|
||||
|
||||
struct InverseToneMapRC
|
||||
{
|
||||
uint32_t textureIndex;
|
||||
uint32_t samplerIndex;
|
||||
float gamma;
|
||||
float invBrightness;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
void ToneMap::Init()
|
||||
{
|
||||
{
|
||||
GraphicsPipelineDesc desc("Tone Map");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(tone_map::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(tone_map::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
pipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("Inverse Tone Map");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(tone_map::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(tone_map::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
pipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void ToneMap::DrawToneMap()
|
||||
{
|
||||
srp.renderMode = RenderMode::None;
|
||||
|
||||
SCOPED_RENDER_PASS("Tone Map", 1.0f, 1.0f, 1.0f);
|
||||
|
||||
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
||||
crp.SwapRenderTargets();
|
||||
const TextureBarrier texBarriers[] =
|
||||
{
|
||||
TextureBarrier(crp.GetReadRenderTarget(), ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.GetWriteRenderTarget(), ResourceStates::RenderTargetBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(texBarriers), texBarriers, 0, NULL);
|
||||
|
||||
ToneMapRC rc = {};
|
||||
rc.textureIndex = GetTextureIndexSRV(crp.GetReadRenderTarget());
|
||||
rc.samplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Linear);
|
||||
rc.invGamma = 1.0f / r_gamma->value;
|
||||
rc.brightness = r_brightness->value;
|
||||
rc.greyscale = r_greyscale->value;
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
CmdBindPipeline(pipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
|
||||
void ToneMap::DrawInverseToneMap()
|
||||
{
|
||||
srp.renderMode = RenderMode::None;
|
||||
|
||||
SCOPED_RENDER_PASS("Inverse Tone Map", 1.0f, 1.0f, 1.0f);
|
||||
|
||||
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
||||
crp.SwapRenderTargets();
|
||||
const TextureBarrier texBarriers[] =
|
||||
{
|
||||
TextureBarrier(crp.GetReadRenderTarget(), ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.GetWriteRenderTarget(), ResourceStates::RenderTargetBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(texBarriers), texBarriers, 0, NULL);
|
||||
|
||||
InverseToneMapRC rc = {};
|
||||
rc.textureIndex = GetTextureIndexSRV(crp.GetReadRenderTarget());
|
||||
rc.samplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Linear);
|
||||
rc.gamma = r_gamma->value;
|
||||
rc.invBrightness = 1.0f / r_brightness->value;
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
CmdBindPipeline(inversePipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
368
code/renderer/crp_transp_draw.cpp
Normal file
368
code/renderer/crp_transp_draw.cpp
Normal file
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - OIT geometry pass
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
namespace transp_draw
|
||||
{
|
||||
#include "compshaders/crp/transp_draw_vs.h"
|
||||
#include "compshaders/crp/transp_draw_ps.h"
|
||||
}
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
struct TranspDrawVertexRC : WorldVertexRC
|
||||
{
|
||||
};
|
||||
|
||||
struct TranspDrawPixelRC
|
||||
{
|
||||
uint32_t textureIndex;
|
||||
uint32_t samplerIndex;
|
||||
uint32_t alphaTest;
|
||||
uint32_t counterBuffer;
|
||||
uint32_t indexTexture;
|
||||
uint32_t fragmentBuffer;
|
||||
float greyscale;
|
||||
uint32_t stateBits;
|
||||
uint32_t shaderTrace;
|
||||
uint16_t hFadeDistance;
|
||||
uint16_t hFadeOffset;
|
||||
uint32_t depthFadeScaleBias; // color bias: 4 - color scale: 4
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
static uint32_t GetFixedStageBits(uint32_t stateBits, uint32_t stageIndex)
|
||||
{
|
||||
// makes sure we're not overwriting anything useful
|
||||
assert((stateBits & GLS_STAGEINDEX_BITS) == 0);
|
||||
|
||||
// transform "no blend" into a "replace" blend mode
|
||||
if((stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS)) == 0)
|
||||
{
|
||||
stateBits |= GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO;
|
||||
}
|
||||
|
||||
stateBits |= stageIndex << GLS_STAGEINDEX_SHIFT;
|
||||
|
||||
return stateBits;
|
||||
}
|
||||
|
||||
|
||||
void WorldTransp::Init()
|
||||
{
|
||||
psoCache.Init(psoCacheEntries, ARRAY_LEN(psoCacheEntries));
|
||||
}
|
||||
|
||||
void WorldTransp::Draw(const drawSceneViewCommand_t& cmd)
|
||||
{
|
||||
if(cmd.numTranspSurfs <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
srp.renderMode = RenderMode::World;
|
||||
|
||||
backEnd.refdef = cmd.refdef;
|
||||
backEnd.viewParms = cmd.viewParms;
|
||||
|
||||
if(backEnd.viewParms.isPortal)
|
||||
{
|
||||
float plane[4];
|
||||
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||||
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||||
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||||
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||||
|
||||
float plane2[4];
|
||||
plane2[0] = DotProduct(backEnd.viewParms.orient.axis[0], plane);
|
||||
plane2[1] = DotProduct(backEnd.viewParms.orient.axis[1], plane);
|
||||
plane2[2] = DotProduct(backEnd.viewParms.orient.axis[2], plane);
|
||||
plane2[3] = DotProduct(plane, backEnd.viewParms.orient.origin) - plane[3];
|
||||
|
||||
float* o = plane;
|
||||
const float* m = s_flipMatrix;
|
||||
const float* v = plane2;
|
||||
o[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3];
|
||||
o[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3];
|
||||
o[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3];
|
||||
o[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3];
|
||||
|
||||
memcpy(clipPlane, plane, sizeof(clipPlane));
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(clipPlane, 0, sizeof(clipPlane));
|
||||
}
|
||||
|
||||
SCOPED_RENDER_PASS("Transparent", 1.0f, 0.5f, 0.5f);
|
||||
|
||||
CmdSetViewportAndScissor(backEnd.viewParms);
|
||||
batchOldDepthHack = false;
|
||||
batchDepthHack = false;
|
||||
|
||||
const TextureBarrier texBarriers[] =
|
||||
{
|
||||
TextureBarrier(crp.depthTexture, ResourceStates::DepthWriteBit),
|
||||
TextureBarrier(crp.oitIndexTexture, ResourceStates::UnorderedAccessBit)
|
||||
};
|
||||
const BufferBarrier bufBarriers[] =
|
||||
{
|
||||
BufferBarrier(crp.oitFragmentBuffer, ResourceStates::UnorderedAccessBit),
|
||||
BufferBarrier(crp.oitCounterBuffer, ResourceStates::UnorderedAccessBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(texBarriers), texBarriers, ARRAY_LEN(bufBarriers), bufBarriers);
|
||||
|
||||
GeoBuffers& db = crp.dynBuffers[GetFrameIndex()];
|
||||
db.BeginUpload();
|
||||
|
||||
CmdBindRenderTargets(0, NULL, &crp.depthTexture);
|
||||
CmdBindVertexBuffers(ARRAY_LEN(db.vertexBuffers), db.vertexBuffers, db.vertexBufferStrides, NULL);
|
||||
CmdBindIndexBuffer(db.indexBuffer.buffer, IndexType::UInt32, 0);
|
||||
|
||||
// reset the fragment counter
|
||||
{
|
||||
BufferBarrier b0(crp.oitCounterBuffer, ResourceStates::CopyDestinationBit);
|
||||
CmdBarrier(0, NULL, 1, &b0);
|
||||
|
||||
CmdCopyBuffer(crp.oitCounterBuffer, crp.oitCounterStagingBuffer);
|
||||
|
||||
BufferBarrier b1(crp.oitCounterBuffer, ResourceStates::UnorderedAccessBit);
|
||||
CmdBarrier(0, NULL, 1, &b1);
|
||||
}
|
||||
|
||||
// clear the index texture
|
||||
{
|
||||
const uint32_t zeroes[4] = {};
|
||||
CmdClearTextureUAV(crp.oitIndexTexture, 0, zeroes);
|
||||
}
|
||||
|
||||
// really should just be just for the counter buffer and the index texture
|
||||
CmdBarrier(ARRAY_LEN(texBarriers), texBarriers, ARRAY_LEN(bufBarriers), bufBarriers);
|
||||
|
||||
const drawSurf_t* drawSurfs = cmd.drawSurfs;
|
||||
const int opaqueSurfCount = cmd.numDrawSurfs - cmd.numTranspSurfs;
|
||||
const int transpSurfCount = cmd.numTranspSurfs;
|
||||
const double originalTime = backEnd.refdef.floatTime;
|
||||
|
||||
const shader_t* shader = NULL;
|
||||
const shader_t* oldShader = NULL;
|
||||
int oldEntityNum = -1;
|
||||
backEnd.currentEntity = &tr.worldEntity;
|
||||
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
|
||||
const drawSurf_t* drawSurf = drawSurfs + opaqueSurfCount;
|
||||
for(int ds = 0; ds < transpSurfCount; ++ds, ++drawSurf)
|
||||
{
|
||||
int entityNum;
|
||||
R_DecomposeSort(drawSurf->sort, &entityNum, &shader);
|
||||
Q_assert(shader != NULL);
|
||||
Q_assert(!shader->isOpaque);
|
||||
|
||||
const bool shaderChanged = shader != oldShader;
|
||||
const bool entityChanged = entityNum != oldEntityNum;
|
||||
if(shaderChanged || entityChanged)
|
||||
{
|
||||
oldShader = shader;
|
||||
oldEntityNum = entityNum;
|
||||
EndBatch();
|
||||
BeginBatch(shader);
|
||||
tess.greyscale = drawSurf->greyscale;
|
||||
}
|
||||
|
||||
if(entityChanged)
|
||||
{
|
||||
UpdateEntityData(batchDepthHack, entityNum, originalTime);
|
||||
}
|
||||
|
||||
R_TessellateSurface(drawSurf->surface);
|
||||
}
|
||||
|
||||
backEnd.refdef.floatTime = originalTime;
|
||||
|
||||
EndBatch();
|
||||
|
||||
db.EndUpload();
|
||||
|
||||
// restores the potentially "hacked" depth range as well
|
||||
CmdSetViewportAndScissor(backEnd.viewParms);
|
||||
batchOldDepthHack = false;
|
||||
batchDepthHack = false;
|
||||
}
|
||||
|
||||
void WorldTransp::ProcessShader(shader_t& shader)
|
||||
{
|
||||
Q_assert(!shader.isOpaque);
|
||||
|
||||
if(shader.numStages < 1)
|
||||
{
|
||||
shader.numTranspPipelines = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const bool clampDepth = r_depthClamp->integer != 0 || shader.isSky;
|
||||
|
||||
for(int s = 0; s < shader.numStages; ++s)
|
||||
{
|
||||
int a = 0;
|
||||
|
||||
// @NOTE: we are not using any CTOR because we deliberately want to 0-init the struct
|
||||
// this is necessary for padding bytes not to mess up comparisons in the PSO cache
|
||||
GraphicsPipelineDesc desc = {};
|
||||
desc.name = "transp";
|
||||
desc.rootSignature = RHI_MAKE_NULL_HANDLE();
|
||||
desc.shortLifeTime = true; // the PSO cache is only valid for this map!
|
||||
desc.vertexShader = transp_draw::g_vs;
|
||||
desc.pixelShader = transp_draw::g_ps;
|
||||
desc.vertexLayout.AddAttribute(a++, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
||||
desc.vertexLayout.AddAttribute(a++, ShaderSemantic::Normal, DataType::Float32, 2, 0);
|
||||
desc.vertexLayout.AddAttribute(a++, ShaderSemantic::TexCoord, DataType::Float32, 2, 0);
|
||||
desc.vertexLayout.AddAttribute(a++, ShaderSemantic::Color, DataType::UNorm8, 4, 0);
|
||||
desc.depthStencil.depthStencilFormat = TextureFormat::Depth32_Float;
|
||||
desc.depthStencil.depthComparison = ComparisonFunction::GreaterEqual;
|
||||
desc.depthStencil.enableDepthTest = true;
|
||||
desc.depthStencil.enableDepthWrites = false;
|
||||
desc.rasterizer.cullMode = shader.cullType;
|
||||
desc.rasterizer.polygonOffset = shader.polygonOffset != 0;
|
||||
desc.rasterizer.clampDepth = clampDepth;
|
||||
|
||||
pipeline_t& p = shader.transpPipelines[s];
|
||||
p.firstStage = s;
|
||||
p.numStages = 1;
|
||||
p.pipeline = psoCache.AddPipeline(desc, va("transp %d %d", psoCache.entryCount, s + 1));
|
||||
desc.rasterizer.cullMode = GetMirrorredCullType(desc.rasterizer.cullMode);
|
||||
p.mirrorPipeline = psoCache.AddPipeline(desc, va("transp %d %d mirrored", psoCache.entryCount, s + 1));
|
||||
}
|
||||
|
||||
shader.numTranspPipelines = shader.numStages;
|
||||
}
|
||||
|
||||
void WorldTransp::TessellationOverflow()
|
||||
{
|
||||
EndBatch();
|
||||
BeginBatch(tess.shader);
|
||||
}
|
||||
|
||||
void WorldTransp::BeginBatch(const shader_t* shader)
|
||||
{
|
||||
tess.tessellator = Tessellator::Transp;
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
tess.depthFade = DFT_NONE;
|
||||
tess.deformsPreApplied = qfalse;
|
||||
tess.xstages = (const shaderStage_t**)shader->stages;
|
||||
tess.shader = shader;
|
||||
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
|
||||
if(tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime)
|
||||
{
|
||||
tess.shaderTime = tess.shader->clampTime;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldTransp::EndBatch()
|
||||
{
|
||||
const int vertexCount = tess.numVertexes;
|
||||
const int indexCount = tess.numIndexes;
|
||||
if(vertexCount <= 0 ||
|
||||
indexCount <= 0 ||
|
||||
tess.shader->numStages == 0 ||
|
||||
tess.shader->numTranspPipelines <= 0)
|
||||
{
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
const shader_t* const shader = tess.shader;
|
||||
|
||||
GeoBuffers& db = crp.dynBuffers[GetFrameIndex()];
|
||||
if(!db.CanAdd(vertexCount, indexCount, shader->numStages))
|
||||
{
|
||||
Q_assert(!"World surface geometry buffer too small!");
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
RB_DeformTessGeometry(0, vertexCount, 0, indexCount);
|
||||
db.UploadBase();
|
||||
|
||||
if(batchDepthHack != batchOldDepthHack)
|
||||
{
|
||||
const viewParms_t& vp = backEnd.viewParms;
|
||||
CmdSetViewport(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight, batchDepthHack ? 0.7f : 0.0f, 1.0f);
|
||||
batchOldDepthHack = batchDepthHack;
|
||||
}
|
||||
|
||||
TranspDrawVertexRC vertexRC = {};
|
||||
memcpy(vertexRC.modelViewMatrix, backEnd.orient.modelMatrix, sizeof(vertexRC.modelViewMatrix));
|
||||
memcpy(vertexRC.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(vertexRC.projectionMatrix));
|
||||
memcpy(vertexRC.clipPlane, clipPlane, sizeof(vertexRC.clipPlane));
|
||||
CmdSetGraphicsRootConstants(0, sizeof(vertexRC), &vertexRC);
|
||||
|
||||
for(int s = 0; s < shader->numStages; ++s)
|
||||
{
|
||||
const shaderStage_t* const stage = shader->stages[s];
|
||||
|
||||
R_ComputeColors(stage, tess.svars[0], 0, vertexCount);
|
||||
R_ComputeTexCoords(stage, tess.svars[0], 0, vertexCount, qfalse);
|
||||
db.UploadStage(0);
|
||||
|
||||
const pipeline_t& pipeline = shader->transpPipelines[s];
|
||||
const int psoIndex = backEnd.viewParms.isMirror ? pipeline.mirrorPipeline : pipeline.pipeline;
|
||||
Q_assert(psoIndex > 0);
|
||||
CmdBindPipeline(psoCache.entries[psoIndex].handle);
|
||||
|
||||
const image_t* image = GetBundleImage(stage->bundle);
|
||||
const uint32_t texIdx = image->textureIndex;
|
||||
const uint32_t sampIdx = GetSamplerIndex(image);
|
||||
const uint32_t alphaTest = AlphaTestShaderConstFromStateBits(stage->stateBits);
|
||||
const uint32_t enableShaderTrace = tr.traceWorldShader && s == 0 ? 1 : 0;
|
||||
const uint32_t enableDepthFade = shader->dfType != DFT_NONE ? 1 : 0;
|
||||
Q_assert(sampIdx < ARRAY_LEN(crp.samplers));
|
||||
|
||||
TranspDrawPixelRC pixelRC = {};
|
||||
pixelRC.alphaTest = alphaTest;
|
||||
pixelRC.counterBuffer = GetBufferIndexUAV(crp.oitCounterBuffer);
|
||||
pixelRC.fragmentBuffer = GetBufferIndexUAV(crp.oitFragmentBuffer);
|
||||
pixelRC.greyscale = tess.greyscale;
|
||||
pixelRC.indexTexture = GetTextureIndexUAV(crp.oitIndexTexture, 0);
|
||||
pixelRC.samplerIndex = sampIdx;
|
||||
pixelRC.stateBits = GetFixedStageBits(stage->stateBits, s);
|
||||
pixelRC.textureIndex = texIdx;
|
||||
pixelRC.shaderTrace = ((uint32_t)shader->index << 3) | (RHI::GetFrameIndex() << 1) | enableShaderTrace;
|
||||
pixelRC.hFadeDistance = f32tof16(shader->dfInvDist);
|
||||
pixelRC.hFadeOffset = f32tof16(shader->dfBias);
|
||||
pixelRC.depthFadeScaleBias = (enableDepthFade << 8) | (uint32_t)r_depthFadeScaleAndBias[shader->dfType];
|
||||
CmdSetGraphicsRootConstants(sizeof(vertexRC), sizeof(pixelRC), &pixelRC);
|
||||
|
||||
db.DrawStage(vertexCount, indexCount);
|
||||
}
|
||||
|
||||
db.EndBaseBatch(vertexCount);
|
||||
|
||||
clean_up:
|
||||
tess.tessellator = Tessellator::None;
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
}
|
111
code/renderer/crp_transp_resolve.cpp
Normal file
111
code/renderer/crp_transp_resolve.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - OIT resolve pass
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
namespace transp_resolve
|
||||
{
|
||||
#include "compshaders/crp/transp_resolve_vs.h"
|
||||
#include "compshaders/crp/transp_resolve_ps.h"
|
||||
}
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct TranspResolveRC
|
||||
{
|
||||
uint32_t renderTargetTexture;
|
||||
uint32_t shaderIndexBuffer;
|
||||
uint32_t indexTexture;
|
||||
uint32_t fragmentBuffer;
|
||||
uint16_t centerPixelX;
|
||||
uint16_t centerPixelY;
|
||||
uint32_t depthTexture;
|
||||
float proj22;
|
||||
float proj32;
|
||||
float scissorMinX;
|
||||
float scissorMinY;
|
||||
float scissorMaxX;
|
||||
float scissorMaxY;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
void TranspResolve::Init()
|
||||
{
|
||||
GraphicsPipelineDesc desc("OIT Resolve");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(transp_resolve::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(transp_resolve::g_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
pipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
void TranspResolve::Draw(const drawSceneViewCommand_t& cmd)
|
||||
{
|
||||
if(cmd.numTranspSurfs <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
srp.renderMode = RenderMode::World;
|
||||
|
||||
SCOPED_RENDER_PASS("OIT Resolve", 1.0f, 0.5f, 0.5f);
|
||||
|
||||
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
||||
crp.SwapRenderTargets();
|
||||
const TextureBarrier texBarriers[] =
|
||||
{
|
||||
TextureBarrier(crp.GetReadRenderTarget(), ResourceStates::PixelShaderAccessBit),
|
||||
TextureBarrier(crp.GetWriteRenderTarget(), ResourceStates::RenderTargetBit),
|
||||
TextureBarrier(crp.oitIndexTexture, ResourceStates::UnorderedAccessBit),
|
||||
TextureBarrier(crp.depthTexture, ResourceStates::PixelShaderAccessBit)
|
||||
};
|
||||
const BufferBarrier bufBarriers[] =
|
||||
{
|
||||
BufferBarrier(crp.oitFragmentBuffer, ResourceStates::UnorderedAccessBit),
|
||||
BufferBarrier(srp.traceRenderBuffer, ResourceStates::UnorderedAccessBit)
|
||||
};
|
||||
CmdBarrier(ARRAY_LEN(texBarriers), texBarriers, ARRAY_LEN(bufBarriers), bufBarriers);
|
||||
|
||||
TranspResolveRC rc = {};
|
||||
rc.fragmentBuffer = GetBufferIndexUAV(crp.oitFragmentBuffer);
|
||||
rc.indexTexture = GetTextureIndexUAV(crp.oitIndexTexture, 0);
|
||||
rc.renderTargetTexture = GetTextureIndexSRV(crp.GetReadRenderTarget());
|
||||
rc.shaderIndexBuffer = GetBufferIndexUAV(srp.traceRenderBuffer);
|
||||
rc.centerPixelX = glConfig.vidWidth / 2;
|
||||
rc.centerPixelY = glConfig.vidHeight / 2;
|
||||
rc.depthTexture = GetTextureIndexSRV(crp.depthTexture);
|
||||
rc.proj22 = -backEnd.viewParms.projectionMatrix[2 * 4 + 2];
|
||||
rc.proj32 = backEnd.viewParms.projectionMatrix[3 * 4 + 2];
|
||||
rc.scissorMinX = backEnd.viewParms.viewportX;
|
||||
rc.scissorMinY = backEnd.viewParms.viewportY;
|
||||
rc.scissorMaxX = rc.scissorMinX + backEnd.viewParms.viewportWidth - 1;
|
||||
rc.scissorMaxY = rc.scissorMinY + backEnd.viewParms.viewportHeight - 1;
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
CmdBindPipeline(pipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
113
code/renderer/grp_geometry.cpp
Normal file
113
code/renderer/grp_geometry.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Gameplay Rendering Pipeline - vertex and index buffer management
|
||||
|
||||
|
||||
#include "grp_local.h"
|
||||
|
||||
|
||||
void VertexBuffers::Create(const char* name, MemoryUsage::Id memoryUsage, uint32_t vertexCount)
|
||||
{
|
||||
totalCount = vertexCount;
|
||||
|
||||
BufferDesc desc = {};
|
||||
desc.committedResource = true;
|
||||
desc.initialState = ResourceStates::VertexBufferBit;
|
||||
desc.memoryUsage = memoryUsage;
|
||||
|
||||
desc.name = va("%s position vertex", name);
|
||||
desc.byteCount = vertexCount * sizeof(vec3_t);
|
||||
buffers[BasePosition] = CreateBuffer(desc);
|
||||
strides[BasePosition] = sizeof(vec3_t);
|
||||
|
||||
desc.name = va("%s normal vertex", name);
|
||||
desc.byteCount = vertexCount * sizeof(vec3_t);
|
||||
buffers[BaseNormal] = CreateBuffer(desc);
|
||||
strides[BaseNormal] = sizeof(vec3_t);
|
||||
|
||||
for(uint32_t s = 0; s < MAX_SHADER_STAGES; ++s)
|
||||
{
|
||||
desc.name = va("%s tex coords #%d vertex", name, (int)s + 1);
|
||||
desc.byteCount = vertexCount * sizeof(vec2_t);
|
||||
buffers[BaseCount + s * StageCount + StageTexCoords] = CreateBuffer(desc);
|
||||
strides[BaseCount + s * StageCount + StageTexCoords] = sizeof(vec2_t);
|
||||
|
||||
desc.name = va("%s color #%d vertex", name, (int)s + 1);
|
||||
desc.byteCount = vertexCount * sizeof(color4ub_t);
|
||||
buffers[BaseCount + s * StageCount + StageColors] = CreateBuffer(desc);
|
||||
strides[BaseCount + s * StageCount + StageColors] = sizeof(color4ub_t);
|
||||
}
|
||||
}
|
||||
|
||||
void VertexBuffers::BeginUpload()
|
||||
{
|
||||
for(uint32_t b = 0; b < BufferCount; ++b)
|
||||
{
|
||||
mapped[b] = BeginBufferUpload(buffers[b]);
|
||||
}
|
||||
}
|
||||
|
||||
void VertexBuffers::EndUpload()
|
||||
{
|
||||
for(uint32_t b = 0; b < BufferCount; ++b)
|
||||
{
|
||||
EndBufferUpload(buffers[b]);
|
||||
mapped[b] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void VertexBuffers::Upload(uint32_t firstStage, uint32_t stageCount)
|
||||
{
|
||||
Q_assert(mapped[0] != NULL);
|
||||
|
||||
const uint32_t batchOffset = batchFirst + batchCount;
|
||||
|
||||
float* pos = (float*)mapped[BasePosition] + 3 * batchOffset;
|
||||
for(int v = 0; v < tess.numVertexes; ++v)
|
||||
{
|
||||
pos[0] = tess.xyz[v][0];
|
||||
pos[1] = tess.xyz[v][1];
|
||||
pos[2] = tess.xyz[v][2];
|
||||
pos += 3;
|
||||
}
|
||||
|
||||
float* nor = (float*)mapped[BaseNormal] + 3 * batchOffset;
|
||||
for(int v = 0; v < tess.numVertexes; ++v)
|
||||
{
|
||||
nor[0] = tess.normal[v][0];
|
||||
nor[1] = tess.normal[v][1];
|
||||
nor[2] = tess.normal[v][2];
|
||||
nor += 3;
|
||||
}
|
||||
|
||||
for(uint32_t s = 0; s < stageCount; ++s)
|
||||
{
|
||||
const stageVars_t& sv = tess.svars[s + firstStage];
|
||||
|
||||
uint8_t* const tcBuffer = mapped[BaseCount + s * StageCount + StageTexCoords];
|
||||
float* tc = (float*)tcBuffer + 2 * batchOffset;
|
||||
memcpy(tc, &sv.texcoords[0], tess.numVertexes * sizeof(vec2_t));
|
||||
|
||||
uint8_t* const colBuffer = mapped[BaseCount + s * StageCount + StageColors];
|
||||
uint32_t* col = (uint32_t*)colBuffer + batchOffset;
|
||||
memcpy(col, &sv.colors[0], tess.numVertexes * sizeof(color4ub_t));
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2022-2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2022-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -24,16 +24,7 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "tr_local.h"
|
||||
#include "rhi_local.h"
|
||||
|
||||
|
||||
using namespace RHI;
|
||||
|
||||
|
||||
// @TODO: move out
|
||||
#define CONCAT_IMM(x, y) x ## y
|
||||
#define CONCAT(x, y) CONCAT_IMM(x, y)
|
||||
#include "srp_local.h"
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
@ -70,36 +61,6 @@ struct WorldPixelRC
|
|||
|
||||
#pragma pack(pop)
|
||||
|
||||
struct BufferBase
|
||||
{
|
||||
bool CanAdd(uint32_t count_)
|
||||
{
|
||||
return batchFirst + batchCount + count_ <= totalCount;
|
||||
}
|
||||
|
||||
void EndBatch()
|
||||
{
|
||||
batchFirst += batchCount;
|
||||
batchCount = 0;
|
||||
}
|
||||
|
||||
void EndBatch(uint32_t size)
|
||||
{
|
||||
batchFirst += size;
|
||||
batchCount = 0;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
batchFirst = 0;
|
||||
batchCount = 0;
|
||||
}
|
||||
|
||||
uint32_t totalCount = 0;
|
||||
uint32_t batchFirst = 0;
|
||||
uint32_t batchCount = 0;
|
||||
};
|
||||
|
||||
struct VertexBuffers : BufferBase
|
||||
{
|
||||
enum BaseId
|
||||
|
@ -116,93 +77,10 @@ struct VertexBuffers : BufferBase
|
|||
StageCount
|
||||
};
|
||||
|
||||
void Create(const char* name, MemoryUsage::Id memoryUsage, uint32_t vertexCount)
|
||||
{
|
||||
totalCount = vertexCount;
|
||||
|
||||
BufferDesc desc = {};
|
||||
desc.committedResource = true;
|
||||
desc.initialState = ResourceStates::VertexBufferBit;
|
||||
desc.memoryUsage = memoryUsage;
|
||||
|
||||
desc.name = va("%s position vertex", name);
|
||||
desc.byteCount = vertexCount * sizeof(vec3_t);
|
||||
buffers[BasePosition] = CreateBuffer(desc);
|
||||
strides[BasePosition] = sizeof(vec3_t);
|
||||
|
||||
desc.name = va("%s normal vertex", name);
|
||||
desc.byteCount = vertexCount * sizeof(vec3_t);
|
||||
buffers[BaseNormal] = CreateBuffer(desc);
|
||||
strides[BaseNormal] = sizeof(vec3_t);
|
||||
|
||||
for(uint32_t s = 0; s < MAX_SHADER_STAGES; ++s)
|
||||
{
|
||||
desc.name = va("%s tex coords #%d vertex", name, (int)s + 1);
|
||||
desc.byteCount = vertexCount * sizeof(vec2_t);
|
||||
buffers[BaseCount + s * StageCount + StageTexCoords] = CreateBuffer(desc);
|
||||
strides[BaseCount + s * StageCount + StageTexCoords] = sizeof(vec2_t);
|
||||
|
||||
desc.name = va("%s color #%d vertex", name, (int)s + 1);
|
||||
desc.byteCount = vertexCount * sizeof(color4ub_t);
|
||||
buffers[BaseCount + s * StageCount + StageColors] = CreateBuffer(desc);
|
||||
strides[BaseCount + s * StageCount + StageColors] = sizeof(color4ub_t);
|
||||
}
|
||||
}
|
||||
|
||||
void BeginUpload()
|
||||
{
|
||||
for(uint32_t b = 0; b < BufferCount; ++b)
|
||||
{
|
||||
mapped[b] = BeginBufferUpload(buffers[b]);
|
||||
}
|
||||
}
|
||||
|
||||
void EndUpload()
|
||||
{
|
||||
for(uint32_t b = 0; b < BufferCount; ++b)
|
||||
{
|
||||
EndBufferUpload(buffers[b]);
|
||||
mapped[b] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Upload(uint32_t firstStage, uint32_t stageCount)
|
||||
{
|
||||
Q_assert(mapped[0] != NULL);
|
||||
|
||||
const uint32_t batchOffset = batchFirst + batchCount;
|
||||
|
||||
float* pos = (float*)mapped[BasePosition] + 3 * batchOffset;
|
||||
for(int v = 0; v < tess.numVertexes; ++v)
|
||||
{
|
||||
pos[0] = tess.xyz[v][0];
|
||||
pos[1] = tess.xyz[v][1];
|
||||
pos[2] = tess.xyz[v][2];
|
||||
pos += 3;
|
||||
}
|
||||
|
||||
float* nor = (float*)mapped[BaseNormal] + 3 * batchOffset;
|
||||
for(int v = 0; v < tess.numVertexes; ++v)
|
||||
{
|
||||
nor[0] = tess.normal[v][0];
|
||||
nor[1] = tess.normal[v][1];
|
||||
nor[2] = tess.normal[v][2];
|
||||
nor += 3;
|
||||
}
|
||||
|
||||
for(uint32_t s = 0; s < stageCount; ++s)
|
||||
{
|
||||
const stageVars_t& sv = tess.svars[s + firstStage];
|
||||
|
||||
uint8_t* const tcBuffer = mapped[BaseCount + s * StageCount + StageTexCoords];
|
||||
float* tc = (float*)tcBuffer + 2 * batchOffset;
|
||||
memcpy(tc, &sv.texcoords[0], tess.numVertexes * sizeof(vec2_t));
|
||||
|
||||
uint8_t* const colBuffer = mapped[BaseCount + s * StageCount + StageColors];
|
||||
uint32_t* col = (uint32_t*)colBuffer + batchOffset;
|
||||
memcpy(col, &sv.colors[0], tess.numVertexes * sizeof(color4ub_t));
|
||||
}
|
||||
}
|
||||
void Create(const char* name, MemoryUsage::Id memoryUsage, uint32_t vertexCount);
|
||||
void BeginUpload();
|
||||
void EndUpload();
|
||||
void Upload(uint32_t firstStage, uint32_t stageCount);
|
||||
|
||||
static const uint32_t BufferCount = BaseCount + StageCount * MAX_SHADER_STAGES;
|
||||
HBuffer buffers[BufferCount] = {};
|
||||
|
@ -210,66 +88,6 @@ struct VertexBuffers : BufferBase
|
|||
uint8_t* mapped[BufferCount] = {};
|
||||
};
|
||||
|
||||
struct IndexBuffer : BufferBase
|
||||
{
|
||||
void Create(const char* name, MemoryUsage::Id memoryUsage, uint32_t indexCount)
|
||||
{
|
||||
totalCount = indexCount;
|
||||
|
||||
BufferDesc desc = {};
|
||||
desc.committedResource = true;
|
||||
desc.initialState = ResourceStates::IndexBufferBit;
|
||||
desc.memoryUsage = memoryUsage;
|
||||
desc.name = va("%s index", name);
|
||||
desc.byteCount = indexCount * sizeof(uint32_t);
|
||||
buffer = CreateBuffer(desc);
|
||||
}
|
||||
|
||||
void BeginUpload()
|
||||
{
|
||||
mapped = (uint32_t*)BeginBufferUpload(buffer);
|
||||
}
|
||||
|
||||
void EndUpload()
|
||||
{
|
||||
EndBufferUpload(buffer);
|
||||
mapped = NULL;
|
||||
}
|
||||
|
||||
void Upload()
|
||||
{
|
||||
Q_assert(mapped != NULL);
|
||||
|
||||
uint32_t* const idx = mapped + batchFirst + batchCount;
|
||||
memcpy(idx, &tess.indexes[0], tess.numIndexes * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
uint32_t* GetCurrentAddress()
|
||||
{
|
||||
return mapped + batchFirst + batchCount;
|
||||
}
|
||||
|
||||
HBuffer buffer = RHI_MAKE_NULL_HANDLE();
|
||||
uint32_t* mapped = NULL;
|
||||
};
|
||||
|
||||
struct GeometryBuffer : BufferBase
|
||||
{
|
||||
void Init(uint32_t count_, uint32_t stride_)
|
||||
{
|
||||
buffer = RHI_MAKE_NULL_HANDLE();
|
||||
byteCount = count_ * stride_;
|
||||
stride = stride_;
|
||||
totalCount = count_;
|
||||
batchFirst = 0;
|
||||
batchCount = 0;
|
||||
}
|
||||
|
||||
HBuffer buffer = RHI_MAKE_NULL_HANDLE();
|
||||
uint32_t byteCount = 0;
|
||||
uint32_t stride = 0;
|
||||
};
|
||||
|
||||
struct GeometryBuffers
|
||||
{
|
||||
void Rewind()
|
||||
|
@ -291,20 +109,6 @@ struct StaticGeometryChunk
|
|||
uint32_t firstCPUIndex;
|
||||
};
|
||||
|
||||
struct FrameStats
|
||||
{
|
||||
enum { MaxFrames = 1024 };
|
||||
|
||||
void EndFrame();
|
||||
|
||||
float temp[MaxFrames];
|
||||
float p2pMS[MaxFrames];
|
||||
stats_t p2pStats;
|
||||
int frameCount;
|
||||
int frameIndex;
|
||||
int skippedFrames;
|
||||
};
|
||||
|
||||
struct BatchType
|
||||
{
|
||||
enum Id
|
||||
|
@ -396,10 +200,6 @@ struct World
|
|||
HBuffer boxVertexBuffer;
|
||||
HBuffer boxIndexBuffer;
|
||||
|
||||
// shader trace
|
||||
HBuffer traceRenderBuffer;
|
||||
HBuffer traceReadbackBuffer;
|
||||
|
||||
// dynamic lights
|
||||
HRootSignature dlRootSignature;
|
||||
HPipeline dlPipelines[CT_COUNT * 2 * 2]; // { cull type, polygon offset, depth test }
|
||||
|
@ -412,176 +212,6 @@ struct World
|
|||
// we get "light holes" in opaque surfaces, which is not what we want
|
||||
};
|
||||
|
||||
struct UI
|
||||
{
|
||||
void Init();
|
||||
void BeginFrame();
|
||||
void Begin();
|
||||
void End();
|
||||
void DrawBatch();
|
||||
void UISetColor(const uiSetColorCommand_t& cmd);
|
||||
void UIDrawQuad(const uiDrawQuadCommand_t& cmd);
|
||||
void UIDrawTriangle(const uiDrawTriangleCommand_t& cmd);
|
||||
|
||||
// 32-bit needed until the render logic is fixed!
|
||||
typedef uint32_t Index;
|
||||
const IndexType::Id indexType = IndexType::UInt32;
|
||||
|
||||
uint32_t renderPassIndex;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Vertex
|
||||
{
|
||||
vec2_t position;
|
||||
vec2_t texCoords;
|
||||
uint32_t color;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
int maxIndexCount;
|
||||
int maxVertexCount;
|
||||
int firstIndex;
|
||||
int firstVertex;
|
||||
int indexCount;
|
||||
int vertexCount;
|
||||
HRootSignature rootSignature;
|
||||
HPipeline pipeline;
|
||||
HBuffer indexBuffer;
|
||||
HBuffer vertexBuffer;
|
||||
Index* indices;
|
||||
Vertex* vertices;
|
||||
uint32_t color;
|
||||
const shader_t* shader;
|
||||
};
|
||||
|
||||
struct MipMapGenerator
|
||||
{
|
||||
void Init();
|
||||
void GenerateMipMaps(HTexture texture);
|
||||
|
||||
struct Stage
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
Start, // gamma to linear
|
||||
DownSample, // down sample on 1 axis
|
||||
End, // linear to gamma
|
||||
Count
|
||||
};
|
||||
|
||||
HRootSignature rootSignature;
|
||||
HDescriptorTable descriptorTable;
|
||||
HPipeline pipeline;
|
||||
};
|
||||
|
||||
struct MipSlice
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
Float16_0,
|
||||
Float16_1,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
HTexture textures[MipSlice::Count];
|
||||
Stage stages[3];
|
||||
};
|
||||
|
||||
struct ImGUI
|
||||
{
|
||||
void Init();
|
||||
void RegisterFontAtlas();
|
||||
void Draw();
|
||||
void SafeBeginFrame();
|
||||
void SafeEndFrame();
|
||||
|
||||
struct FrameResources
|
||||
{
|
||||
HBuffer indexBuffer;
|
||||
HBuffer vertexBuffer;
|
||||
};
|
||||
|
||||
HRootSignature rootSignature;
|
||||
HPipeline pipeline;
|
||||
HTexture fontAtlas;
|
||||
FrameResources frameResources[FrameCount];
|
||||
bool frameStarted = false;
|
||||
};
|
||||
|
||||
struct Nuklear
|
||||
{
|
||||
void Init();
|
||||
void BeginFrame();
|
||||
void Begin();
|
||||
void End();
|
||||
void Upload(const nuklearUploadCommand_t& cmd);
|
||||
void Draw(const nuklearDrawCommand_t& cmd);
|
||||
|
||||
struct FrameResources
|
||||
{
|
||||
HBuffer indexBuffer;
|
||||
HBuffer vertexBuffer;
|
||||
};
|
||||
|
||||
HRootSignature rootSignature;
|
||||
HPipeline pipeline;
|
||||
FrameResources frameResources[FrameCount];
|
||||
uint32_t renderPassIndex;
|
||||
int prevScissorRect[4];
|
||||
|
||||
// reset every frame
|
||||
int firstVertex;
|
||||
int firstIndex;
|
||||
int numVertexes; // set in Upload
|
||||
int numIndexes; // set in Upload
|
||||
};
|
||||
|
||||
struct RenderMode
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
None,
|
||||
UI,
|
||||
World,
|
||||
ImGui,
|
||||
Nuklear,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
struct RenderPassQueries
|
||||
{
|
||||
char name[64];
|
||||
uint32_t gpuDurationUS;
|
||||
uint32_t cpuDurationUS;
|
||||
int64_t cpuStartUS;
|
||||
uint32_t queryIndex;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MaxRenderPasses = 64, // cg_draw3dIcons forces tons of 2D/3D transitions...
|
||||
MaxStatsFrameCount = 64
|
||||
};
|
||||
|
||||
struct RenderPassStats
|
||||
{
|
||||
void EndFrame(uint32_t cpu, uint32_t gpu);
|
||||
|
||||
uint32_t samplesCPU[MaxStatsFrameCount];
|
||||
uint32_t samplesGPU[MaxStatsFrameCount];
|
||||
stats_t statsCPU;
|
||||
stats_t statsGPU;
|
||||
uint32_t count;
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
struct RenderPassFrame
|
||||
{
|
||||
RenderPassQueries passes[MaxRenderPasses];
|
||||
uint32_t count;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct PSODesc
|
||||
|
@ -616,6 +246,7 @@ struct PostProcess
|
|||
void SetToneMapInput(HTexture toneMapInput);
|
||||
void SetInverseToneMapInput(HTexture inverseToneMapInput);
|
||||
|
||||
private:
|
||||
HPipeline toneMapPipeline;
|
||||
HRootSignature toneMapRootSignature;
|
||||
HDescriptorTable toneMapDescriptorTable;
|
||||
|
@ -645,6 +276,7 @@ struct SMAA
|
|||
};
|
||||
};
|
||||
|
||||
private:
|
||||
// fixed
|
||||
HTexture areaTexture;
|
||||
HTexture searchTexture;
|
||||
|
@ -686,27 +318,18 @@ struct GRP : IRenderPipeline
|
|||
void ProcessShader(shader_t& shader) override;
|
||||
|
||||
void ExecuteRenderCommands(const byte* data, bool readbackRequested) override;
|
||||
|
||||
void UISetColor(const uiSetColorCommand_t& cmd) override { ui.UISetColor(cmd); }
|
||||
void UIDrawQuad(const uiDrawQuadCommand_t& cmd) override { ui.UIDrawQuad(cmd); }
|
||||
void UIDrawTriangle(const uiDrawTriangleCommand_t& cmd) override { ui.UIDrawTriangle(cmd); }
|
||||
void DrawSceneView(const drawSceneViewCommand_t& cmd) override { world.DrawSceneView(cmd); }
|
||||
void TessellationOverflow() override { world.RestartBatch(); }
|
||||
void DrawSkyBox() override { world.DrawSkyBox(); }
|
||||
void DrawClouds() override { world.DrawClouds(); }
|
||||
|
||||
void ReadPixels(int w, int h, int alignment, colorSpace_t colorSpace, void* out) override;
|
||||
|
||||
uint32_t GetSamplerDescriptorIndexFromBaseIndex(uint32_t baseIndex) override { return baseIndex; }
|
||||
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
|
||||
uint32_t RegisterTexture(HTexture htexture);
|
||||
|
||||
uint32_t BeginRenderPass(const char* name, float r, float g, float b);
|
||||
void EndRenderPass(uint32_t index);
|
||||
|
||||
void DrawGUI();
|
||||
|
||||
uint32_t CreatePSO(CachedPSO& cache, const char* name);
|
||||
|
||||
void UpdateReadbackTexture();
|
||||
|
@ -718,14 +341,9 @@ struct GRP : IRenderPipeline
|
|||
PostProcess post;
|
||||
SMAA smaa;
|
||||
Nuklear nuklear;
|
||||
bool firstInit = true;
|
||||
RenderMode::Id renderMode; // necessary for sampler selection, useful for debugging
|
||||
float frameSeed;
|
||||
bool updateReadbackTexture;
|
||||
|
||||
// @TODO: what's up with rootSignature and uberRootSignature?
|
||||
// probably need to nuke one of them...
|
||||
|
||||
HTexture renderTarget;
|
||||
TextureFormat::Id renderTargetFormat;
|
||||
HTexture readbackRenderTarget;
|
||||
|
@ -733,14 +351,7 @@ struct GRP : IRenderPipeline
|
|||
HRootSignature rootSignature;
|
||||
HDescriptorTable descriptorTable;
|
||||
uint32_t textureIndex;
|
||||
HSampler samplers[TW_COUNT * TextureFilter::Count * MaxTextureMips];
|
||||
|
||||
RenderPassFrame renderPasses[FrameCount];
|
||||
RenderPassFrame tempRenderPasses;
|
||||
RenderPassStats renderPassStats[MaxRenderPasses];
|
||||
RenderPassStats wholeFrameStats;
|
||||
|
||||
FrameStats frameStats;
|
||||
HSampler samplers[BASE_SAMPLER_COUNT]; // all base samplers
|
||||
|
||||
CachedPSO psos[1024];
|
||||
uint32_t psoCount;
|
||||
|
@ -748,43 +359,3 @@ struct GRP : IRenderPipeline
|
|||
};
|
||||
|
||||
extern GRP grp;
|
||||
|
||||
struct ScopedRenderPass
|
||||
{
|
||||
ScopedRenderPass(const char* name, float r, float g, float b)
|
||||
{
|
||||
index = grp.BeginRenderPass(name, r, g, b);
|
||||
}
|
||||
|
||||
~ScopedRenderPass()
|
||||
{
|
||||
grp.EndRenderPass(index);
|
||||
}
|
||||
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
#define SCOPED_RENDER_PASS(Name, R, G, B) ScopedRenderPass CONCAT(rp_, __LINE__)(Name, R, G, B)
|
||||
|
||||
inline void CmdSetViewportAndScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
||||
{
|
||||
CmdSetViewport(x, y, w, h);
|
||||
CmdSetScissor(x, y, w, h);
|
||||
}
|
||||
|
||||
inline void CmdSetViewportAndScissor(const viewParms_t& vp)
|
||||
{
|
||||
CmdSetViewportAndScissor(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight);
|
||||
}
|
||||
|
||||
inline bool IsDepthFadeEnabled(const shader_t& shader)
|
||||
{
|
||||
return
|
||||
r_depthFade->integer != 0 &&
|
||||
shader.dfType > DFT_NONE &&
|
||||
shader.dfType < DFT_TBD;
|
||||
}
|
||||
|
||||
const image_t* GetBundleImage(const textureBundle_t& bundle);
|
||||
uint32_t GetSamplerIndex(textureWrap_t wrap, TextureFilter::Id filter, uint32_t minLOD = 0);
|
||||
uint32_t GetSamplerIndex(const image_t* image);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2022-2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2022-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -22,14 +22,42 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
|
||||
#include "grp_local.h"
|
||||
#include "uber_shaders.h"
|
||||
#include "hlsl/uber_shader.h"
|
||||
#include "hlsl/complete_uber_vs.h"
|
||||
#include "hlsl/complete_uber_ps.h"
|
||||
#include "grp_uber_shaders.h"
|
||||
#include "compshaders/grp/uber_shader.h"
|
||||
#include "compshaders/grp/complete_uber_vs.h"
|
||||
#include "compshaders/grp/complete_uber_ps.h"
|
||||
#include "../client/cl_imgui.h"
|
||||
namespace ui
|
||||
{
|
||||
#include "compshaders/grp/ui_vs.h"
|
||||
#include "compshaders/grp/ui_ps.h"
|
||||
}
|
||||
namespace imgui
|
||||
{
|
||||
#include "compshaders/grp/imgui_vs.h"
|
||||
#include "compshaders/grp/imgui_ps.h"
|
||||
}
|
||||
namespace nuklear
|
||||
{
|
||||
#include "compshaders/grp/nuklear_vs.h"
|
||||
#include "compshaders/grp/nuklear_ps.h"
|
||||
}
|
||||
namespace mip_1
|
||||
{
|
||||
#include "compshaders/grp/mip_1_cs.h"
|
||||
}
|
||||
namespace mip_2
|
||||
{
|
||||
#include "compshaders/grp/mip_2_cs.h"
|
||||
}
|
||||
namespace mip_3
|
||||
{
|
||||
#include "compshaders/grp/mip_3_cs.h"
|
||||
}
|
||||
|
||||
|
||||
GRP grp;
|
||||
IRenderPipeline* grpp = &grp;
|
||||
|
||||
static const ShaderByteCode vertexShaderByteCodes[8] =
|
||||
{
|
||||
|
@ -64,79 +92,6 @@ static const uint32_t uberPixelShaderCacheSize = UBER_SHADER_PS_LIST(PS) 0;
|
|||
static UberPixelShaderState uberPixelShaderStates[uberPixelShaderCacheSize];
|
||||
|
||||
|
||||
static ImPlotPoint FrameTimeGetter(int index, void*)
|
||||
{
|
||||
const FrameStats& fs = grp.frameStats;
|
||||
const int realIndex = (fs.frameIndex + index) % fs.frameCount;
|
||||
const float value = fs.p2pMS[realIndex];
|
||||
|
||||
ImPlotPoint p;
|
||||
p.x = index;
|
||||
p.y = value;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void UpdateAnimatedImage(image_t* image, int w, int h, const byte* data, qbool dirty)
|
||||
{
|
||||
if(w != image->width || h != image->height)
|
||||
{
|
||||
// @TODO: ?
|
||||
/*image->width = w;
|
||||
image->height = h;
|
||||
CreateTexture(&d3d.textures[image->texnum], image, 1, w, h);
|
||||
GAL_UpdateTexture(image, 0, 0, 0, w, h, data);*/
|
||||
}
|
||||
else if(dirty)
|
||||
{
|
||||
// @TODO: ?
|
||||
//GAL_UpdateTexture(image, 0, 0, 0, w, h, data);
|
||||
}
|
||||
}
|
||||
|
||||
const image_t* GetBundleImage(const textureBundle_t& bundle)
|
||||
{
|
||||
return R_UpdateAndGetBundleImage(&bundle, &UpdateAnimatedImage);
|
||||
}
|
||||
|
||||
uint32_t GetSamplerIndex(textureWrap_t wrap, TextureFilter::Id filter, uint32_t minLOD)
|
||||
{
|
||||
Q_assert((uint32_t)wrap < TW_COUNT);
|
||||
Q_assert((uint32_t)filter < TextureFilter::Count);
|
||||
|
||||
const uint32_t index =
|
||||
(uint32_t)filter +
|
||||
(uint32_t)TextureFilter::Count * (uint32_t)wrap +
|
||||
(uint32_t)TextureFilter::Count * (uint32_t)TW_COUNT * minLOD;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t GetSamplerIndex(const image_t* image)
|
||||
{
|
||||
TextureFilter::Id filter = TextureFilter::Anisotropic;
|
||||
if(r_lego->integer &&
|
||||
grp.renderMode == RenderMode::World &&
|
||||
(image->flags & (IMG_LMATLAS | IMG_EXTLMATLAS | IMG_NOPICMIP)) == 0)
|
||||
{
|
||||
filter = TextureFilter::Point;
|
||||
}
|
||||
else if((image->flags & IMG_NOAF) != 0 ||
|
||||
grp.renderMode != RenderMode::World)
|
||||
{
|
||||
filter = TextureFilter::Linear;
|
||||
}
|
||||
|
||||
int minLOD = 0;
|
||||
if(grp.renderMode == RenderMode::World &&
|
||||
(image->flags & IMG_NOPICMIP) == 0)
|
||||
{
|
||||
minLOD = Com_ClampInt(0, MaxTextureMips - 1, r_picmip->integer);
|
||||
}
|
||||
|
||||
return GetSamplerIndex(image->wrapClampMode, filter, (uint32_t)minLOD);
|
||||
}
|
||||
|
||||
static bool IsCommutativeBlendState(unsigned int stateBits)
|
||||
{
|
||||
const unsigned int blendStates[] =
|
||||
|
@ -159,42 +114,14 @@ static bool IsCommutativeBlendState(unsigned int stateBits)
|
|||
return false;
|
||||
}
|
||||
|
||||
static cullType_t GetMirrorredCullType(cullType_t cullType)
|
||||
{
|
||||
switch(cullType)
|
||||
{
|
||||
case CT_BACK_SIDED: return CT_FRONT_SIDED;
|
||||
case CT_FRONT_SIDED: return CT_BACK_SIDED;
|
||||
default: return CT_TWO_SIDED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FrameStats::EndFrame()
|
||||
{
|
||||
frameCount = min(frameCount + 1, (int)MaxFrames);
|
||||
frameIndex = (frameIndex + 1) % MaxFrames;
|
||||
Com_StatsFromArray(p2pMS, frameCount, temp, &p2pStats);
|
||||
}
|
||||
|
||||
|
||||
void RenderPassStats::EndFrame(uint32_t cpu, uint32_t gpu)
|
||||
{
|
||||
static uint32_t tempSamples[MaxStatsFrameCount];
|
||||
samplesCPU[index] = cpu;
|
||||
samplesGPU[index] = gpu;
|
||||
count = min(count + 1, (uint32_t)MaxStatsFrameCount);
|
||||
index = (index + 1) % MaxStatsFrameCount;
|
||||
Com_StatsFromArray((const int*)samplesCPU, count, (int*)tempSamples, &statsCPU);
|
||||
Com_StatsFromArray((const int*)samplesGPU, count, (int*)tempSamples, &statsGPU);
|
||||
}
|
||||
|
||||
|
||||
void GRP::Init()
|
||||
{
|
||||
firstInit = RHI::Init();
|
||||
InitDesc initDesc;
|
||||
initDesc.directDescriptorHeapIndexing = false;
|
||||
srp.firstInit = RHI::Init(initDesc);
|
||||
|
||||
if(firstInit)
|
||||
if(srp.firstInit)
|
||||
{
|
||||
RootSignatureDesc desc("main");
|
||||
desc.usingVertexBuffers = true;
|
||||
|
@ -223,6 +150,11 @@ void GRP::Init()
|
|||
Q_assert(!"ParseUberPixelShaderState failed!");
|
||||
}
|
||||
}
|
||||
|
||||
srp.CreateShaderTraceBuffers();
|
||||
DescriptorTableUpdate update;
|
||||
update.SetRWBuffers(1, &srp.traceRenderBuffer, MAX_DRAWIMAGES * 2);
|
||||
UpdateDescriptorTable(descriptorTable, update);
|
||||
}
|
||||
|
||||
// we recreate the samplers on every vid_restart to create the right level
|
||||
|
@ -235,7 +167,7 @@ void GRP::Init()
|
|||
{
|
||||
const textureWrap_t wrap = (textureWrap_t)w;
|
||||
const TextureFilter::Id filter = (TextureFilter::Id)f;
|
||||
const uint32_t s = GetSamplerIndex(wrap, filter, m);
|
||||
const uint32_t s = GetBaseSamplerIndex(wrap, filter, m);
|
||||
SamplerDesc desc(wrap, filter, (float)m);
|
||||
desc.shortLifeTime = true;
|
||||
samplers[s] = CreateSampler(desc);
|
||||
|
@ -291,16 +223,18 @@ void GRP::Init()
|
|||
readbackRenderTarget = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
||||
ui.Init();
|
||||
ui.Init(false, ShaderByteCode(ui::g_vs), ShaderByteCode(ui::g_ps), renderTargetFormat, descriptorTable, &rootSignatureDesc);
|
||||
world.Init();
|
||||
mipMapGen.Init();
|
||||
imgui.Init();
|
||||
nuklear.Init();
|
||||
mipMapGen.Init(false, ShaderByteCode(mip_1::g_cs), ShaderByteCode(mip_2::g_cs), ShaderByteCode(mip_3::g_cs));
|
||||
const HTexture fontAtlas = imgui.Init(false, ShaderByteCode(imgui::g_vs), ShaderByteCode(imgui::g_ps), renderTargetFormat, descriptorTable, &rootSignatureDesc);
|
||||
const uint32_t fontAtlasSRV = RegisterTexture(fontAtlas);
|
||||
imgui.RegisterFontAtlas(fontAtlasSRV);
|
||||
nuklear.Init(false, ShaderByteCode(nuklear::g_vs), ShaderByteCode(nuklear::g_ps), renderTargetFormat, descriptorTable, &rootSignatureDesc);
|
||||
post.Init();
|
||||
post.SetToneMapInput(renderTarget);
|
||||
smaa.Init(); // must be after post
|
||||
|
||||
firstInit = false;
|
||||
srp.firstInit = false;
|
||||
}
|
||||
|
||||
void GRP::ShutDown(bool fullShutDown)
|
||||
|
@ -310,14 +244,15 @@ void GRP::ShutDown(bool fullShutDown)
|
|||
|
||||
void GRP::BeginFrame()
|
||||
{
|
||||
renderPasses[tr.frameCount % FrameCount].count = 0;
|
||||
|
||||
R_SetColorMappings();
|
||||
srp.psoCount = psoCount;
|
||||
srp.psoChangeCount = world.psoChangeCount;
|
||||
srp.psoStatsValid = true;
|
||||
|
||||
srp.BeginFrame();
|
||||
smaa.Update();
|
||||
|
||||
// have it be first to we can use ImGUI in the other components too
|
||||
grp.imgui.SafeBeginFrame();
|
||||
grp.imgui.BeginFrame();
|
||||
|
||||
RHI::BeginFrame();
|
||||
ui.BeginFrame();
|
||||
|
@ -330,35 +265,19 @@ void GRP::BeginFrame()
|
|||
CmdClearColorTarget(renderTarget, clearColor);
|
||||
|
||||
// nothing is bound to the command list yet!
|
||||
renderMode = RenderMode::None;
|
||||
srp.renderMode = RenderMode::None;
|
||||
|
||||
frameSeed = (float)rand() / (float)RAND_MAX;
|
||||
}
|
||||
|
||||
void GRP::EndFrame()
|
||||
{
|
||||
DrawGUI();
|
||||
R_DrawGUI();
|
||||
imgui.Draw();
|
||||
srp.DrawGUI();
|
||||
imgui.Draw(renderTarget);
|
||||
post.Draw("Post-process", GetSwapChainTexture());
|
||||
world.EndFrame();
|
||||
UpdateReadbackTexture();
|
||||
RHI::EndFrame();
|
||||
|
||||
if(rhie.presentToPresentUS > 0)
|
||||
{
|
||||
frameStats.p2pMS[frameStats.frameIndex] = (float)rhie.presentToPresentUS / 1000.0f;
|
||||
frameStats.EndFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
frameStats.skippedFrames++;
|
||||
}
|
||||
|
||||
if(backEnd.renderFrame)
|
||||
{
|
||||
Sys_V_EndFrame();
|
||||
}
|
||||
srp.EndFrame();
|
||||
}
|
||||
|
||||
void GRP::UpdateReadbackTexture()
|
||||
|
@ -525,206 +444,6 @@ uint32_t GRP::RegisterTexture(HTexture htexture)
|
|||
return index;
|
||||
}
|
||||
|
||||
uint32_t GRP::BeginRenderPass(const char* name, float r, float g, float b)
|
||||
{
|
||||
RenderPassFrame& f = renderPasses[tr.frameCount % FrameCount];
|
||||
if(f.count >= ARRAY_LEN(f.passes))
|
||||
{
|
||||
Q_assert(0);
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
CmdBeginDebugLabel(name, r, g, b);
|
||||
|
||||
const uint32_t index = f.count++;
|
||||
RenderPassQueries& q = f.passes[index];
|
||||
Q_strncpyz(q.name, name, sizeof(q.name));
|
||||
q.cpuStartUS = Sys_Microseconds();
|
||||
q.queryIndex = CmdBeginDurationQuery();
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void GRP::EndRenderPass(uint32_t index)
|
||||
{
|
||||
RenderPassFrame& f = renderPasses[tr.frameCount % FrameCount];
|
||||
if(index >= f.count)
|
||||
{
|
||||
Q_assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
CmdEndDebugLabel();
|
||||
|
||||
RenderPassQueries& q = f.passes[index];
|
||||
q.cpuDurationUS = (uint32_t)(Sys_Microseconds() - q.cpuStartUS);
|
||||
CmdEndDurationQuery(q.queryIndex);
|
||||
}
|
||||
|
||||
void GRP::DrawGUI()
|
||||
{
|
||||
uint32_t durations[MaxDurationQueries];
|
||||
GetDurations(durations);
|
||||
|
||||
wholeFrameStats.EndFrame(rhie.renderToPresentUS, durations[0]);
|
||||
|
||||
const RenderPassFrame& currFrame = renderPasses[(tr.frameCount % FrameCount) ^ 1];
|
||||
RenderPassFrame& tempFrame = tempRenderPasses;
|
||||
|
||||
// see if the render pass list is the same as the previous frame's
|
||||
bool sameRenderPass = true;
|
||||
if(currFrame.count == tempRenderPasses.count)
|
||||
{
|
||||
for(uint32_t p = 0; p < currFrame.count; ++p)
|
||||
{
|
||||
if(Q_stricmp(currFrame.passes[p].name, tempRenderPasses.passes[p].name) != 0)
|
||||
{
|
||||
sameRenderPass = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sameRenderPass = false;
|
||||
}
|
||||
|
||||
// write out the displayed timings into the temp buffer
|
||||
tempFrame.count = currFrame.count;
|
||||
if(sameRenderPass)
|
||||
{
|
||||
for(uint32_t p = 0; p < currFrame.count; ++p)
|
||||
{
|
||||
const uint32_t index = currFrame.passes[p].queryIndex;
|
||||
if(index < MaxDurationQueries)
|
||||
{
|
||||
renderPassStats[p].EndFrame(currFrame.passes[p].cpuDurationUS, durations[index]);
|
||||
tempFrame.passes[p].gpuDurationUS = renderPassStats[p].statsGPU.median;
|
||||
tempFrame.passes[p].cpuDurationUS = renderPassStats[p].statsCPU.median;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(uint32_t p = 0; p < currFrame.count; ++p)
|
||||
{
|
||||
const uint32_t index = currFrame.passes[p].queryIndex;
|
||||
if(index < MaxDurationQueries)
|
||||
{
|
||||
tempFrame.passes[p].gpuDurationUS = durations[index];
|
||||
tempFrame.passes[p].cpuDurationUS = currFrame.passes[p].cpuDurationUS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool breakdownActive = false;
|
||||
ToggleBooleanWithShortcut(breakdownActive, ImGuiKey_F);
|
||||
GUI_AddMainMenuItem(GUI_MainMenu::Perf, "Frame breakdown", "Ctrl+F", &breakdownActive);
|
||||
if(breakdownActive)
|
||||
{
|
||||
if(ImGui::Begin("Frame breakdown", &breakdownActive, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
if(BeginTable("Frame breakdown", 3))
|
||||
{
|
||||
TableHeader(3, "Pass", "GPU [us]", "CPU [us]");
|
||||
|
||||
TableRow(3, "Whole frame",
|
||||
va("%d", (int)wholeFrameStats.statsGPU.median),
|
||||
va("%d", (int)wholeFrameStats.statsCPU.median));
|
||||
|
||||
for(uint32_t p = 0; p < currFrame.count; ++p)
|
||||
{
|
||||
const RenderPassQueries& rp = tempFrame.passes[p];
|
||||
if(rp.queryIndex < MaxDurationQueries)
|
||||
{
|
||||
TableRow(3, rp.name,
|
||||
va("%d", (int)rp.gpuDurationUS),
|
||||
va("%d", (int)rp.cpuDurationUS));
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::Text("PSO count: %d", (int)grp.psoCount);
|
||||
ImGui::Text("PSO changes: %d", (int)grp.world.psoChangeCount);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// save the current render pass list in the temp buffer
|
||||
memcpy(&tempFrame, &currFrame, sizeof(tempFrame));
|
||||
|
||||
static bool frameTimeActive = false;
|
||||
GUI_AddMainMenuItem(GUI_MainMenu::Perf, "Frame stats", NULL, &frameTimeActive);
|
||||
if(frameTimeActive)
|
||||
{
|
||||
if(ImGui::Begin("Frame stats", &frameTimeActive, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
if(BeginTable("Frame stats", 2))
|
||||
{
|
||||
const FrameStats& fs = frameStats;
|
||||
const stats_t& s = fs.p2pStats;
|
||||
TableRow2("Skipped frames", fs.skippedFrames);
|
||||
TableRow2("Frame time target", rhie.targetFrameDurationMS);
|
||||
TableRow2("Frame time average", s.average);
|
||||
TableRow2("Frame time std dev.", s.stdDev);
|
||||
TableRow2("Input to render", (float)rhie.inputToRenderUS / 1000.0f);
|
||||
TableRow2("Input to present", (float)rhie.inputToPresentUS / 1000.0f);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
static bool graphsActive = false;
|
||||
ToggleBooleanWithShortcut(graphsActive, ImGuiKey_G);
|
||||
GUI_AddMainMenuItem(GUI_MainMenu::Perf, "Frame time graphs", "Ctrl+G", &graphsActive);
|
||||
if(graphsActive)
|
||||
{
|
||||
const int windowFlags =
|
||||
ImGuiWindowFlags_NoDecoration |
|
||||
ImGuiWindowFlags_NoBackground |
|
||||
ImGuiWindowFlags_NoMove;
|
||||
ImGui::SetNextWindowSize(ImVec2(glConfig.vidWidth, glConfig.vidHeight / 2), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowPos(ImVec2(0, glConfig.vidHeight / 2), ImGuiCond_Always);
|
||||
if(ImGui::Begin("Frame time graphs", &graphsActive, windowFlags))
|
||||
{
|
||||
const FrameStats& fs = frameStats;
|
||||
const double target = (double)rhie.targetFrameDurationMS;
|
||||
|
||||
static bool autoFit = false;
|
||||
ImGui::Checkbox("Auto-fit", &autoFit);
|
||||
|
||||
if(ImPlot::BeginPlot("Frame Times", ImVec2(-1, -1), ImPlotFlags_NoInputs))
|
||||
{
|
||||
const int axisFlags = 0; // ImPlotAxisFlags_NoTickLabels
|
||||
const int axisFlagsY = axisFlags | (autoFit ? ImPlotAxisFlags_AutoFit : 0);
|
||||
ImPlot::SetupAxes(NULL, NULL, axisFlags, axisFlagsY);
|
||||
ImPlot::SetupAxisLimits(ImAxis_X1, 0, FrameStats::MaxFrames, ImGuiCond_Always);
|
||||
if(!autoFit)
|
||||
{
|
||||
ImPlot::SetupAxisLimits(ImAxis_Y1, max(target - 2.0, 0.0), target + 2.0, ImGuiCond_Always);
|
||||
}
|
||||
|
||||
ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 1.0f);
|
||||
ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL, 1.0f);
|
||||
ImPlot::PlotInfLines("Target", &target, 1, ImPlotInfLinesFlags_Horizontal);
|
||||
|
||||
ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 1.0f);
|
||||
ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL, 1.0f);
|
||||
ImPlot::PlotLineG("Frame Time", &FrameTimeGetter, NULL, fs.frameCount, ImPlotLineFlags_None);
|
||||
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
GUI_DrawMainMenu();
|
||||
}
|
||||
|
||||
uint32_t GRP::CreatePSO(CachedPSO& cache, const char* name)
|
||||
{
|
||||
Q_assert(cache.stageCount > 0);
|
||||
|
@ -785,6 +504,9 @@ uint32_t GRP::CreatePSO(CachedPSO& cache, const char* name)
|
|||
{
|
||||
uint32_t macroCount = 0;
|
||||
ShaderMacro macros[64];
|
||||
macros[macroCount].name = "DISABLE_PRAGMA_ONCE";
|
||||
macros[macroCount].value = "1";
|
||||
macroCount++;
|
||||
macros[macroCount].name = "STAGE_COUNT";
|
||||
macros[macroCount].value = va("%d", cache.stageCount);
|
||||
macroCount++;
|
||||
|
@ -908,16 +630,16 @@ void GRP::ExecuteRenderCommands(const byte* data, bool readbackRequested)
|
|||
switch(commandId)
|
||||
{
|
||||
case RC_UI_SET_COLOR:
|
||||
UISetColor(*(const uiSetColorCommand_t*)data);
|
||||
ui.CmdSetColor(*(const uiSetColorCommand_t*)data);
|
||||
break;
|
||||
case RC_UI_DRAW_QUAD:
|
||||
UIDrawQuad(*(const uiDrawQuadCommand_t*)data);
|
||||
ui.CmdDrawQuad(*(const uiDrawQuadCommand_t*)data);
|
||||
break;
|
||||
case RC_UI_DRAW_TRIANGLE:
|
||||
UIDrawTriangle(*(const uiDrawTriangleCommand_t*)data);
|
||||
ui.CmdDrawTriangle(*(const uiDrawTriangleCommand_t*)data);
|
||||
break;
|
||||
case RC_DRAW_SCENE_VIEW:
|
||||
DrawSceneView(*(const drawSceneViewCommand_t*)data);
|
||||
world.DrawSceneView(*(const drawSceneViewCommand_t*)data);
|
||||
break;
|
||||
case RC_BEGIN_FRAME:
|
||||
BeginFrame();
|
||||
|
@ -926,7 +648,7 @@ void GRP::ExecuteRenderCommands(const byte* data, bool readbackRequested)
|
|||
EndFrame();
|
||||
break;
|
||||
case RC_BEGIN_UI:
|
||||
ui.Begin();
|
||||
ui.Begin(renderTarget);
|
||||
break;
|
||||
case RC_END_UI:
|
||||
ui.End();
|
||||
|
@ -941,7 +663,7 @@ void GRP::ExecuteRenderCommands(const byte* data, bool readbackRequested)
|
|||
smaa.Draw(((const endSceneCommand_t*)data)->viewParms);
|
||||
break;
|
||||
case RC_BEGIN_NK:
|
||||
nuklear.Begin();
|
||||
nuklear.Begin(renderTarget);
|
||||
break;
|
||||
case RC_END_NK:
|
||||
nuklear.End();
|
||||
|
@ -963,49 +685,5 @@ void GRP::ExecuteRenderCommands(const byte* data, bool readbackRequested)
|
|||
|
||||
void GRP::ReadPixels(int w, int h, int alignment, colorSpace_t colorSpace, void* outPixels)
|
||||
{
|
||||
MappedTexture mapped;
|
||||
BeginTextureReadback(mapped, grp.readbackRenderTarget);
|
||||
|
||||
byte* const out0 = (byte*)outPixels;
|
||||
const byte* const in0 = mapped.mappedData;
|
||||
|
||||
if(colorSpace == CS_RGBA)
|
||||
{
|
||||
const int dstRowSizeNoPadding = w * 4;
|
||||
mapped.dstRowByteCount = AlignUp(dstRowSizeNoPadding, alignment);
|
||||
|
||||
for(int y = 0; y < mapped.rowCount; ++y)
|
||||
{
|
||||
byte* out = out0 + (mapped.rowCount - 1 - y) * mapped.dstRowByteCount;
|
||||
const byte* in = in0 + y * mapped.srcRowByteCount;
|
||||
memcpy(out, in, dstRowSizeNoPadding);
|
||||
}
|
||||
}
|
||||
else if(colorSpace == CS_BGR)
|
||||
{
|
||||
mapped.dstRowByteCount = AlignUp(w * 3, alignment);
|
||||
|
||||
for(int y = 0; y < mapped.rowCount; ++y)
|
||||
{
|
||||
byte* out = out0 + (mapped.rowCount - 1 - y) * mapped.dstRowByteCount;
|
||||
const byte* in = in0 + y * mapped.srcRowByteCount;
|
||||
for(int x = 0; x < mapped.columnCount; ++x)
|
||||
{
|
||||
out[2] = in[0];
|
||||
out[1] = in[1];
|
||||
out[0] = in[2];
|
||||
out += 3;
|
||||
in += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_assert(!"Unsupported color space");
|
||||
}
|
||||
|
||||
EndTextureReadback();
|
||||
ReadTextureImage(outPixels, readbackRenderTarget, w, h, alignment, colorSpace);
|
||||
}
|
||||
|
||||
// @TODO: move out once the cinematic render pipeline is added
|
||||
IRenderPipeline* renderPipeline = &grp;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -24,13 +24,13 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include "grp_local.h"
|
||||
namespace tone_map
|
||||
{
|
||||
#include "hlsl/post_gamma_vs.h"
|
||||
#include "hlsl/post_gamma_ps.h"
|
||||
#include "compshaders/grp/post_gamma_vs.h"
|
||||
#include "compshaders/grp/post_gamma_ps.h"
|
||||
}
|
||||
namespace inverse_tone_map
|
||||
{
|
||||
#include "hlsl/post_inverse_gamma_vs.h"
|
||||
#include "hlsl/post_inverse_gamma_ps.h"
|
||||
#include "compshaders/grp/post_inverse_gamma_vs.h"
|
||||
#include "compshaders/grp/post_inverse_gamma_ps.h"
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,7 +60,7 @@ struct InverseGammaPixelRC
|
|||
|
||||
void PostProcess::Init()
|
||||
{
|
||||
if(!grp.firstInit)
|
||||
if(!srp.firstInit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2022-2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2022-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -24,7 +24,7 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include "grp_local.h"
|
||||
#include "smaa_area_texture.h"
|
||||
#include "smaa_search_texture.h"
|
||||
#include "hlsl/complete_smaa.h"
|
||||
#include "compshaders/grp/complete_smaa.h"
|
||||
|
||||
|
||||
#define SMAA_PRESET_LIST(P) \
|
||||
|
@ -96,7 +96,7 @@ void SMAA::Update()
|
|||
bool createPresetDep = justEnabled || (alwaysEnabled && presetChanged);
|
||||
bool destroyPresetDep = justDisabled || (alwaysEnabled && presetChanged);
|
||||
|
||||
if(grp.firstInit)
|
||||
if(srp.firstInit)
|
||||
{
|
||||
// first init or device change: we have nothing to destroy
|
||||
const bool enableSMAA = newMode != Mode::Disabled;
|
||||
|
|
|
@ -1,3 +1,29 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Gameplay Rendering Pipeline - defines all pre-compiled uber pixel shader combinations
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
// format: stage_count global_state (stage_state_in_hex)+
|
||||
#define UBER_SHADER_PS_LIST(PS) \
|
||||
PS(1_0_0) \
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2022-2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2022-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -28,25 +28,25 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include "../client/cl_imgui.h"
|
||||
namespace zpp
|
||||
{
|
||||
#include "hlsl/depth_pre_pass_vs.h"
|
||||
#include "hlsl/depth_pre_pass_ps.h"
|
||||
#include "compshaders/grp/depth_pre_pass_vs.h"
|
||||
#include "compshaders/grp/depth_pre_pass_ps.h"
|
||||
}
|
||||
namespace fog
|
||||
{
|
||||
#include "hlsl/fog_vs.h"
|
||||
#include "compshaders/grp/fog_vs.h"
|
||||
}
|
||||
namespace fog_inside
|
||||
{
|
||||
#include "hlsl/fog_inside_ps.h"
|
||||
#include "compshaders/grp/fog_inside_ps.h"
|
||||
}
|
||||
namespace fog_outside
|
||||
{
|
||||
#include "hlsl/fog_outside_ps.h"
|
||||
#include "compshaders/grp/fog_outside_ps.h"
|
||||
}
|
||||
namespace dyn_light
|
||||
{
|
||||
#include "hlsl/dynamic_light_vs.h"
|
||||
#include "hlsl/dynamic_light_ps.h"
|
||||
#include "compshaders/grp/dynamic_light_vs.h"
|
||||
#include "compshaders/grp/dynamic_light_ps.h"
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,40 +126,6 @@ static bool HasStaticGeo(int staticGeoChunk, const shader_t* shader)
|
|||
staticGeoChunk < ARRAY_LEN(grp.world.statChunks);
|
||||
}
|
||||
|
||||
static void UpdateEntityData(bool& depthHack, int entityNum, double originalTime)
|
||||
{
|
||||
depthHack = false;
|
||||
|
||||
if(entityNum != ENTITYNUM_WORLD)
|
||||
{
|
||||
backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
|
||||
if(backEnd.currentEntity->intShaderTime)
|
||||
backEnd.refdef.floatTime = originalTime - (double)backEnd.currentEntity->e.shaderTime.iShaderTime / 1000.0;
|
||||
else
|
||||
backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime.fShaderTime;
|
||||
// we have to reset the shaderTime as well otherwise image animations start
|
||||
// from the wrong frame
|
||||
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
|
||||
|
||||
// set up the transformation matrix
|
||||
R_RotateForEntity(backEnd.currentEntity, &backEnd.viewParms, &backEnd.orient);
|
||||
|
||||
if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK)
|
||||
{
|
||||
depthHack = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
backEnd.currentEntity = &tr.worldEntity;
|
||||
backEnd.refdef.floatTime = originalTime;
|
||||
backEnd.orient = backEnd.viewParms.world;
|
||||
// we have to reset the shaderTime as well otherwise image animations on
|
||||
// the world (like water) continue with the wrong frame
|
||||
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
|
||||
}
|
||||
}
|
||||
|
||||
static int GetDynamicLightPipelineIndex(cullType_t cullType, qbool polygonOffset, qbool depthTestEquals)
|
||||
{
|
||||
return (int)cullType + CT_COUNT * (int)polygonOffset + CT_COUNT * 2 * (int)depthTestEquals;
|
||||
|
@ -168,7 +134,7 @@ static int GetDynamicLightPipelineIndex(cullType_t cullType, qbool polygonOffset
|
|||
|
||||
void World::Init()
|
||||
{
|
||||
if(grp.firstInit)
|
||||
if(srp.firstInit)
|
||||
{
|
||||
fogDescriptorTable = RHI_MAKE_NULL_HANDLE();
|
||||
}
|
||||
|
@ -192,7 +158,7 @@ void World::Init()
|
|||
}
|
||||
}
|
||||
|
||||
if(grp.firstInit)
|
||||
if(srp.firstInit)
|
||||
{
|
||||
//
|
||||
// depth pre-pass
|
||||
|
@ -313,23 +279,6 @@ void World::Init()
|
|||
EndBufferUpload(boxVertexBuffer);
|
||||
}
|
||||
|
||||
//
|
||||
// shader trace
|
||||
//
|
||||
{
|
||||
BufferDesc desc("shader trace opaque", 2 * sizeof(uint32_t), ResourceStates::UnorderedAccessBit);
|
||||
traceRenderBuffer = CreateBuffer(desc);
|
||||
|
||||
DescriptorTableUpdate update;
|
||||
update.SetRWBuffers(1, &traceRenderBuffer, MAX_DRAWIMAGES * 2);
|
||||
UpdateDescriptorTable(grp.descriptorTable, update);
|
||||
}
|
||||
{
|
||||
BufferDesc desc("shader trace opaque readback", 2 * sizeof(uint32_t), ResourceStates::Common);
|
||||
desc.memoryUsage = MemoryUsage::Readback;
|
||||
traceReadbackBuffer = CreateBuffer(desc);
|
||||
}
|
||||
|
||||
//
|
||||
// dynamic lights
|
||||
//
|
||||
|
@ -425,34 +374,11 @@ void World::BeginFrame()
|
|||
|
||||
void World::EndFrame()
|
||||
{
|
||||
tr.tracedWorldShaderIndex = -1;
|
||||
if(tr.traceWorldShader && tr.world != NULL)
|
||||
{
|
||||
// schedule a GPU -> CPU transfer
|
||||
{
|
||||
BufferBarrier barrier(traceRenderBuffer, ResourceStates::CopySourceBit);
|
||||
CmdBarrier(0, NULL, 1, &barrier);
|
||||
}
|
||||
CmdCopyBuffer(traceReadbackBuffer, traceRenderBuffer);
|
||||
{
|
||||
BufferBarrier barrier(traceRenderBuffer, ResourceStates::UnorderedAccessBit);
|
||||
CmdBarrier(0, NULL, 1, &barrier);
|
||||
}
|
||||
|
||||
// grab last frame's result
|
||||
uint32_t* shaderIndices = (uint32_t*)MapBuffer(traceReadbackBuffer);
|
||||
const uint32_t shaderIndex = shaderIndices[RHI::GetFrameIndex() ^ 1];
|
||||
UnmapBuffer(traceReadbackBuffer);
|
||||
if(shaderIndex < (uint32_t)tr.numShaders)
|
||||
{
|
||||
tr.tracedWorldShaderIndex = (int)shaderIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void World::Begin()
|
||||
{
|
||||
grp.renderMode = RenderMode::World;
|
||||
srp.renderMode = RenderMode::World;
|
||||
|
||||
if(backEnd.viewParms.isPortal)
|
||||
{
|
||||
|
@ -495,7 +421,7 @@ void World::Begin()
|
|||
|
||||
void World::End()
|
||||
{
|
||||
grp.renderMode = RenderMode::None;
|
||||
srp.renderMode = RenderMode::None;
|
||||
}
|
||||
|
||||
void World::DrawPrePass(const drawSceneViewCommand_t& cmd)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2022-2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2022-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -169,6 +169,7 @@ namespace RHI
|
|||
R8_UNorm,
|
||||
Depth24_Stencil8,
|
||||
R10G10B10A2_UNorm,
|
||||
R32_UInt,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
@ -353,6 +354,11 @@ namespace RHI
|
|||
name = name_;
|
||||
rootSignature = rootSignature_;
|
||||
}
|
||||
explicit GraphicsPipelineDesc(const char* name_)
|
||||
{
|
||||
name = name_;
|
||||
rootSignature = RHI_MAKE_NULL_HANDLE();
|
||||
}
|
||||
|
||||
const char* name = NULL;
|
||||
bool shortLifeTime = false;
|
||||
|
@ -434,6 +440,11 @@ namespace RHI
|
|||
name = name_;
|
||||
rootSignature = rootSignature_;
|
||||
}
|
||||
explicit ComputePipelineDesc(const char* name_)
|
||||
{
|
||||
name = name_;
|
||||
rootSignature = RHI_MAKE_NULL_HANDLE();
|
||||
}
|
||||
|
||||
const char* name = NULL;
|
||||
bool shortLifeTime = false;
|
||||
|
@ -677,7 +688,15 @@ namespace RHI
|
|||
const ShaderMacro* macros = NULL;
|
||||
};
|
||||
|
||||
bool Init(); // true when a full init happened (the device was created)
|
||||
struct InitDesc
|
||||
{
|
||||
// HLSL 6.6 Dynamic Resources
|
||||
// - all shader resources are exclusively used through ResourceDescriptorHeap and SamplerDescriptorHeap
|
||||
// - all root signature and descriptor table functions are disabled
|
||||
bool directDescriptorHeapIndexing = false;
|
||||
};
|
||||
|
||||
bool Init(const InitDesc& desc); // true when a full init happened (the device was created)
|
||||
void ShutDown(bool destroyWindow);
|
||||
|
||||
void BeginFrame();
|
||||
|
@ -721,6 +740,8 @@ namespace RHI
|
|||
void CmdSetViewport(uint32_t x, uint32_t y, uint32_t w, uint32_t h, float minDepth = 0.0f, float maxDepth = 1.0f);
|
||||
void CmdSetScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
|
||||
void CmdSetRootConstants(HRootSignature rootSignature, ShaderStage::Id shaderType, const void* constants);
|
||||
void CmdSetGraphicsRootConstants(uint32_t byteOffset, uint32_t byteCount, const void* constants);
|
||||
void CmdSetComputeRootConstants(uint32_t byteOffset, uint32_t byteCount, const void* constants);
|
||||
void CmdDraw(uint32_t vertexCount, uint32_t firstVertex);
|
||||
void CmdDrawIndexed(uint32_t indexCount, uint32_t firstIndex, uint32_t firstVertex);
|
||||
void CmdDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
|
||||
|
@ -729,7 +750,7 @@ namespace RHI
|
|||
void CmdBarrier(uint32_t texCount, const TextureBarrier* textures, uint32_t buffCount = 0, const BufferBarrier* buffers = NULL);
|
||||
void CmdClearColorTarget(HTexture texture, const vec4_t clearColor, const Rect* rect = NULL);
|
||||
void CmdClearDepthStencilTarget(HTexture texture, bool clearDepth, float depth, bool clearStencil = false, uint8_t stencil = 0, const Rect* rect = NULL);
|
||||
void CmdClearTextureUAV(HTexture texture, HDescriptorTable descTable, uint32_t tableIndex, uint32_t mipIndex, const uint32_t* values);
|
||||
void CmdClearTextureUAV(HTexture texture, uint32_t mipIndex, const uint32_t* values);
|
||||
void CmdInsertDebugLabel(const char* name, float r = 1.0f, float g = 1.0f, float b = 1.0f);
|
||||
void CmdBeginDebugLabel(const char* name, float r = 1.0f, float g = 1.0f, float b = 1.0f);
|
||||
void CmdEndDebugLabel();
|
||||
|
@ -737,6 +758,15 @@ namespace RHI
|
|||
void CmdCopyBuffer(HBuffer dest, HBuffer source);
|
||||
void CmdSetShadingRate(ShadingRate::Id shadingRate);
|
||||
|
||||
// only available when dynamic resources are enabled
|
||||
uint32_t GetTextureIndexSRV(HTexture texture);
|
||||
uint32_t GetTextureIndexUAV(HTexture texture, uint32_t mipIndex);
|
||||
uint32_t GetBufferIndexSRV(HBuffer buffer);
|
||||
uint32_t GetBufferIndexUAV(HBuffer buffer);
|
||||
uint32_t GetBufferIndexCBV(HBuffer buffer);
|
||||
uint32_t GetSamplerIndex(HSampler sampler);
|
||||
void CmdBarrierUAV();
|
||||
|
||||
// the duration at index 0 is for the entire frame
|
||||
uint32_t GetDurationCount();
|
||||
void GetDurations(uint32_t* gpuMicroSeconds);
|
||||
|
@ -756,6 +786,8 @@ namespace RHI
|
|||
|
||||
void WaitUntilDeviceIsIdle();
|
||||
|
||||
void SubmitAndContinue();
|
||||
|
||||
const Handle HandleIndexBitCount = 16;
|
||||
const Handle HandleIndexBitOffset = 0;
|
||||
const Handle HandleGenBitCount = 10;
|
||||
|
|
81
code/renderer/shaders/common/blend.hlsli
Normal file
81
code/renderer/shaders/common/blend.hlsli
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Quake 3 blend equations
|
||||
|
||||
|
||||
#if !defined(DISABLE_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
float4 BlendSource(float4 src, float4 dst, uint stateBits)
|
||||
{
|
||||
if(stateBits == GLS_SRCBLEND_ZERO)
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
else if(stateBits == GLS_SRCBLEND_ONE)
|
||||
return src;
|
||||
else if(stateBits == GLS_SRCBLEND_DST_COLOR)
|
||||
return src * dst;
|
||||
else if(stateBits == GLS_SRCBLEND_ONE_MINUS_DST_COLOR)
|
||||
return src * (float4(1.0, 1.0, 1.0, 1.0) - dst);
|
||||
else if(stateBits == GLS_SRCBLEND_SRC_ALPHA)
|
||||
return src * float4(src.a, src.a, src.a, 1.0);
|
||||
else if(stateBits == GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA)
|
||||
return src * float4(1.0 - src.a, 1.0 - src.a, 1.0 - src.a, 1.0);
|
||||
else if(stateBits == GLS_SRCBLEND_DST_ALPHA)
|
||||
return src * float4(dst.a, dst.a, dst.a, 1.0);
|
||||
else if(stateBits == GLS_SRCBLEND_ONE_MINUS_DST_ALPHA)
|
||||
return src * float4(1.0 - dst.a, 1.0 - dst.a, 1.0 - dst.a, 1.0);
|
||||
else if(stateBits == GLS_SRCBLEND_ALPHA_SATURATE)
|
||||
return src * float4(src.a, src.a, src.a, 1.0);
|
||||
else
|
||||
return src;
|
||||
}
|
||||
|
||||
float4 BlendDest(float4 src, float4 dst, uint stateBits)
|
||||
{
|
||||
if(stateBits == GLS_DSTBLEND_ZERO)
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
else if(stateBits == GLS_DSTBLEND_ONE)
|
||||
return dst;
|
||||
else if(stateBits == GLS_DSTBLEND_SRC_COLOR)
|
||||
return dst * src;
|
||||
else if(stateBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR)
|
||||
return dst * float4(1.0 - src.r, 1.0 - src.g, 1.0 - src.b, 1.0 - src.a);
|
||||
else if(stateBits == GLS_DSTBLEND_SRC_ALPHA)
|
||||
return dst * float4(src.a, src.a, src.a, 1.0);
|
||||
else if(stateBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA)
|
||||
return dst * float4(1.0 - src.a, 1.0 - src.a, 1.0 - src.a, 0.0);
|
||||
else if(stateBits == GLS_DSTBLEND_DST_ALPHA)
|
||||
return dst * float4(dst.a, dst.a, dst.a, 1.0);
|
||||
else if(stateBits == GLS_DSTBLEND_ONE_MINUS_DST_ALPHA)
|
||||
return dst * float4(1.0 - dst.a, 1.0 - dst.a, 1.0 - dst.a, 1.0);
|
||||
else
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
float4 Blend(float4 src, float4 dst, uint stateBits)
|
||||
{
|
||||
float4 srcOut = BlendSource(src, dst, stateBits & GLS_SRCBLEND_BITS);
|
||||
float4 dstOut = BlendDest(src, dst, stateBits & GLS_DSTBLEND_BITS);
|
||||
|
||||
return srcOut + dstOut;
|
||||
}
|
96
code/renderer/shaders/common/mip_gen.hlsli
Normal file
96
code/renderer/shaders/common/mip_gen.hlsli
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// mip-map generation
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
uint2 MipGen_FixCoords(int2 tc, int2 maxSize, uint clampCoords)
|
||||
{
|
||||
if(clampCoords > 0)
|
||||
{
|
||||
// clamp
|
||||
return uint2(clamp(tc, int2(0, 0), maxSize));
|
||||
}
|
||||
|
||||
// repeat
|
||||
return uint2(tc & maxSize);
|
||||
}
|
||||
|
||||
void MipGen_GammaToLinear(RWTexture2D<float4> dst, RWTexture2D<float4> src, uint3 dtid, float gamma)
|
||||
{
|
||||
uint w, h;
|
||||
dst.GetDimensions(w, h);
|
||||
if(any(dtid.xy >= uint2(w, h)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float4 v = src[dtid.xy];
|
||||
dst[dtid.xy] = float4(pow(v.xyz, gamma), v.a);
|
||||
}
|
||||
|
||||
void MipGen_LinearToGamma(RWTexture2D<float4> dst, RWTexture2D<float4> src, uint3 dtid, float4 blendColor, float intensity, float invGamma)
|
||||
{
|
||||
uint w, h;
|
||||
dst.GetDimensions(w, h);
|
||||
if(any(dtid.xy >= uint2(w, h)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// yes, intensity *should* be done in light-linear space
|
||||
// but we keep the old behavior for consistency...
|
||||
float4 in0 = src[dtid.xy];
|
||||
float3 in1 = 0.5 * (in0.rgb + blendColor.rgb);
|
||||
float3 inV = lerp(in0.rgb, in1.rgb, blendColor.a);
|
||||
float3 out0 = pow(max(inV, 0.0), invGamma);
|
||||
float3 out1 = out0 * intensity;
|
||||
float4 outV = saturate(float4(out1, in0.a));
|
||||
dst[dtid.xy] = outV;
|
||||
}
|
||||
|
||||
void MipGen_DownSample(RWTexture2D<float4> dst, RWTexture2D<float4> src, uint3 dtid, int2 maxSize, uint clampCoords, int2 scale, int2 offset, float4 weights)
|
||||
{
|
||||
uint w, h;
|
||||
dst.GetDimensions(w, h);
|
||||
if(any(dtid.xy >= uint2(w, h)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#define FixCoords(tc) MipGen_FixCoords(tc, maxSize, clampCoords)
|
||||
|
||||
int2 base = int2(dtid.xy) * scale;
|
||||
float4 r = float4(0, 0, 0, 0);
|
||||
r += src[FixCoords(base - offset * 3)] * weights.x;
|
||||
r += src[FixCoords(base - offset * 2)] * weights.y;
|
||||
r += src[FixCoords(base - offset * 1)] * weights.z;
|
||||
r += src[base] * weights.w;
|
||||
r += src[base + offset] * weights.w;
|
||||
r += src[FixCoords(base + offset * 2)] * weights.z;
|
||||
r += src[FixCoords(base + offset * 3)] * weights.y;
|
||||
r += src[FixCoords(base + offset * 4)] * weights.x;
|
||||
dst[dtid.xy] = r;
|
||||
|
||||
#undef FixCoords
|
||||
}
|
65
code/renderer/shaders/common/state_bits.h.hlsli
Normal file
65
code/renderer/shaders/common/state_bits.h.hlsli
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// shader stage state constants
|
||||
|
||||
|
||||
#if !defined(DISABLE_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#define GLS_SRCBLEND_ZERO 0x00000001u
|
||||
#define GLS_SRCBLEND_ONE 0x00000002u
|
||||
#define GLS_SRCBLEND_DST_COLOR 0x00000003u
|
||||
#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004u
|
||||
#define GLS_SRCBLEND_SRC_ALPHA 0x00000005u
|
||||
#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006u
|
||||
#define GLS_SRCBLEND_DST_ALPHA 0x00000007u
|
||||
#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008u
|
||||
#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009u
|
||||
#define GLS_SRCBLEND_BITS 0x0000000fu
|
||||
|
||||
#define GLS_DSTBLEND_ZERO 0x00000010u
|
||||
#define GLS_DSTBLEND_ONE 0x00000020u
|
||||
#define GLS_DSTBLEND_SRC_COLOR 0x00000030u
|
||||
#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040u
|
||||
#define GLS_DSTBLEND_SRC_ALPHA 0x00000050u
|
||||
#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060u
|
||||
#define GLS_DSTBLEND_DST_ALPHA 0x00000070u
|
||||
#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080u
|
||||
#define GLS_DSTBLEND_BITS 0x000000f0u
|
||||
|
||||
#define GLS_BLEND_BITS 0x000000ffu
|
||||
|
||||
#define GLS_DEPTHMASK_TRUE 0x00000100u // enable depth writes
|
||||
|
||||
#define GLS_POLYMODE_LINE 0x00001000u // wireframe polygon filling, not line rendering
|
||||
|
||||
#define GLS_DEPTHTEST_DISABLE 0x00010000u // disable depth tests
|
||||
#define GLS_DEPTHFUNC_EQUAL 0x00020000u
|
||||
|
||||
#define GLS_STAGEINDEX_BITS 0x00700000u
|
||||
#define GLS_STAGEINDEX_SHIFT 20u
|
||||
|
||||
#define GLS_ATEST_GT_0 0x10000000u
|
||||
#define GLS_ATEST_LT_80 0x20000000u
|
||||
#define GLS_ATEST_GE_80 0x40000000u
|
||||
#define GLS_ATEST_BITS 0x70000000u
|
65
code/renderer/shaders/crp/accumdof_accum.hlsl
Normal file
65
code/renderer/shaders/crp/accumdof_accum.hlsl
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// accumulation depth of field: accumulation pass
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint textureIndex;
|
||||
};
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(uint id : SV_VertexID)
|
||||
{
|
||||
VOut output;
|
||||
output.position = FSTrianglePosFromVertexId(id);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
|
||||
int2 tc = int2(input.position.xy);
|
||||
float3 color = texture0.Load(int3(tc.x, tc.y, 0)).rgb;
|
||||
float weight = 1.0 + Brightness(color);
|
||||
float4 result = float4(color * weight, weight);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
99
code/renderer/shaders/crp/accumdof_debug.hlsl
Normal file
99
code/renderer/shaders/crp/accumdof_debug.hlsl
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// accumulation depth of field: debug overlay
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "dof.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
matrix mvp; // displaced view, to project to CS
|
||||
matrix invMvp; // main view, to unproject to WS
|
||||
uint colorTextureIndex;
|
||||
uint depthTextureIndex;
|
||||
uint debugMode; // 1: colorized coc, 2: constant intensity far field
|
||||
int tcScale;
|
||||
float focusDist;
|
||||
float linearDepthA; // main view, to unproject to WS
|
||||
float linearDepthB;
|
||||
float maxNearCocCS;
|
||||
float maxFarCocCS;
|
||||
};
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(uint id : SV_VertexID)
|
||||
{
|
||||
VOut output;
|
||||
output.position = FSTrianglePosFromVertexId(id);
|
||||
output.texCoords = FSTriangleTCFromVertexId(id);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D colorTexture = ResourceDescriptorHeap[colorTextureIndex];
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
|
||||
int3 tcColor = int3(input.position.xy, 0);
|
||||
int3 tcDepth = int3(input.position.xy / tcScale, 0);
|
||||
float3 color = colorTexture.Load(tcColor).rgb;
|
||||
float depthZW = depthTexture.Load(tcDepth);
|
||||
float depth = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
bool nearField = depth < focusDist;
|
||||
float4 result;
|
||||
if(debugMode == 1)
|
||||
{
|
||||
float quadPosXCS = input.texCoords.x * 2.0 - 1.0;
|
||||
float quadPosYCS = (1.0 - input.texCoords.y) * 2.0 - 1.0;
|
||||
float4 positionWS = mul(invMvp, float4(quadPosXCS, quadPosYCS, depthZW, 1));
|
||||
float4 positionCS = mul(mvp, float4(positionWS.xyz / positionWS.w, 1));
|
||||
float coc = distance(positionCS.xy / positionCS.w, float2(quadPosXCS, quadPosYCS));
|
||||
result = DOF_DebugCoc(color, nearField, saturate(coc / maxNearCocCS), saturate(coc / maxFarCocCS));
|
||||
}
|
||||
else if(debugMode == 2)
|
||||
{
|
||||
result = DOF_DebugFocusPlane(color, nearField);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = float4(color, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
65
code/renderer/shaders/crp/accumdof_norm.hlsl
Normal file
65
code/renderer/shaders/crp/accumdof_norm.hlsl
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// accumulation depth of field: normalization pass
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint textureIndex;
|
||||
};
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(uint id : SV_VertexID)
|
||||
{
|
||||
VOut output;
|
||||
output.position = FSTrianglePosFromVertexId(id);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
|
||||
int2 tc = int2(input.position.xy);
|
||||
float4 sum = texture0.Load(int3(tc.x, tc.y, 0));
|
||||
float3 color = saturate(sum.rgb / sum.a);
|
||||
float4 result = float4(color, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
69
code/renderer/shaders/crp/blit.hlsl
Normal file
69
code/renderer/shaders/crp/blit.hlsl
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// blit shader - unlike texture copies, it doesn't care about the specific formats used
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint textureIndex;
|
||||
uint samplerIndex;
|
||||
float2 tcScale;
|
||||
float2 tcBias;
|
||||
};
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(uint id : SV_VertexID)
|
||||
{
|
||||
VOut output;
|
||||
output.position = FSTrianglePosFromVertexId(id);
|
||||
output.texCoords = FSTriangleTCFromVertexId(id);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
SamplerState sampler0 = SamplerDescriptorHeap[samplerIndex];
|
||||
float2 tc = input.texCoords * tcScale + tcBias;
|
||||
float3 base = texture0.Sample(sampler0, tc).rgb;
|
||||
float4 result = float4(base, 1.0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
144
code/renderer/shaders/crp/common.hlsli
Normal file
144
code/renderer/shaders/crp/common.hlsli
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// shared utilities
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../common/state_bits.h.hlsli"
|
||||
#include "../common/blend.hlsli"
|
||||
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define PI_D2 (PI / 2.0)
|
||||
#define PI_D4 (PI / 4.0)
|
||||
#define PI_M2 (PI * 2.0)
|
||||
|
||||
|
||||
float DegToRad(float deg)
|
||||
{
|
||||
return PI * (deg / 180.0);
|
||||
}
|
||||
|
||||
float RadToDeg(float rad)
|
||||
{
|
||||
return 180.0 * (rad / PI);
|
||||
}
|
||||
|
||||
float Brightness(float3 color)
|
||||
{
|
||||
float brightness = dot(color, float3(0.299, 0.587, 0.114));
|
||||
|
||||
return brightness;
|
||||
}
|
||||
|
||||
float4 MakeGreyscale(float4 input, float amount)
|
||||
{
|
||||
float grey = dot(input.rgb, float3(0.299, 0.587, 0.114));
|
||||
float4 result = lerp(input, float4(grey, grey, grey, input.a), amount);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
f = far clip plane distance
|
||||
n = near clip plane distance
|
||||
exp = exponential depth value (as stored in the Z-buffer)
|
||||
|
||||
2 * f * n B
|
||||
linear(exp) = ----------------------- = -------
|
||||
(f + n) - exp * (f - n) exp - A
|
||||
|
||||
f + n -2 * f * n
|
||||
with A = ----- and B = ----------
|
||||
f - n f - n
|
||||
*/
|
||||
float LinearDepth(float zwDepth, float A, float B)
|
||||
{
|
||||
return B / (zwDepth - A);
|
||||
}
|
||||
|
||||
float4 FSTrianglePosFromVertexId(uint id)
|
||||
{
|
||||
return float4(
|
||||
(float)(id / 2) * 4.0 - 1.0,
|
||||
(float)(id % 2) * 4.0 - 1.0,
|
||||
0.0,
|
||||
1.0);
|
||||
}
|
||||
|
||||
float2 FSTriangleTCFromVertexId(uint id)
|
||||
{
|
||||
return float2(
|
||||
(float)(id / 2) * 2.0,
|
||||
1.0 - (float)(id % 2) * 2.0);
|
||||
}
|
||||
|
||||
uint PackColor(float4 c)
|
||||
{
|
||||
uint4 u = uint4(saturate(c) * 255.0);
|
||||
uint r = u.r | (u.g << 8) | (u.b << 16) | (u.a << 24);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
float4 UnpackColor(uint c)
|
||||
{
|
||||
uint4 u = uint4(c & 0xFFu, (c >> 8) & 0xFFu, (c >> 16) & 0xFFu, (c >> 24) & 0xFFu);
|
||||
float4 r = float4(u) / 255.0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
float EaseInCubic(float x)
|
||||
{
|
||||
return x * x * x;
|
||||
}
|
||||
|
||||
float EaseOutCubic(float x)
|
||||
{
|
||||
float y = 1.0 - x;
|
||||
|
||||
return 1.0 - y * y * y;
|
||||
}
|
||||
|
||||
float EaseInOutCubic(float x)
|
||||
{
|
||||
if(x < 0.5)
|
||||
{
|
||||
return 4 * x * x * x;
|
||||
}
|
||||
|
||||
float y = -2 * x + 2;
|
||||
|
||||
return 1 - 0.5 * y * y * y;
|
||||
}
|
||||
|
||||
float EaseInQuad(float x)
|
||||
{
|
||||
return x * x;
|
||||
}
|
||||
|
||||
float SmoothStep(float x)
|
||||
{
|
||||
return smoothstep(0.0, 1.0, x);
|
||||
}
|
54
code/renderer/shaders/crp/dof.hlsli
Normal file
54
code/renderer/shaders/crp/dof.hlsli
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// depth of field: debug overlay support functions
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
float4 DOF_DebugCoc(float3 color, bool nearField, float nearCoc, float farCoc)
|
||||
{
|
||||
float blendFactor;
|
||||
float3 target;
|
||||
if(nearField)
|
||||
{
|
||||
blendFactor = 0.5 * nearCoc;
|
||||
target = float3(0, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
blendFactor = 0.5 * farCoc;
|
||||
target = float3(0, 0, 1);
|
||||
}
|
||||
float4 result = float4(lerp(color, target, blendFactor), 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 DOF_DebugFocusPlane(float3 color, bool nearField)
|
||||
{
|
||||
float farFieldFactor = nearField ? 0.0 : 0.25;
|
||||
float3 farFieldColor = float3(0.5, 0, 0.5);
|
||||
float3 mixed = lerp(color, farFieldColor, farFieldFactor);
|
||||
float4 result = float4(mixed, 1);
|
||||
|
||||
return result;
|
||||
}
|
58
code/renderer/shaders/crp/fog.hlsli
Normal file
58
code/renderer/shaders/crp/fog.hlsli
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// fog volume (AABB) rendering - shared code
|
||||
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float depthVS : DEPTHVS;
|
||||
};
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
matrix modelViewMatrix;
|
||||
matrix projectionMatrix;
|
||||
float4 boxMin;
|
||||
float4 boxMax;
|
||||
float4 color;
|
||||
float depth;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
uint depthTextureIndex;
|
||||
};
|
||||
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
|
||||
VOut vs(float3 positionOS : POSITION)
|
||||
{
|
||||
float3 positionWS = boxMin.xyz + positionOS * (boxMax.xyz - boxMin.xyz);
|
||||
float4 positionVS = mul(modelViewMatrix, float4(positionWS, 1));
|
||||
|
||||
VOut output;
|
||||
output.position = mul(projectionMatrix, positionVS);
|
||||
output.depthVS = -positionVS.z;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
43
code/renderer/shaders/crp/fog_inside.hlsl
Normal file
43
code/renderer/shaders/crp/fog_inside.hlsl
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// fog volume (AABB) seen from inside
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "fog.hlsli"
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
float depthZW = depthTexture.Load(int3(input.position.xy, 0));
|
||||
float depthBuff = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
float depthFrag = input.depthVS;
|
||||
float depthMin = min(depthBuff, depthFrag);
|
||||
float fogOpacity = saturate(depthMin / depth);
|
||||
float4 result = float4(color.rgb, fogOpacity);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
47
code/renderer/shaders/crp/fog_outside.hlsl
Normal file
47
code/renderer/shaders/crp/fog_outside.hlsl
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// fog volume (AABB) seen from outside
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "fog.hlsli"
|
||||
|
||||
|
||||
#ifdef PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
float depthZW = depthTexture.Load(int3(input.position.xy, 0));
|
||||
float depthBuff = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
float depthFrag = input.depthVS;
|
||||
if(depthFrag > depthBuff)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
float fogOpacity = saturate((depthBuff - depthFrag) / depth);
|
||||
float4 result = float4(color.rgb, fogOpacity);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
61
code/renderer/shaders/crp/gatherdof.hlsli
Normal file
61
code/renderer/shaders/crp/gatherdof.hlsli
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// gather depth of field: support functions
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
|
||||
|
||||
#define MAX_BLUR_DIAMETER 32.0
|
||||
#define MAX_COC 16.0
|
||||
|
||||
|
||||
float CircleOfConfusion(float depth, float focusNearMin, float focusNearMax, float focusFarMin, float focusFarMax)
|
||||
{
|
||||
if(depth <= focusNearMin)
|
||||
{
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
if(depth > focusNearMin && depth < focusNearMax)
|
||||
{
|
||||
float t = 1.0 - (depth - focusNearMin) / (focusNearMax - focusNearMin);
|
||||
|
||||
return -t;
|
||||
}
|
||||
|
||||
if(depth > focusFarMin && depth < focusFarMax)
|
||||
{
|
||||
float t = (depth - focusFarMin) / (focusFarMax - focusFarMin);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
if(depth >= focusFarMax)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
207
code/renderer/shaders/crp/gatherdof_blur.hlsl
Normal file
207
code/renderer/shaders/crp/gatherdof_blur.hlsl
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// gather depth of field: near-field and far-field blur
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "gatherdof.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint colorTextureIndex;
|
||||
uint nearColorTextureIndex;
|
||||
uint nearMaxCocTextureIndex; // tile
|
||||
uint nearCocTextureIndex; // blurry
|
||||
uint nearOutputTextureIndex;
|
||||
uint farColorTextureIndex;
|
||||
uint farCocTextureIndex; // sharp
|
||||
uint farOutputTextureIndex;
|
||||
uint samplerIndex; // linear/clamp
|
||||
float brightnessScale;
|
||||
float bladeCount;
|
||||
float bokehAngleRad;
|
||||
};
|
||||
|
||||
// the input is in [0,1]^2, the output polygon is centered at the origin
|
||||
float2 MapUnitSquareToPolygon(float2 square, float apertureBladeCount, float apertureAngleRad)
|
||||
{
|
||||
// needed to avoid inf/nan propagation through theta for samples
|
||||
// that are exactly in the middle of the quad on either axis
|
||||
// (i.e. square.x|y == 0.5 gets remapped to 0.0)
|
||||
const float epsilon = 0.000001;
|
||||
|
||||
// morph into a square in [-1,1]^2
|
||||
square = square * 2.0 - 1.0;
|
||||
|
||||
// morph the square into a disk
|
||||
// "A Low Distortion Map Between Disk and Square" by Peter Shirley and Kenneth Chiu
|
||||
float radius, angle;
|
||||
float2 square2 = square * square;
|
||||
if(square2.x > square2.y)
|
||||
{
|
||||
// left and right quadrants
|
||||
radius = square.x;
|
||||
angle = (square.y * PI_D4) / (square.x + epsilon);
|
||||
}
|
||||
else
|
||||
{
|
||||
// top and bottom quadrants
|
||||
radius = square.y;
|
||||
angle = PI_D2 - (square.x * PI_D4) / (square.y + epsilon);
|
||||
}
|
||||
if(radius < 0.0)
|
||||
{
|
||||
radius = -radius;
|
||||
angle += PI;
|
||||
}
|
||||
|
||||
// morph the disk into a polygon
|
||||
// "Graphics Gems from CryENGINE 3" by Tiago Sousa
|
||||
float edgeCount = apertureBladeCount;
|
||||
if(edgeCount >= 3.0)
|
||||
{
|
||||
float num = cos(PI / edgeCount);
|
||||
float den0 = PI_M2 / edgeCount;
|
||||
float den1 = (angle * edgeCount + PI) / PI_M2;
|
||||
float den = angle - (den0 * floor(den1));
|
||||
radius *= num / cos(den);
|
||||
angle += apertureAngleRad;
|
||||
}
|
||||
|
||||
float2 disk;
|
||||
sincos(angle, disk.y, disk.x);
|
||||
disk *= radius;
|
||||
|
||||
return disk;
|
||||
}
|
||||
|
||||
float4 BlurFarField(Texture2D inTexture, SamplerState samplerState, float coc, float2 tc01, float2 pixelSize)
|
||||
{
|
||||
const int TAP_COUNT_BLUR = 16;
|
||||
float2 tcScale = 16.0 * coc * pixelSize;
|
||||
|
||||
float4 result = inTexture.SampleLevel(samplerState, tc01, 0);
|
||||
for(int y = 0; y < TAP_COUNT_BLUR; ++y)
|
||||
{
|
||||
for(int x = 0; x < TAP_COUNT_BLUR; ++x)
|
||||
{
|
||||
float2 tcQuad = float2(x, y) / float(TAP_COUNT_BLUR - 1);
|
||||
float2 tcOffset = MapUnitSquareToPolygon(tcQuad, bladeCount, bokehAngleRad) * tcScale;
|
||||
float4 sampleValue = inTexture.SampleLevel(samplerState, tc01 + tcOffset, 0);
|
||||
result += sampleValue;
|
||||
}
|
||||
}
|
||||
|
||||
result /= result.a;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlurNearField(Texture2D inTexture, SamplerState samplerState, float tileMaxCoc, float2 tc01, float2 pixelSize)
|
||||
{
|
||||
const int TAP_COUNT_BLUR = 15; // must be odd so we generate 1 sample at 0.5, 0.5 in the quad
|
||||
float2 tcScale = 16.0 * tileMaxCoc * pixelSize;
|
||||
float insideCount = 0.0;
|
||||
float totalCount = 1.0 + float(TAP_COUNT_BLUR * TAP_COUNT_BLUR);
|
||||
float4 result = float4(0, 0, 0, 0);
|
||||
float weightSum = 0.0;
|
||||
|
||||
for(int y = 0; y < TAP_COUNT_BLUR; ++y)
|
||||
{
|
||||
for(int x = 0; x < TAP_COUNT_BLUR; ++x)
|
||||
{
|
||||
float2 tcQuad = float2(x, y) / float(TAP_COUNT_BLUR - 1);
|
||||
float2 tcOffset = MapUnitSquareToPolygon(tcQuad, bladeCount, bokehAngleRad) * tcScale;
|
||||
float4 sampleValue = inTexture.SampleLevel(samplerState, tc01 + tcOffset, 0);
|
||||
float inside = sampleValue.a > 0.0 ? 1.0 : 0.0;
|
||||
float brightnessWeight = 1.0 + brightnessScale * Brightness(sampleValue.rgb);
|
||||
float colorWeight = (sampleValue.a / tileMaxCoc) * brightnessWeight;
|
||||
insideCount += inside;
|
||||
weightSum += inside * colorWeight;
|
||||
result += inside * float4(colorWeight.xxx, 1) * sampleValue;
|
||||
}
|
||||
}
|
||||
|
||||
if(insideCount >= 1.0)
|
||||
{
|
||||
result.rgb /= weightSum;
|
||||
result.a /= insideCount;
|
||||
result.a *= EaseInOutCubic(saturate(2.0 * (insideCount / totalCount)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = float4(1, 1, 0, 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 dtid : SV_DispatchThreadID)
|
||||
{
|
||||
uint2 tc = dtid.xy;
|
||||
RWTexture2D<float4> nearOutputTexture = ResourceDescriptorHeap[nearOutputTextureIndex];
|
||||
RWTexture2D<float4> farOutputTexture = ResourceDescriptorHeap[farOutputTextureIndex];
|
||||
uint width, height;
|
||||
farOutputTexture.GetDimensions(width, height);
|
||||
if(any(dtid.xy >= uint2(width, height)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SamplerState samplerState = SamplerDescriptorHeap[samplerIndex];
|
||||
Texture2D colorTexture = ResourceDescriptorHeap[colorTextureIndex];
|
||||
Texture2D nearColorTexture = ResourceDescriptorHeap[nearColorTextureIndex];
|
||||
Texture2D farColorTexture = ResourceDescriptorHeap[farColorTextureIndex];
|
||||
Texture2D<float> nearCocTexture = ResourceDescriptorHeap[nearCocTextureIndex];
|
||||
Texture2D<float> nearMaxCocTexture = ResourceDescriptorHeap[nearMaxCocTextureIndex];
|
||||
Texture2D<float> farCocTexture = ResourceDescriptorHeap[farCocTextureIndex];
|
||||
RWTexture2D<float4> nearOutTexture = ResourceDescriptorHeap[nearOutputTextureIndex];
|
||||
RWTexture2D<float4> farOutTexture = ResourceDescriptorHeap[farOutputTextureIndex];
|
||||
float2 tc01 = (float2(dtid.xy) + float2(0.5, 0.5)) / float2(width, height);
|
||||
float2 pixelSize = float2(1, 1) / float2(width, height);
|
||||
float nearCoc = nearCocTexture.SampleLevel(samplerState, tc01, 0);
|
||||
float nearMaxCoc = nearMaxCocTexture.SampleLevel(samplerState, tc01, 0);
|
||||
float farCoc = farCocTexture.SampleLevel(samplerState, tc01, 0);
|
||||
float4 color = colorTexture.SampleLevel(samplerState, tc01, 0);
|
||||
|
||||
if(nearMaxCoc > 0.0)
|
||||
{
|
||||
nearOutTexture[tc] = BlurNearField(nearColorTexture, samplerState, nearMaxCoc, tc01, pixelSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// A must be 0 to disable the near field from being blended
|
||||
nearOutTexture[tc] = float4(color.rgb, 0);
|
||||
}
|
||||
|
||||
if(farCoc > 0.0)
|
||||
{
|
||||
farOutTexture[tc] = BlurFarField(farColorTexture, samplerState, farCoc, tc01, pixelSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// RGB must be 0 to not mess up the fill pass of neighbor pixels that are inside the near field
|
||||
// A must be 0 to disable the far field from being blended
|
||||
farOutTexture[tc] = float4(0, 0, 0, 0);
|
||||
}
|
||||
}
|
65
code/renderer/shaders/crp/gatherdof_coc_tile_gen.hlsl
Normal file
65
code/renderer/shaders/crp/gatherdof_coc_tile_gen.hlsl
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// gather depth of field: near-field circle of confusion tile generation
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "gatherdof.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint inputTextureIndex;
|
||||
uint outputTextureIndex;
|
||||
};
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 dtid : SV_DispatchThreadID, uint3 gid : SV_GroupID, uint3 gtid : SV_GroupThreadID)
|
||||
{
|
||||
uint2 tcOut = dtid.xy;
|
||||
RWTexture2D<float> outputTexture = ResourceDescriptorHeap[outputTextureIndex];
|
||||
uint width, height;
|
||||
outputTexture.GetDimensions(width, height);
|
||||
if(any(dtid.xy >= uint2(width, height)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Texture2D<float> inputTexture = ResourceDescriptorHeap[inputTextureIndex];
|
||||
|
||||
// This loop can read out of bounds in the inputTexture.
|
||||
// Each full-res pixel has a corresponding tile pixel, but the reverse isn't always true.
|
||||
// Texture.Load is specced to return 0 on OOB accesses.
|
||||
// Since we max() the values, zeroes have no effect on the final result.
|
||||
uint2 tcInCorner = tcOut * uint2(16, 16);
|
||||
float maxCoc = 0.0;
|
||||
for(uint y = 0; y < 16; y++)
|
||||
{
|
||||
for(uint x = 0; x < 16; x++)
|
||||
{
|
||||
uint2 tcIn = tcInCorner + uint2(x, y);
|
||||
float coc = inputTexture.Load(uint3(tcIn.x, tcIn.y, 0));
|
||||
maxCoc = max(maxCoc, coc);
|
||||
}
|
||||
}
|
||||
|
||||
outputTexture[tcOut] = maxCoc;
|
||||
}
|
64
code/renderer/shaders/crp/gatherdof_coc_tile_max.hlsl
Normal file
64
code/renderer/shaders/crp/gatherdof_coc_tile_max.hlsl
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// gather depth of field: near-field circle of confusion tile dilation
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "gatherdof.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint inputTextureIndex;
|
||||
uint outputTextureIndex;
|
||||
uint samplerIndex; // point/clamp
|
||||
};
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 dtid : SV_DispatchThreadID)
|
||||
{
|
||||
uint2 tc = dtid.xy;
|
||||
RWTexture2D<float> outputTexture = ResourceDescriptorHeap[outputTextureIndex];
|
||||
uint width, height;
|
||||
outputTexture.GetDimensions(width, height);
|
||||
if(any(dtid.xy >= uint2(width, height)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Texture2D<float> inputTexture = ResourceDescriptorHeap[inputTextureIndex];
|
||||
SamplerState samplerState = SamplerDescriptorHeap[samplerIndex];
|
||||
|
||||
float2 tcShifted = float2(tc) + float2(0.5, 0.5);
|
||||
float2 pixelSize = float2(1, 1) / float2(width, height);
|
||||
float maxCoc = 0.0;
|
||||
for(int y = -1; y <= 1; y++)
|
||||
{
|
||||
for(int x = -1; x <= 1; x++)
|
||||
{
|
||||
float2 tc01 = (tcShifted + float2(x, y)) * pixelSize;
|
||||
float coc = inputTexture.SampleLevel(samplerState, tc01, 0);
|
||||
maxCoc = max(maxCoc, coc);
|
||||
}
|
||||
}
|
||||
|
||||
outputTexture[tc] = maxCoc;
|
||||
}
|
84
code/renderer/shaders/crp/gatherdof_combine.hlsl
Normal file
84
code/renderer/shaders/crp/gatherdof_combine.hlsl
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// gather depth of field: final blend pass
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "gatherdof.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint nearTextureIndex;
|
||||
uint farTextureIndex;
|
||||
uint nearCocTextureIndex;
|
||||
uint farCocTextureIndex;
|
||||
uint sharpTextureIndex;
|
||||
uint samplerIndex; // point/clamp
|
||||
};
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(uint id : SV_VertexID)
|
||||
{
|
||||
VOut output;
|
||||
output.position = FSTrianglePosFromVertexId(id);
|
||||
output.texCoords = FSTriangleTCFromVertexId(id);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
SamplerState samplerState = SamplerDescriptorHeap[samplerIndex];
|
||||
Texture2D nearColorTexture = ResourceDescriptorHeap[nearTextureIndex];
|
||||
Texture2D farColorTexture = ResourceDescriptorHeap[farTextureIndex];
|
||||
Texture2D<float> nearCocTexture = ResourceDescriptorHeap[nearCocTextureIndex];
|
||||
Texture2D<float> farCocTexture = ResourceDescriptorHeap[farCocTextureIndex];
|
||||
Texture2D sharpTexture = ResourceDescriptorHeap[sharpTextureIndex];
|
||||
|
||||
float4 nearColor = nearColorTexture.Sample(samplerState, input.texCoords);
|
||||
float4 farColor = farColorTexture.Sample(samplerState, input.texCoords);
|
||||
//float nearCoc = nearCocTexture.Sample(samplerState, input.texCoords);
|
||||
float nearCoc = saturate(nearColor.a);
|
||||
float farCoc = farCocTexture.Sample(samplerState, input.texCoords);
|
||||
float4 sharp = sharpTexture.Sample(samplerState, input.texCoords);
|
||||
|
||||
float3 color = lerp(sharp.rgb, farColor.rgb, farCoc);
|
||||
color = lerp(color, nearColor.rgb, nearCoc);
|
||||
float4 result = float4(color, 1.0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
93
code/renderer/shaders/crp/gatherdof_debug.hlsl
Normal file
93
code/renderer/shaders/crp/gatherdof_debug.hlsl
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// gather depth of field: debug overlay
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "gatherdof.hlsli"
|
||||
#include "dof.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint colorTextureIndex;
|
||||
uint depthTextureIndex;
|
||||
uint debugMode;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float focusNearMin;
|
||||
float focusNearMax;
|
||||
float focusFarMin;
|
||||
float focusFarMax;
|
||||
float focusDist;
|
||||
};
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(uint id : SV_VertexID)
|
||||
{
|
||||
VOut output;
|
||||
output.position = FSTrianglePosFromVertexId(id);
|
||||
output.texCoords = FSTriangleTCFromVertexId(id);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D colorTexture = ResourceDescriptorHeap[colorTextureIndex];
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
uint3 tc = uint3(input.position.x, input.position.y, 0);
|
||||
float3 color = colorTexture.Load(tc).rgb;
|
||||
float depthZW = depthTexture.Load(tc);
|
||||
float depth = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
float coc = CircleOfConfusion(depth, focusNearMin, focusNearMax, focusFarMin, focusFarMax);
|
||||
float nearField = coc < 0.0;
|
||||
float4 result;
|
||||
if(debugMode == 1)
|
||||
{
|
||||
result = DOF_DebugCoc(color, nearField, saturate(-coc), saturate(coc));
|
||||
}
|
||||
else if(debugMode == 2)
|
||||
{
|
||||
result = DOF_DebugFocusPlane(color, nearField);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = float4(color, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
76
code/renderer/shaders/crp/gatherdof_fill.hlsl
Normal file
76
code/renderer/shaders/crp/gatherdof_fill.hlsl
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// gather depth of field: max blur post-filter to combat undersampling
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "gatherdof.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint nearInputTextureIndex;
|
||||
uint nearOutputTextureIndex;
|
||||
uint farInputTextureIndex;
|
||||
uint farOutputTextureIndex;
|
||||
uint samplerIndex; // point/clamp
|
||||
};
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 dtid : SV_DispatchThreadID)
|
||||
{
|
||||
uint2 tc = dtid.xy;
|
||||
RWTexture2D<float4> nearOutputTexture = ResourceDescriptorHeap[nearOutputTextureIndex];
|
||||
RWTexture2D<float4> farOutputTexture = ResourceDescriptorHeap[farOutputTextureIndex];
|
||||
uint width, height, levels;
|
||||
nearOutputTexture.GetDimensions(width, height);
|
||||
if(any(dtid.xy >= uint2(width, height)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SamplerState samplerState = SamplerDescriptorHeap[samplerIndex];
|
||||
Texture2D nearInputTexture = ResourceDescriptorHeap[nearInputTextureIndex];
|
||||
Texture2D farInputTexture = ResourceDescriptorHeap[farInputTextureIndex];
|
||||
|
||||
float2 tc01 = (float2(tc) + float2(0.5, 0.5)) / float2(width, height);
|
||||
float2 pixelSize = float2(1, 1) / float2(width, height);
|
||||
float4 nearFilled = float4(0, 0, 0, 0);
|
||||
float4 farFilled = float4(0, 0, 0, 0);
|
||||
for(int y = -1; y <= 1; y++)
|
||||
{
|
||||
for(int x = -1; x <= 1; x++)
|
||||
{
|
||||
float2 tcSample01 = tc01 + float2(x, y) * pixelSize;
|
||||
float4 nearSample = nearInputTexture.SampleLevel(samplerState, tcSample01, 0);
|
||||
float4 farSample = farInputTexture.SampleLevel(samplerState, tcSample01, 0);
|
||||
nearFilled = max(nearFilled, nearSample);
|
||||
farFilled = max(farFilled, farSample);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure to keep the original blend factors
|
||||
nearFilled.a = nearInputTexture.Load(uint3(tc.x, tc.y, 0)).a;
|
||||
farFilled.a = farInputTexture.Load(uint3(tc.x, tc.y, 0)).a;
|
||||
|
||||
nearOutputTexture[tc] = nearFilled;
|
||||
farOutputTexture[tc] = farFilled;
|
||||
}
|
78
code/renderer/shaders/crp/gatherdof_split.hlsl
Normal file
78
code/renderer/shaders/crp/gatherdof_split.hlsl
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// gather depth of field: field split and CoC generation
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "gatherdof.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint depthTextureIndex;
|
||||
uint colorTextureIndex;
|
||||
uint nearColorTextureIndex;
|
||||
uint farColorTextureIndex;
|
||||
uint nearCocTextureIndex;
|
||||
uint farCocTextureIndex;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float focusNearMin;
|
||||
float focusNearMax;
|
||||
float focusFarMin;
|
||||
float focusFarMax;
|
||||
float brightnessScale;
|
||||
};
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 dtid : SV_DispatchThreadID)
|
||||
{
|
||||
uint2 tc = dtid.xy;
|
||||
Texture2D colorTexture = ResourceDescriptorHeap[colorTextureIndex];
|
||||
uint width, height, levels;
|
||||
colorTexture.GetDimensions(0, width, height, levels);
|
||||
if(any(dtid.xy >= uint2(width, height)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
RWTexture2D<float4> nearColorTexture = ResourceDescriptorHeap[nearColorTextureIndex];
|
||||
RWTexture2D<float4> farColorTexture = ResourceDescriptorHeap[farColorTextureIndex];
|
||||
RWTexture2D<float> nearCocTexture = ResourceDescriptorHeap[nearCocTextureIndex];
|
||||
RWTexture2D<float> farCocTexture = ResourceDescriptorHeap[farCocTextureIndex];
|
||||
|
||||
float4 color = colorTexture[tc];
|
||||
float depthZW = depthTexture[tc];
|
||||
float depth = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
float coc = CircleOfConfusion(depth, focusNearMin, focusNearMax, focusFarMin, focusFarMax);
|
||||
float nearCoc = max(-coc, 0.0);
|
||||
float farCoc = max(coc, 0.0);
|
||||
float brightnessWeight = 1.0 + brightnessScale * Brightness(color.rgb);
|
||||
float farWeight = farCoc * brightnessWeight;
|
||||
float4 nearColor = float4(color.rgb, nearCoc);
|
||||
float4 farColor = float4(color.rgb * farWeight, farWeight);
|
||||
|
||||
nearColorTexture[tc] = nearColor;
|
||||
farColorTexture[tc] = farColor;
|
||||
nearCocTexture[tc] = nearCoc;
|
||||
farCocTexture[tc] = farCoc;
|
||||
}
|
73
code/renderer/shaders/crp/imgui.hlsl
Normal file
73
code/renderer/shaders/crp/imgui.hlsl
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Dear ImGui integration
|
||||
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
float4 col : COLOR0;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
float4x4 projectionMatrix;
|
||||
uint textureIndex;
|
||||
uint samplerIndex;
|
||||
float mipIndex;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
struct VIn
|
||||
{
|
||||
float2 pos : POSITION;
|
||||
float4 col : COLOR0;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VOut vs(VIn input)
|
||||
{
|
||||
VOut output;
|
||||
output.pos = mul(projectionMatrix, float4(input.pos.xy, 0.0, 1.0));
|
||||
output.col = input.col;
|
||||
output.uv = input.uv;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
SamplerState sampler0 = SamplerDescriptorHeap[samplerIndex];
|
||||
float4 result = input.col * texture0.SampleLevel(sampler0, input.uv, mipIndex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
40
code/renderer/shaders/crp/mip_1.hlsl
Normal file
40
code/renderer/shaders/crp/mip_1.hlsl
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// mip-map generation: gamma-space to linear-space transform
|
||||
|
||||
|
||||
#include "../common/mip_gen.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float gamma;
|
||||
uint srcTexture;
|
||||
uint dstTexture;
|
||||
}
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture2D<float4> src = ResourceDescriptorHeap[srcTexture];
|
||||
RWTexture2D<float4> dst = ResourceDescriptorHeap[dstTexture];
|
||||
MipGen_GammaToLinear(dst, src, id, gamma);
|
||||
}
|
46
code/renderer/shaders/crp/mip_2.hlsl
Normal file
46
code/renderer/shaders/crp/mip_2.hlsl
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// mip-map generation: 8-tap 1D filter
|
||||
|
||||
|
||||
#include "../common/mip_gen.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float4 weights;
|
||||
int2 maxSize;
|
||||
int2 scale;
|
||||
int2 offset;
|
||||
uint clampMode; // 0 = repeat
|
||||
uint srcMip;
|
||||
uint dstMip;
|
||||
uint srcTexture;
|
||||
uint dstTexture;
|
||||
}
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture2D<float4> src = ResourceDescriptorHeap[srcTexture];
|
||||
RWTexture2D<float4> dst = ResourceDescriptorHeap[dstTexture];
|
||||
MipGen_DownSample(dst, src, id, maxSize, clampMode, scale, offset, weights);
|
||||
}
|
44
code/renderer/shaders/crp/mip_3.hlsl
Normal file
44
code/renderer/shaders/crp/mip_3.hlsl
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// mip-map generation: linear-space to gamma-space transform
|
||||
|
||||
|
||||
#include "../common/mip_gen.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float4 blendColor;
|
||||
float intensity;
|
||||
float invGamma; // 1.0 / gamma
|
||||
uint srcMip;
|
||||
uint dstMip;
|
||||
uint srcTexture;
|
||||
uint dstTexture;
|
||||
}
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture2D<float4> src = ResourceDescriptorHeap[srcTexture];
|
||||
RWTexture2D<float4> dst = ResourceDescriptorHeap[dstTexture];
|
||||
MipGen_LinearToGamma(dst, src, id, blendColor, intensity, invGamma);
|
||||
}
|
72
code/renderer/shaders/crp/nuklear.hlsl
Normal file
72
code/renderer/shaders/crp/nuklear.hlsl
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Nuklear integration
|
||||
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
float4 col : COLOR0;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float4x4 projectionMatrix;
|
||||
uint textureIndex;
|
||||
uint samplerIndex;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
struct VIn
|
||||
{
|
||||
float2 pos : POSITION;
|
||||
float4 col : COLOR0;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VOut vs(VIn input)
|
||||
{
|
||||
VOut output;
|
||||
output.pos = mul(projectionMatrix, float4(input.pos.xy, 0.0, 1.0));
|
||||
output.col = input.col;
|
||||
output.uv = input.uv;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
SamplerState sampler0 = SamplerDescriptorHeap[samplerIndex];
|
||||
float4 result = input.col * texture0.Sample(sampler0, input.uv);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
58
code/renderer/shaders/crp/oit.h.hlsli
Normal file
58
code/renderer/shaders/crp/oit.h.hlsli
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// shared structures and constants used to implement order-independent transparency
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#pragma pack(push, 4)
|
||||
typedef uint32_t uint;
|
||||
#endif
|
||||
|
||||
#define OIT_MAX_FRAGMENTS_PER_PIXEL 32
|
||||
#define OIT_AVG_FRAGMENTS_PER_PIXEL 16
|
||||
|
||||
struct OIT_Counter
|
||||
{
|
||||
uint fragmentCount;
|
||||
uint maxFragmentCount;
|
||||
uint overflowCount;
|
||||
};
|
||||
|
||||
struct OIT_Fragment
|
||||
{
|
||||
uint color;
|
||||
float depth; // higher is further away from the camera
|
||||
uint stateBits; // GLS_* stage bits + stage index
|
||||
uint next;
|
||||
uint shaderTrace; // shader index: 14 - frame index: 2 - enable: 1
|
||||
uint depthFadeDistOffset; // offset: fp16 - distance: fp16
|
||||
uint depthFadeScaleBias; // enable: 1 - color bias: 4 - color scale: 4
|
||||
// @TODO: move the 9 bits from depthFadeScaleBias into shaderTrace
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(OIT_Counter) == 12, "sizeof(OIT_Counter) is wrong");
|
||||
static_assert(sizeof(OIT_Fragment) == 28, "sizeof(OIT_Fragment) is wrong");
|
||||
#endif
|
131
code/renderer/shaders/crp/opaque.hlsl
Normal file
131
code/renderer/shaders/crp/opaque.hlsl
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// generic shader for opaque surfaces
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "world.h.hlsli"
|
||||
#include "world.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
// geometry
|
||||
matrix modelViewMatrix;
|
||||
matrix projectionMatrix;
|
||||
float4 clipPlane;
|
||||
|
||||
// general
|
||||
uint textureIndex;
|
||||
uint samplerIndex;
|
||||
uint shaderIndexBufferIndex;
|
||||
uint alphaTest;
|
||||
float greyscale;
|
||||
|
||||
// shader trace
|
||||
uint shaderTrace; // shader index: 14 - frame index: 2 - enable: 1
|
||||
uint centerPixel; // y: 16 - x: 16
|
||||
|
||||
// @TODO: dither
|
||||
// @TODO: Voronoi tiling
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
struct VIn
|
||||
{
|
||||
float3 position : POSITION;
|
||||
float3 normal : NORMAL;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float3 normal : NORMAL;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
float clipDist : SV_ClipDistance0;
|
||||
float2 proj2232 : PROJ;
|
||||
float depthVS : DEPTHVS;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(VIn input)
|
||||
{
|
||||
float4 positionVS = mul(modelViewMatrix, float4(input.position.xyz, 1));
|
||||
|
||||
VOut output;
|
||||
output.position = mul(projectionMatrix, positionVS);
|
||||
output.normal = input.normal;
|
||||
output.texCoords = input.texCoords;
|
||||
output.color = input.color;
|
||||
output.clipDist = dot(positionVS, clipPlane);
|
||||
output.proj2232 = float2(-projectionMatrix[2][2], projectionMatrix[2][3]);
|
||||
output.depthVS = -positionVS.z;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
// @TODO: Voronoi tiling
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
SamplerState sampler0 = ResourceDescriptorHeap[samplerIndex];
|
||||
float4 dst = texture0.Sample(sampler0, input.texCoords) * input.color;
|
||||
if(FailsAlphaTest(dst.a, alphaTest))
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
dst = MakeGreyscale(dst, greyscale);
|
||||
|
||||
// @TODO: dithering (need to figure out the tone mapping function first)
|
||||
|
||||
if(shaderTrace & 1)
|
||||
{
|
||||
// we only store the shader index of 1 pixel
|
||||
uint2 fragmentCoords = uint2(input.position.xy);
|
||||
uint2 centerCoords = uint2(centerPixel & 0xFFFF, centerPixel >> 16);
|
||||
if(all(fragmentCoords == centerCoords))
|
||||
{
|
||||
RWByteAddressBuffer shaderIndexBuffer = ResourceDescriptorHeap[shaderIndexBufferIndex];
|
||||
uint frameIndex = (shaderTrace >> 1) & 3;
|
||||
uint shaderIndex = shaderTrace >> 3;
|
||||
shaderIndexBuffer.Store(frameIndex * 4, shaderIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
#endif
|
74
code/renderer/shaders/crp/tone_map.hlsl
Normal file
74
code/renderer/shaders/crp/tone_map.hlsl
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// post-processing: moves from linear to gamma space
|
||||
// applies r_gamma, r_brightness, r_greyscale
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
};
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint textureIndex;
|
||||
uint samplerIndex;
|
||||
float invGamma;
|
||||
float brightness;
|
||||
float greyscale;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(uint id : SV_VertexID)
|
||||
{
|
||||
VOut output;
|
||||
output.position = FSTrianglePosFromVertexId(id);
|
||||
output.texCoords = FSTriangleTCFromVertexId(id);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
// X3571: pow(f, e) won't work if f is negative
|
||||
#pragma warning(disable : 3571)
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
SamplerState sampler0 = SamplerDescriptorHeap[samplerIndex];
|
||||
float3 base = texture0.Sample(sampler0, input.texCoords).rgb;
|
||||
float3 gc = pow(base, invGamma) * brightness;
|
||||
float4 result = MakeGreyscale(float4(gc.rgb, 1.0), greyscale);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
72
code/renderer/shaders/crp/tone_map_inverse.hlsl
Normal file
72
code/renderer/shaders/crp/tone_map_inverse.hlsl
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// post-processing: moves from gamma to linear space
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
};
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint textureIndex;
|
||||
uint samplerIndex;
|
||||
float gamma;
|
||||
float invBrightness;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(uint id : SV_VertexID)
|
||||
{
|
||||
VOut output;
|
||||
output.position = FSTrianglePosFromVertexId(id);
|
||||
output.texCoords = FSTriangleTCFromVertexId(id);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
// X3571: pow(f, e) won't work if f is negative
|
||||
#pragma warning(disable : 3571)
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
SamplerState sampler0 = SamplerDescriptorHeap[samplerIndex];
|
||||
float3 base = texture0.Sample(sampler0, input.texCoords).rgb;
|
||||
float3 linearSpace = pow(base * invBrightness, gamma);
|
||||
float4 result = float4(linearSpace, 1.0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
136
code/renderer/shaders/crp/transp_draw.hlsl
Normal file
136
code/renderer/shaders/crp/transp_draw.hlsl
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// add fragments of transparent surfaces to per-pixel linked lists
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "world.h.hlsli"
|
||||
#include "world.hlsli"
|
||||
#include "oit.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
matrix modelViewMatrix;
|
||||
matrix projectionMatrix;
|
||||
float4 clipPlane;
|
||||
|
||||
uint textureIndex;
|
||||
uint samplerIndex;
|
||||
uint alphaTest;
|
||||
uint counterBuffer;
|
||||
uint indexTexture;
|
||||
uint fragmentBuffer;
|
||||
float greyscale;
|
||||
uint stateBits;
|
||||
uint shaderTrace;
|
||||
uint depthFadeDistOffset; // offset: fp16 - distance: fp16
|
||||
uint depthFadeScaleBias; // enable: 1 - color bias: 4 - color scale: 4
|
||||
};
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
struct VIn
|
||||
{
|
||||
float3 position : POSITION;
|
||||
float3 normal : NORMAL;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float3 normal : NORMAL;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
float clipDist : SV_ClipDistance0;
|
||||
float2 proj2232 : PROJ;
|
||||
float depthVS : DEPTHVS;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(VIn input)
|
||||
{
|
||||
float4 positionVS = mul(modelViewMatrix, float4(input.position.xyz, 1));
|
||||
|
||||
VOut output;
|
||||
output.position = mul(projectionMatrix, positionVS);
|
||||
output.normal = input.normal;
|
||||
output.texCoords = input.texCoords;
|
||||
output.color = input.color;
|
||||
output.clipDist = dot(positionVS, clipPlane);
|
||||
output.proj2232 = float2(-projectionMatrix[2][2], projectionMatrix[2][3]);
|
||||
output.depthVS = -positionVS.z;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
[earlydepthstencil]
|
||||
void ps(VOut input)
|
||||
{
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
SamplerState sampler0 = SamplerDescriptorHeap[samplerIndex];
|
||||
float4 dst = texture0.Sample(sampler0, input.texCoords) * input.color;
|
||||
if(FailsAlphaTest(dst.a, alphaTest))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dst = MakeGreyscale(dst, greyscale);
|
||||
|
||||
RWStructuredBuffer<OIT_Counter> counter = ResourceDescriptorHeap[counterBuffer];
|
||||
uint fragmentIndex;
|
||||
InterlockedAdd(counter[0].fragmentCount, 1, fragmentIndex);
|
||||
if(fragmentIndex < counter[0].maxFragmentCount)
|
||||
{
|
||||
RWTexture2D<uint> indexTex = ResourceDescriptorHeap[indexTexture];
|
||||
RWStructuredBuffer<OIT_Fragment> fragments = ResourceDescriptorHeap[fragmentBuffer];
|
||||
uint prevFragmentIndex;
|
||||
InterlockedExchange(indexTex[int2(input.position.xy)], fragmentIndex, prevFragmentIndex);
|
||||
OIT_Fragment fragment;
|
||||
fragment.color = PackColor(dst);
|
||||
fragment.depth = input.depthVS;
|
||||
fragment.stateBits = stateBits;
|
||||
fragment.next = prevFragmentIndex;
|
||||
fragment.shaderTrace = shaderTrace;
|
||||
fragment.depthFadeDistOffset = depthFadeDistOffset;
|
||||
fragment.depthFadeScaleBias = depthFadeScaleBias;
|
||||
fragments[fragmentIndex] = fragment;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint garbage;
|
||||
InterlockedAdd(counter[0].overflowCount, 1, garbage);
|
||||
InterlockedAdd(counter[0].fragmentCount, -1, garbage);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
216
code/renderer/shaders/crp/transp_resolve.hlsl
Normal file
216
code/renderer/shaders/crp/transp_resolve.hlsl
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// reads per-pixel fragment linked lists into arrays, sorts them and composites them
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "oit.h.hlsli"
|
||||
#include "../common/state_bits.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint renderTargetTexture;
|
||||
uint shaderIndexBuffer;
|
||||
uint indexTexture;
|
||||
uint fragmentBuffer;
|
||||
uint centerPixel; // y: 16 - x: 16
|
||||
uint depthTexture;
|
||||
float proj22;
|
||||
float proj32;
|
||||
float2 scissorRectMin;
|
||||
float2 scissorRectMax;
|
||||
};
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
VOut vs(uint id : SV_VertexID)
|
||||
{
|
||||
VOut output;
|
||||
output.position = FSTrianglePosFromVertexId(id);
|
||||
output.texCoords = FSTriangleTCFromVertexId(id);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
uint GetShaderStage(uint stateBits)
|
||||
{
|
||||
return (stateBits & GLS_STAGEINDEX_BITS) >> GLS_STAGEINDEX_SHIFT;
|
||||
}
|
||||
|
||||
bool IsBehind(float depthA, float depthB, uint stageA, uint stageB)
|
||||
{
|
||||
if(depthA > depthB)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(depthA == depthB && stageA < stageB)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// from NVIDIA's 2007 "Soft Particles" whitepaper by Tristan Lorach
|
||||
float Contrast(float d, float power)
|
||||
{
|
||||
bool aboveHalf = d > 0.5;
|
||||
float base = saturate(2.0 * (aboveHalf ? (1.0 - d) : d));
|
||||
float r = 0.5 * pow(base, power);
|
||||
|
||||
return aboveHalf ? (1.0 - r) : r;
|
||||
}
|
||||
|
||||
float GetBitAsFloat(uint bits, uint bitIndex)
|
||||
{
|
||||
return (bits & (1u << bitIndex)) ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
float2 UnpackHalf2(uint data)
|
||||
{
|
||||
return float2(f16tof32(data), f16tof32(data >> 16));
|
||||
}
|
||||
|
||||
float4 DepthFadeFragmentColor(float4 color, OIT_Fragment fragment, float storedDepthZW)
|
||||
{
|
||||
if(((fragment.depthFadeScaleBias >> 8) & 1) == 0)
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
#define BIT(Index) GetBitAsFloat(fragment.depthFadeScaleBias, Index)
|
||||
float4 dst = color;
|
||||
float2 distOffset = UnpackHalf2(fragment.depthFadeDistOffset);
|
||||
float4 fadeColorScale = float4(BIT(0), BIT(1), BIT(2), BIT(3));
|
||||
float4 fadeColorBias = float4(BIT(4), BIT(5), BIT(6), BIT(7));
|
||||
float zwDepth = storedDepthZW; // stored depth, z/w
|
||||
float depthS = LinearDepth(zwDepth, proj22, proj32); // stored depth, linear
|
||||
float depthP = fragment.depth - distOffset.y; // fragment depth, linear
|
||||
float fadeScale = Contrast((depthS - depthP) * distOffset.x, 2.0);
|
||||
dst = lerp(dst * fadeColorScale + fadeColorBias, dst, fadeScale);
|
||||
#undef BIT
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D renderTarget = ResourceDescriptorHeap[renderTargetTexture];
|
||||
int2 tc = int2(input.position.x, input.position.y);
|
||||
float4 color = renderTarget.Load(int3(tc.x, tc.y, 0));
|
||||
if(any(input.position.xy < scissorRectMin) ||
|
||||
any(input.position.xy > scissorRectMax))
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
RWTexture2D<uint> index = ResourceDescriptorHeap[indexTexture];
|
||||
RWStructuredBuffer<OIT_Fragment> fragments = ResourceDescriptorHeap[fragmentBuffer];
|
||||
Texture2D depthTex = ResourceDescriptorHeap[depthTexture];
|
||||
uint fragmentIndex = index[tc];
|
||||
uint i;
|
||||
OIT_Fragment sorted[OIT_MAX_FRAGMENTS_PER_PIXEL];
|
||||
uint fragmentCount = 0;
|
||||
|
||||
// grab this pixel's fragments
|
||||
while(fragmentIndex != 0 && fragmentCount < OIT_MAX_FRAGMENTS_PER_PIXEL)
|
||||
{
|
||||
sorted[fragmentCount] = fragments[fragmentIndex];
|
||||
fragmentIndex = sorted[fragmentCount].next;
|
||||
++fragmentCount;
|
||||
}
|
||||
|
||||
// sort the fragments using an insertion sort
|
||||
for(i = 1; i < fragmentCount; ++i)
|
||||
{
|
||||
OIT_Fragment insert = sorted[i];
|
||||
uint stage = GetShaderStage(insert.stateBits);
|
||||
uint j = i;
|
||||
while(j > 0 && IsBehind(insert.depth, sorted[j - 1].depth, stage, GetShaderStage(sorted[j - 1].stateBits)))
|
||||
{
|
||||
sorted[j] = sorted[j - 1];
|
||||
--j;
|
||||
}
|
||||
sorted[j] = insert;
|
||||
}
|
||||
|
||||
// blend the results
|
||||
float storedDepthZW = depthTex.Load(int3(input.position.xy, 0)).x; // stored depth, z/w
|
||||
float dstDepth = 1.0;
|
||||
for(i = 0; i < fragmentCount; ++i)
|
||||
{
|
||||
OIT_Fragment frag = sorted[i];
|
||||
uint stateBits = frag.stateBits;
|
||||
float fragDepth = frag.depth;
|
||||
if((stateBits & (GLS_DEPTHFUNC_EQUAL | GLS_DEPTHTEST_DISABLE)) == GLS_DEPTHFUNC_EQUAL &&
|
||||
fragDepth != dstDepth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float4 fragColor = UnpackColor(frag.color);
|
||||
fragColor = DepthFadeFragmentColor(fragColor, frag, storedDepthZW);
|
||||
color = Blend(fragColor, color, frag.stateBits);
|
||||
if((stateBits & GLS_DEPTHMASK_TRUE) != 0u &&
|
||||
fragDepth < dstDepth)
|
||||
{
|
||||
dstDepth = fragDepth;
|
||||
}
|
||||
}
|
||||
|
||||
// write out the fragment shader ID of the closest fragment of the center pixel
|
||||
if(fragmentCount > 0)
|
||||
{
|
||||
uint lastFragmentIndex = fragmentCount - 1;
|
||||
OIT_Fragment closest = sorted[lastFragmentIndex];
|
||||
uint shaderTrace = closest.shaderTrace;
|
||||
if(shaderTrace & 1)
|
||||
{
|
||||
uint2 fragmentCoords = uint2(input.position.xy);
|
||||
uint2 centerCoords = uint2(centerPixel & 0xFFFF, centerPixel >> 16);
|
||||
if(all(fragmentCoords == centerCoords))
|
||||
{
|
||||
RWByteAddressBuffer shaderIdBuf = ResourceDescriptorHeap[shaderIndexBuffer];
|
||||
uint frameIndex = (shaderTrace >> 1) & 3;
|
||||
uint shaderId = shaderTrace >> 3;
|
||||
shaderIdBuf.Store(frameIndex * 4, shaderId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
#endif
|
73
code/renderer/shaders/crp/ui.hlsl
Normal file
73
code/renderer/shaders/crp/ui.hlsl
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// UI rendering
|
||||
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
};
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
float2 scale;
|
||||
uint textureIndex;
|
||||
uint samplerIndex;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
struct VIn
|
||||
{
|
||||
float2 position : POSITION;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
};
|
||||
|
||||
VOut vs(VIn input)
|
||||
{
|
||||
const float2 position = input.position * scale;
|
||||
VOut output;
|
||||
output.position = float4(position.x - 1.0, 1.0 - position.y, 0.0, 1.0);
|
||||
output.texCoords = input.texCoords;
|
||||
output.color = input.color;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
SamplerState sampler0 = SamplerDescriptorHeap[samplerIndex];
|
||||
float4 result = input.color * texture0.Sample(sampler0, input.texCoords);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
30
code/renderer/shaders/crp/world.h.hlsli
Normal file
30
code/renderer/shaders/crp/world.h.hlsli
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// shared world rendering constants
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#define ATEST_NONE 0
|
||||
#define ATEST_GT_0 1
|
||||
#define ATEST_LT_HALF 2
|
||||
#define ATEST_GE_HALF 3
|
37
code/renderer/shaders/crp/world.hlsli
Normal file
37
code/renderer/shaders/crp/world.hlsli
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// shared world surface rendering functions
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
bool FailsAlphaTest(float alpha, uint alphaTest)
|
||||
{
|
||||
if(alphaTest == ATEST_GT_0)
|
||||
return alpha == 0.0;
|
||||
else if(alphaTest == ATEST_LT_HALF)
|
||||
return alpha >= 0.5;
|
||||
else if(alphaTest == ATEST_GE_HALF)
|
||||
return alpha < 0.5;
|
||||
else // ATEST_NONE
|
||||
return false;
|
||||
}
|
|
@ -21,6 +21,9 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
// mip-map generation: gamma-space to linear-space transform
|
||||
|
||||
|
||||
#include "../common/mip_gen.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float gamma;
|
||||
|
@ -32,14 +35,5 @@ RWTexture2D<float4> dst : register(u0);
|
|||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
// @TODO: is this actually required?
|
||||
uint w, h;
|
||||
dst.GetDimensions(w, h);
|
||||
if(any(id.xy >= uint2(w, h)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float4 v = src[id.xy];
|
||||
dst[id.xy] = float4(pow(v.xyz, gamma), v.a);
|
||||
MipGen_GammaToLinear(dst, src, id, gamma);
|
||||
}
|
|
@ -21,6 +21,9 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
// mip-map generation: 8-tap 1D filter
|
||||
|
||||
|
||||
#include "../common/mip_gen.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float4 weights;
|
||||
|
@ -34,41 +37,10 @@ cbuffer RootConstants
|
|||
|
||||
RWTexture2D<float4> mips[2] : register(u0);
|
||||
|
||||
uint2 FixCoords(int2 c)
|
||||
{
|
||||
if(clampMode > 0)
|
||||
{
|
||||
// clamp
|
||||
return uint2(clamp(c, int2(0, 0), maxSize));
|
||||
}
|
||||
|
||||
// repeat
|
||||
return uint2(c & maxSize);
|
||||
}
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture2D<float4> src = mips[srcMip];
|
||||
RWTexture2D<float4> dst = mips[dstMip];
|
||||
|
||||
// @TODO: is this actually required?
|
||||
uint w, h;
|
||||
dst.GetDimensions(w, h);
|
||||
if(any(id.xy >= uint2(w, h)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int2 base = int2(id.xy) * scale;
|
||||
float4 r = float4(0, 0, 0, 0);
|
||||
r += src[FixCoords(base - offset * 3)] * weights.x;
|
||||
r += src[FixCoords(base - offset * 2)] * weights.y;
|
||||
r += src[FixCoords(base - offset * 1)] * weights.z;
|
||||
r += src[base] * weights.w;
|
||||
r += src[base + offset] * weights.w;
|
||||
r += src[FixCoords(base + offset * 2)] * weights.z;
|
||||
r += src[FixCoords(base + offset * 3)] * weights.y;
|
||||
r += src[FixCoords(base + offset * 4)] * weights.x;
|
||||
dst[id.xy] = r;
|
||||
MipGen_DownSample(dst, src, id, maxSize, clampMode, scale, offset, weights);
|
||||
}
|
|
@ -21,6 +21,9 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
// mip-map generation: linear-space to gamma-space transform
|
||||
|
||||
|
||||
#include "../common/mip_gen.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float4 blendColor;
|
||||
|
@ -37,22 +40,5 @@ void cs(uint3 id : SV_DispatchThreadID)
|
|||
{
|
||||
RWTexture2D<float4> src = mips[srcMip];
|
||||
RWTexture2D<float4> dst = mips[dstMip];
|
||||
|
||||
// @TODO: is this actually required?
|
||||
uint w, h;
|
||||
dst.GetDimensions(w, h);
|
||||
if(any(id.xy >= uint2(w, h)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// yes, intensity *should* be done in light-linear space
|
||||
// but we keep the old behavior for consistency...
|
||||
float4 in0 = src[id.xy];
|
||||
float3 in1 = 0.5 * (in0.rgb + blendColor.rgb);
|
||||
float3 inV = lerp(in0.rgb, in1.rgb, blendColor.a);
|
||||
float3 out0 = pow(max(inV, 0.0), invGamma);
|
||||
float3 out1 = out0 * intensity;
|
||||
float4 outV = saturate(float4(out1, in0.a));
|
||||
dst[id.xy] = outV;
|
||||
MipGen_LinearToGamma(dst, src, id, blendColor, intensity, invGamma);
|
||||
}
|
|
@ -65,7 +65,7 @@ float4 ps(VOut input) : SV_Target
|
|||
float3 base = texture0.Sample(sampler0, input.texCoords).rgb;
|
||||
float3 linearSpace = pow(base * invBrightness, gamma);
|
||||
|
||||
return float4(linearSpace, 1.0f);
|
||||
return float4(linearSpace, 1.0);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -21,6 +21,11 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
// helper functions used by multiple shader files
|
||||
|
||||
|
||||
#if !defined(DISABLE_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
float4 MakeGreyscale(float4 input, float amount)
|
||||
{
|
||||
float grey = dot(input.rgb, float3(0.299, 0.587, 0.114));
|
|
@ -165,6 +165,8 @@ VOut vs(VIn input)
|
|||
|
||||
#if USE_INCLUDES
|
||||
#include "shared.hlsli"
|
||||
#include "../common/state_bits.h.hlsli"
|
||||
#include "../common/blend.hlsli"
|
||||
#endif
|
||||
|
||||
cbuffer RootConstants
|
||||
|
@ -191,86 +193,6 @@ Texture2D textures2D[4096] : register(t0);
|
|||
SamplerState samplers[96] : register(s0);
|
||||
RWByteAddressBuffer shaderIndexBuffer : register(u0);
|
||||
|
||||
#define GLS_SRCBLEND_ZERO 0x00000001
|
||||
#define GLS_SRCBLEND_ONE 0x00000002
|
||||
#define GLS_SRCBLEND_DST_COLOR 0x00000003
|
||||
#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004
|
||||
#define GLS_SRCBLEND_SRC_ALPHA 0x00000005
|
||||
#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006
|
||||
#define GLS_SRCBLEND_DST_ALPHA 0x00000007
|
||||
#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008
|
||||
#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009
|
||||
#define GLS_SRCBLEND_BITS 0x0000000f
|
||||
|
||||
#define GLS_DSTBLEND_ZERO 0x00000010
|
||||
#define GLS_DSTBLEND_ONE 0x00000020
|
||||
#define GLS_DSTBLEND_SRC_COLOR 0x00000030
|
||||
#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040
|
||||
#define GLS_DSTBLEND_SRC_ALPHA 0x00000050
|
||||
#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060
|
||||
#define GLS_DSTBLEND_DST_ALPHA 0x00000070
|
||||
#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080
|
||||
#define GLS_DSTBLEND_BITS 0x000000f0
|
||||
|
||||
#define GLS_ATEST_GT_0 0x10000000
|
||||
#define GLS_ATEST_LT_80 0x20000000
|
||||
#define GLS_ATEST_GE_80 0x40000000
|
||||
#define GLS_ATEST_BITS 0x70000000
|
||||
|
||||
float4 BlendSource(float4 src, float4 dst, uint stateBits)
|
||||
{
|
||||
if(stateBits == GLS_SRCBLEND_ZERO)
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
else if(stateBits == GLS_SRCBLEND_ONE)
|
||||
return src;
|
||||
else if(stateBits == GLS_SRCBLEND_DST_COLOR)
|
||||
return src * dst;
|
||||
else if(stateBits == GLS_SRCBLEND_ONE_MINUS_DST_COLOR)
|
||||
return src * (float4(1.0, 1.0, 1.0, 1.0) - dst);
|
||||
else if(stateBits == GLS_SRCBLEND_SRC_ALPHA)
|
||||
return src * float4(src.a, src.a, src.a, 1.0);
|
||||
else if(stateBits == GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA)
|
||||
return src * float4(1.0 - src.a, 1.0 - src.a, 1.0 - src.a, 1.0);
|
||||
else if(stateBits == GLS_SRCBLEND_DST_ALPHA)
|
||||
return src * float4(dst.a, dst.a, dst.a, 1.0);
|
||||
else if(stateBits == GLS_SRCBLEND_ONE_MINUS_DST_ALPHA)
|
||||
return src * float4(1.0 - dst.a, 1.0 - dst.a, 1.0 - dst.a, 1.0);
|
||||
else if(stateBits == GLS_SRCBLEND_ALPHA_SATURATE)
|
||||
return src * float4(src.a, src.a, src.a, 1.0); // ?????????
|
||||
else
|
||||
return src;
|
||||
}
|
||||
|
||||
float4 BlendDest(float4 src, float4 dst, uint stateBits)
|
||||
{
|
||||
if(stateBits == GLS_DSTBLEND_ZERO)
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
else if(stateBits == GLS_DSTBLEND_ONE)
|
||||
return dst;
|
||||
else if(stateBits == GLS_DSTBLEND_SRC_COLOR)
|
||||
return dst * src;
|
||||
else if(stateBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR)
|
||||
return dst * float4(1.0 - src.r, 1.0 - src.g, 1.0 - src.b, 1.0 - src.a);
|
||||
else if(stateBits == GLS_DSTBLEND_SRC_ALPHA)
|
||||
return dst * float4(src.a, src.a, src.a, 1.0);
|
||||
else if(stateBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA)
|
||||
return dst * float4(1.0 - src.a, 1.0 - src.a, 1.0 - src.a, 0.0);
|
||||
else if(stateBits == GLS_DSTBLEND_DST_ALPHA)
|
||||
return dst * float4(dst.a, dst.a, dst.a, 1.0);
|
||||
else if(stateBits == GLS_DSTBLEND_ONE_MINUS_DST_ALPHA)
|
||||
return dst * float4(1.0 - dst.a, 1.0 - dst.a, 1.0 - dst.a, 1.0);
|
||||
else
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
float4 Blend(float4 src, float4 dst, uint stateBits)
|
||||
{
|
||||
float4 srcOut = BlendSource(src, dst, stateBits & GLS_SRCBLEND_BITS);
|
||||
float4 dstOut = BlendDest(src, dst, stateBits & GLS_DSTBLEND_BITS);
|
||||
|
||||
return srcOut + dstOut;
|
||||
}
|
||||
|
||||
bool FailsAlphaTest(float alpha, uint stateBits)
|
||||
{
|
||||
if(stateBits == GLS_ATEST_GT_0)
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2022-2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2022-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -18,13 +18,11 @@ You should have received a copy of the GNU General Public License
|
|||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Gameplay Rendering Pipeline - Dear ImGUI integration
|
||||
// Shared Rendering Pipeline - Dear ImGUI integration
|
||||
|
||||
|
||||
#include "grp_local.h"
|
||||
#include "srp_local.h"
|
||||
#include "../imgui/imgui.h"
|
||||
#include "hlsl/imgui_vs.h"
|
||||
#include "hlsl/imgui_ps.h"
|
||||
|
||||
|
||||
#define MAX_VERTEX_COUNT (64 << 10)
|
||||
|
@ -46,13 +44,16 @@ struct PixelRC
|
|||
#pragma pack(pop)
|
||||
|
||||
|
||||
void ImGUI::Init()
|
||||
HTexture ImGUI::Init(bool ddhi_, const ShaderByteCode& vs, const ShaderByteCode& ps, TextureFormat::Id rtFormat, HDescriptorTable descTable, RootSignatureDesc* rootSigDesc)
|
||||
{
|
||||
ddhi = ddhi_;
|
||||
descriptorTable = descTable;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize.x = glConfig.vidWidth;
|
||||
io.DisplaySize.y = glConfig.vidHeight;
|
||||
|
||||
if(grp.firstInit)
|
||||
if(srp.firstInit)
|
||||
{
|
||||
io.BackendRendererUserData = this;
|
||||
io.BackendRendererName = "CNQ3 Direct3D 12";
|
||||
|
@ -71,8 +72,13 @@ void ImGUI::Init()
|
|||
fr->vertexBuffer = CreateBuffer(idx);
|
||||
}
|
||||
|
||||
if(ddhi)
|
||||
{
|
||||
RootSignatureDesc desc = grp.rootSignatureDesc;
|
||||
rootSignature = RHI_MAKE_NULL_HANDLE();
|
||||
}
|
||||
else
|
||||
{
|
||||
RootSignatureDesc desc = *rootSigDesc;
|
||||
desc.name = "Dear ImGUI";
|
||||
desc.constants[ShaderStage::Vertex].byteCount = sizeof(VertexRC);
|
||||
desc.constants[ShaderStage::Pixel].byteCount = sizeof(PixelRC);
|
||||
|
@ -100,8 +106,8 @@ void ImGUI::Init()
|
|||
{
|
||||
GraphicsPipelineDesc desc("Dear ImGUI", rootSignature);
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(g_vs);
|
||||
desc.pixelShader = ShaderByteCode(g_ps);
|
||||
desc.vertexShader = vs;
|
||||
desc.pixelShader = ps;
|
||||
desc.vertexLayout.bindingStrides[0] = sizeof(ImDrawVert);
|
||||
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position,
|
||||
DataType::Float32, 2, offsetof(ImDrawVert, pos));
|
||||
|
@ -114,36 +120,39 @@ void ImGUI::Init()
|
|||
desc.depthStencil.enableDepthTest = false;
|
||||
desc.depthStencil.enableDepthWrites = false;
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, grp.renderTargetFormat);
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, rtFormat);
|
||||
pipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
RegisterFontAtlas();
|
||||
if(ddhi)
|
||||
{
|
||||
const uint32_t fontIndex = GetTextureIndexSRV(fontAtlas);
|
||||
io.Fonts->SetTexID((ImTextureID)fontIndex);
|
||||
}
|
||||
|
||||
return fontAtlas;
|
||||
}
|
||||
|
||||
void ImGUI::RegisterFontAtlas()
|
||||
void ImGUI::RegisterFontAtlas(uint32_t fontIndex)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
const uint32_t fontIndex = grp.RegisterTexture(fontAtlas);
|
||||
io.Fonts->SetTexID((ImTextureID)fontIndex);
|
||||
ImGui::GetIO().Fonts->SetTexID((ImTextureID)fontIndex);
|
||||
}
|
||||
|
||||
void ImGUI::Draw()
|
||||
void ImGUI::Draw(HTexture renderTarget)
|
||||
{
|
||||
if(r_debugUI->integer == 0)
|
||||
{
|
||||
SafeEndFrame();
|
||||
EndFrame();
|
||||
return;
|
||||
}
|
||||
|
||||
grp.renderMode = RenderMode::ImGui;
|
||||
srp.renderMode = RenderMode::ImGui;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize.x = glConfig.vidWidth;
|
||||
io.DisplaySize.y = glConfig.vidHeight;
|
||||
|
||||
SafeEndFrame();
|
||||
EndFrame();
|
||||
ImGui::Render();
|
||||
|
||||
const ImDrawData* drawData = ImGui::GetDrawData();
|
||||
|
@ -151,7 +160,7 @@ void ImGUI::Draw()
|
|||
// avoid rendering when minimized
|
||||
if(drawData->DisplaySize.x <= 0.0f || drawData->DisplaySize.y <= 0.0f)
|
||||
{
|
||||
grp.renderMode = RenderMode::None;
|
||||
srp.renderMode = RenderMode::None;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -201,14 +210,27 @@ void ImGUI::Draw()
|
|||
const uint32_t vertexStride = sizeof(ImDrawVert);
|
||||
static_assert(sizeof(ImDrawIdx) == 4, "uint32 indices expected!");
|
||||
|
||||
CmdBindRenderTargets(1, &grp.renderTarget, NULL);
|
||||
CmdBindRootSignature(rootSignature);
|
||||
CmdBindRenderTargets(1, &renderTarget, NULL);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindRootSignature(rootSignature);
|
||||
}
|
||||
CmdBindPipeline(pipeline);
|
||||
CmdBindDescriptorTable(rootSignature, grp.descriptorTable);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindDescriptorTable(rootSignature, descriptorTable);
|
||||
}
|
||||
CmdBindVertexBuffers(1, &fr->vertexBuffer, &vertexStride, NULL);
|
||||
CmdBindIndexBuffer(fr->indexBuffer, IndexType::UInt32, 0);
|
||||
CmdSetViewport(0, 0, drawData->DisplaySize.x, drawData->DisplaySize.y);
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Vertex, &vertexRC);
|
||||
if(ddhi)
|
||||
{
|
||||
CmdSetGraphicsRootConstants(0, sizeof(vertexRC), &vertexRC);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Vertex, &vertexRC);
|
||||
}
|
||||
|
||||
// Render command lists
|
||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||
|
@ -234,7 +256,14 @@ void ImGUI::Draw()
|
|||
pixelRC.texture = (uint32_t)cmd->TextureId & 0xFFFF;
|
||||
pixelRC.sampler = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Linear);
|
||||
pixelRC.mip = (float)(((uint32_t)cmd->TextureId >> 16) & 0xFFFF);
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Pixel, &pixelRC);
|
||||
if(ddhi)
|
||||
{
|
||||
CmdSetGraphicsRootConstants(sizeof(vertexRC), sizeof(pixelRC), &pixelRC);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Pixel, &pixelRC);
|
||||
}
|
||||
|
||||
// Apply Scissor/clipping rectangle, Draw
|
||||
CmdSetScissor(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y);
|
||||
|
@ -245,10 +274,10 @@ void ImGUI::Draw()
|
|||
globalVtxOffset += cmdList->VtxBuffer.Size;
|
||||
}
|
||||
|
||||
grp.renderMode = RenderMode::None;
|
||||
srp.renderMode = RenderMode::None;
|
||||
}
|
||||
|
||||
void ImGUI::SafeBeginFrame()
|
||||
void ImGUI::BeginFrame()
|
||||
{
|
||||
if(!frameStarted)
|
||||
{
|
||||
|
@ -257,7 +286,7 @@ void ImGUI::SafeBeginFrame()
|
|||
}
|
||||
}
|
||||
|
||||
void ImGUI::SafeEndFrame()
|
||||
void ImGUI::EndFrame()
|
||||
{
|
||||
if(frameStarted)
|
||||
{
|
435
code/renderer/srp_local.h
Normal file
435
code/renderer/srp_local.h
Normal file
|
@ -0,0 +1,435 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Shared Rendering Pipeline - private declarations
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "tr_local.h"
|
||||
#include "rhi_local.h"
|
||||
|
||||
|
||||
using namespace RHI;
|
||||
|
||||
|
||||
struct BufferBase
|
||||
{
|
||||
bool CanAdd(uint32_t count_)
|
||||
{
|
||||
return batchFirst + batchCount + count_ <= totalCount;
|
||||
}
|
||||
|
||||
void EndBatch()
|
||||
{
|
||||
batchFirst += batchCount;
|
||||
batchCount = 0;
|
||||
}
|
||||
|
||||
void EndBatch(uint32_t size)
|
||||
{
|
||||
batchFirst += size;
|
||||
batchCount = 0;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
batchFirst = 0;
|
||||
batchCount = 0;
|
||||
}
|
||||
|
||||
uint32_t totalCount = 0;
|
||||
uint32_t batchFirst = 0;
|
||||
uint32_t batchCount = 0;
|
||||
};
|
||||
|
||||
struct IndexBuffer : BufferBase
|
||||
{
|
||||
void Create(const char* name, MemoryUsage::Id memoryUsage, uint32_t indexCount)
|
||||
{
|
||||
totalCount = indexCount;
|
||||
|
||||
BufferDesc desc = {};
|
||||
desc.committedResource = true;
|
||||
desc.initialState = ResourceStates::IndexBufferBit;
|
||||
desc.memoryUsage = memoryUsage;
|
||||
desc.name = va("%s index", name);
|
||||
desc.byteCount = indexCount * sizeof(uint32_t);
|
||||
buffer = CreateBuffer(desc);
|
||||
}
|
||||
|
||||
void BeginUpload()
|
||||
{
|
||||
mapped = (uint32_t*)BeginBufferUpload(buffer);
|
||||
}
|
||||
|
||||
void EndUpload()
|
||||
{
|
||||
EndBufferUpload(buffer);
|
||||
mapped = NULL;
|
||||
}
|
||||
|
||||
void Upload()
|
||||
{
|
||||
Q_assert(mapped != NULL);
|
||||
|
||||
uint32_t* const idx = mapped + batchFirst + batchCount;
|
||||
memcpy(idx, &tess.indexes[0], tess.numIndexes * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
uint32_t* GetCurrentAddress()
|
||||
{
|
||||
return mapped + batchFirst + batchCount;
|
||||
}
|
||||
|
||||
HBuffer buffer = RHI_MAKE_NULL_HANDLE();
|
||||
uint32_t* mapped = NULL;
|
||||
};
|
||||
|
||||
struct GeometryBuffer : BufferBase
|
||||
{
|
||||
void Init(uint32_t count_, uint32_t stride_)
|
||||
{
|
||||
buffer = RHI_MAKE_NULL_HANDLE();
|
||||
byteCount = count_ * stride_;
|
||||
stride = stride_;
|
||||
totalCount = count_;
|
||||
batchFirst = 0;
|
||||
batchCount = 0;
|
||||
}
|
||||
|
||||
void CreateVertexBuffer(const char* name, MemoryUsage::Id memoryUsage, uint32_t count, uint32_t stride_)
|
||||
{
|
||||
BufferDesc desc = {};
|
||||
desc.committedResource = true;
|
||||
desc.initialState = ResourceStates::VertexBufferBit;
|
||||
desc.memoryUsage = memoryUsage;
|
||||
desc.name = name;
|
||||
desc.byteCount = count * stride_;
|
||||
buffer = CreateBuffer(desc);
|
||||
byteCount = count * stride_;
|
||||
stride = stride_;
|
||||
totalCount = count;
|
||||
batchFirst = 0;
|
||||
batchCount = 0;
|
||||
}
|
||||
|
||||
void BeginUpload()
|
||||
{
|
||||
Q_assert(mapped == NULL);
|
||||
mapped = BeginBufferUpload(buffer);
|
||||
}
|
||||
|
||||
void EndUpload()
|
||||
{
|
||||
Q_assert(mapped != NULL);
|
||||
EndBufferUpload(buffer);
|
||||
mapped = NULL;
|
||||
}
|
||||
|
||||
HBuffer buffer = RHI_MAKE_NULL_HANDLE();
|
||||
uint32_t byteCount = 0;
|
||||
uint32_t stride = 0;
|
||||
uint8_t* mapped = NULL;
|
||||
};
|
||||
|
||||
struct RenderMode
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
None,
|
||||
UI,
|
||||
World,
|
||||
ImGui,
|
||||
Nuklear,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
struct RenderPassQueries
|
||||
{
|
||||
char name[64];
|
||||
uint32_t gpuDurationUS;
|
||||
uint32_t cpuDurationUS;
|
||||
int64_t cpuStartUS;
|
||||
uint32_t queryIndex;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MaxRenderPasses = 64, // cg_draw3dIcons forces tons of 2D/3D transitions...
|
||||
MaxStatsFrameCount = 64
|
||||
};
|
||||
|
||||
struct RenderPassStats
|
||||
{
|
||||
void EndFrame(uint32_t cpu, uint32_t gpu);
|
||||
|
||||
uint32_t samplesCPU[MaxStatsFrameCount];
|
||||
uint32_t samplesGPU[MaxStatsFrameCount];
|
||||
stats_t statsCPU;
|
||||
stats_t statsGPU;
|
||||
uint32_t count;
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
struct RenderPassFrame
|
||||
{
|
||||
RenderPassQueries passes[MaxRenderPasses];
|
||||
uint32_t count;
|
||||
};
|
||||
|
||||
struct FrameStats
|
||||
{
|
||||
enum { MaxFrames = 1024 };
|
||||
|
||||
void EndFrame();
|
||||
|
||||
float temp[MaxFrames];
|
||||
float p2pMS[MaxFrames];
|
||||
stats_t p2pStats;
|
||||
int frameCount;
|
||||
int frameIndex;
|
||||
int skippedFrames;
|
||||
};
|
||||
|
||||
struct MipMapGenerator
|
||||
{
|
||||
void Init(bool ddhi, const ShaderByteCode& g2l, const ShaderByteCode& down, const ShaderByteCode& l2g);
|
||||
void GenerateMipMaps(HTexture texture);
|
||||
|
||||
private:
|
||||
struct Stage
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
Start, // gamma to linear
|
||||
DownSample, // down sample on 1 axis
|
||||
End, // linear to gamma
|
||||
Count
|
||||
};
|
||||
|
||||
HRootSignature rootSignature;
|
||||
HDescriptorTable descriptorTable;
|
||||
HPipeline pipeline;
|
||||
};
|
||||
|
||||
struct MipSlice
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
Float16_0,
|
||||
Float16_1,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
HTexture textures[MipSlice::Count];
|
||||
Stage stages[3];
|
||||
bool ddhi = false;
|
||||
};
|
||||
|
||||
struct UI
|
||||
{
|
||||
void Init(bool ddhi_, const ShaderByteCode& vs, const ShaderByteCode& ps, TextureFormat::Id rtFormat,
|
||||
HDescriptorTable descTable, RootSignatureDesc* rootSigDesc);
|
||||
void BeginFrame();
|
||||
void Begin(HTexture renderTarget);
|
||||
void End();
|
||||
void CmdSetColor(const uiSetColorCommand_t& cmd);
|
||||
void CmdDrawQuad(const uiDrawQuadCommand_t& cmd);
|
||||
void CmdDrawTriangle(const uiDrawTriangleCommand_t& cmd);
|
||||
|
||||
private:
|
||||
void DrawBatch();
|
||||
|
||||
// 32-bit needed until the render logic is fixed!
|
||||
typedef uint32_t Index;
|
||||
const IndexType::Id indexType = IndexType::UInt32;
|
||||
|
||||
uint32_t renderPassIndex;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Vertex
|
||||
{
|
||||
vec2_t position;
|
||||
vec2_t texCoords;
|
||||
uint32_t color;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
int maxIndexCount;
|
||||
int maxVertexCount;
|
||||
int firstIndex;
|
||||
int firstVertex;
|
||||
int indexCount;
|
||||
int vertexCount;
|
||||
HRootSignature rootSignature;
|
||||
HDescriptorTable descriptorTable;
|
||||
HPipeline pipeline;
|
||||
HBuffer indexBuffer;
|
||||
HBuffer vertexBuffer;
|
||||
Index* indices;
|
||||
Vertex* vertices;
|
||||
uint32_t color;
|
||||
const shader_t* shader;
|
||||
bool ddhi; // direct descriptor heap indexing
|
||||
};
|
||||
|
||||
struct ImGUI
|
||||
{
|
||||
HTexture Init(bool ddhi, const ShaderByteCode& vs, const ShaderByteCode& ps, TextureFormat::Id rtFormat, HDescriptorTable descTable, RootSignatureDesc* rootSigDesc);
|
||||
void RegisterFontAtlas(uint32_t fontIndex);
|
||||
void Draw(HTexture renderTarget);
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
|
||||
private:
|
||||
struct FrameResources
|
||||
{
|
||||
HBuffer indexBuffer;
|
||||
HBuffer vertexBuffer;
|
||||
};
|
||||
|
||||
HRootSignature rootSignature;
|
||||
HDescriptorTable descriptorTable;
|
||||
HPipeline pipeline;
|
||||
HTexture fontAtlas;
|
||||
FrameResources frameResources[FrameCount];
|
||||
bool frameStarted = false;
|
||||
bool ddhi = false;
|
||||
};
|
||||
|
||||
struct Nuklear
|
||||
{
|
||||
void Init(bool ddhi, const ShaderByteCode& vs, const ShaderByteCode& ps, TextureFormat::Id rtFormat, HDescriptorTable descTable, RootSignatureDesc* rootSigDesc);
|
||||
void BeginFrame();
|
||||
void Begin(HTexture renderTarget);
|
||||
void End();
|
||||
void Upload(const nuklearUploadCommand_t& cmd);
|
||||
void Draw(const nuklearDrawCommand_t& cmd);
|
||||
|
||||
private:
|
||||
struct FrameResources
|
||||
{
|
||||
HBuffer indexBuffer;
|
||||
HBuffer vertexBuffer;
|
||||
};
|
||||
|
||||
HRootSignature rootSignature;
|
||||
HDescriptorTable descriptorTable;
|
||||
HPipeline pipeline;
|
||||
FrameResources frameResources[FrameCount];
|
||||
uint32_t renderPassIndex;
|
||||
int prevScissorRect[4];
|
||||
|
||||
// reset every frame
|
||||
int firstVertex;
|
||||
int firstIndex;
|
||||
int numVertexes; // set in Upload
|
||||
int numIndexes; // set in Upload
|
||||
bool ddhi = false;
|
||||
};
|
||||
|
||||
struct SRP
|
||||
{
|
||||
uint32_t BeginRenderPass(const char* name, float r, float g, float b);
|
||||
void EndRenderPass(uint32_t index);
|
||||
|
||||
// @NOTE: SRP::BeginFrame doesn't call RHI::BeginFrame
|
||||
// @NOTE: SRP::EndFrame calls RHI::EndFrame and Sys_V_EndFrame
|
||||
void BeginFrame(); // call at the start of IRenderPipeline::BeginFrame
|
||||
void EndFrame(); // call at the end of IRenderPipeline::EndFrame
|
||||
|
||||
void DrawGUI();
|
||||
|
||||
// call this in Init but only on srp.firstInit
|
||||
// you need to register them in your own local descriptor table(s)
|
||||
void CreateShaderTraceBuffers();
|
||||
|
||||
bool firstInit = true; // first RP init after a RHI init?
|
||||
RenderMode::Id renderMode; // necessary for sampler selection, useful for debugging
|
||||
|
||||
// shader trace
|
||||
HBuffer traceRenderBuffer;
|
||||
HBuffer traceReadbackBuffer;
|
||||
|
||||
// data for frame breakdown and frame graph
|
||||
RenderPassFrame renderPasses[FrameCount];
|
||||
RenderPassFrame tempRenderPasses;
|
||||
RenderPassStats renderPassStats[MaxRenderPasses];
|
||||
RenderPassStats wholeFrameStats;
|
||||
FrameStats frameStats;
|
||||
bool enableRenderPassQueries = true;
|
||||
|
||||
// PSO stats
|
||||
bool psoStatsValid = false;
|
||||
int psoCount = 0;
|
||||
int psoChangeCount = 0;
|
||||
};
|
||||
|
||||
extern SRP srp;
|
||||
|
||||
struct ScopedRenderPass
|
||||
{
|
||||
ScopedRenderPass(const char* name, float r, float g, float b)
|
||||
{
|
||||
index = srp.BeginRenderPass(name, r, g, b);
|
||||
}
|
||||
|
||||
~ScopedRenderPass()
|
||||
{
|
||||
srp.EndRenderPass(index);
|
||||
}
|
||||
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
#define SCOPED_RENDER_PASS(Name, R, G, B) ScopedRenderPass CONCAT(rp_, __LINE__)(Name, R, G, B)
|
||||
|
||||
#define BASE_SAMPLER_COUNT ((int)(TW_COUNT * TextureFilter::Count * MaxTextureMips))
|
||||
|
||||
const image_t* GetBundleImage(const textureBundle_t& bundle);
|
||||
uint32_t GetBaseSamplerIndex(textureWrap_t wrap, TextureFilter::Id filter, uint32_t minLOD);
|
||||
uint32_t GetSamplerIndex(textureWrap_t wrap, TextureFilter::Id filter, uint32_t minLOD = 0);
|
||||
uint32_t GetSamplerIndex(const image_t* image);
|
||||
void ReadTextureImage(void* outPixels, HTexture hreadback, int w, int h, int alignment, colorSpace_t colorSpace);
|
||||
void UpdateEntityData(bool& depthHack, int entityNum, double originalTime);
|
||||
cullType_t GetMirrorredCullType(cullType_t cullType);
|
||||
uint32_t AlphaTestShaderConstFromStateBits(unsigned int stateBits);
|
||||
|
||||
inline void CmdSetViewportAndScissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
||||
{
|
||||
CmdSetViewport(x, y, w, h);
|
||||
CmdSetScissor(x, y, w, h);
|
||||
}
|
||||
|
||||
inline void CmdSetViewportAndScissor(const viewParms_t& vp)
|
||||
{
|
||||
CmdSetViewportAndScissor(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight);
|
||||
}
|
||||
|
||||
inline bool IsDepthFadeEnabled(const shader_t& shader)
|
||||
{
|
||||
return
|
||||
r_depthFade->integer != 0 &&
|
||||
shader.dfType > DFT_NONE &&
|
||||
shader.dfType < DFT_TBD;
|
||||
}
|
539
code/renderer/srp_main.cpp
Normal file
539
code/renderer/srp_main.cpp
Normal file
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Shared Rendering Pipeline - core functionality
|
||||
|
||||
|
||||
#include "srp_local.h"
|
||||
#include "../client/cl_imgui.h"
|
||||
#include "shaders/crp/world.h.hlsli"
|
||||
|
||||
|
||||
extern IRenderPipeline* grpp;
|
||||
extern IRenderPipeline* crpp;
|
||||
|
||||
SRP srp;
|
||||
IRenderPipeline* renderPipeline;
|
||||
|
||||
|
||||
static ImPlotPoint FrameTimeGetter(int index, void*)
|
||||
{
|
||||
const FrameStats& fs = srp.frameStats;
|
||||
const int realIndex = (fs.frameIndex + index) % fs.frameCount;
|
||||
const float value = fs.p2pMS[realIndex];
|
||||
|
||||
ImPlotPoint p;
|
||||
p.x = index;
|
||||
p.y = value;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void UpdateAnimatedImage(image_t* image, int w, int h, const byte* data, qbool dirty)
|
||||
{
|
||||
if(w != image->width || h != image->height)
|
||||
{
|
||||
// @TODO: ?
|
||||
/*image->width = w;
|
||||
image->height = h;
|
||||
CreateTexture(&d3d.textures[image->texnum], image, 1, w, h);
|
||||
GAL_UpdateTexture(image, 0, 0, 0, w, h, data);*/
|
||||
}
|
||||
else if(dirty)
|
||||
{
|
||||
// @TODO: ?
|
||||
//GAL_UpdateTexture(image, 0, 0, 0, w, h, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const image_t* GetBundleImage(const textureBundle_t& bundle)
|
||||
{
|
||||
return R_UpdateAndGetBundleImage(&bundle, &UpdateAnimatedImage);
|
||||
}
|
||||
|
||||
uint32_t GetBaseSamplerIndex(textureWrap_t wrap, TextureFilter::Id filter, uint32_t minLOD)
|
||||
{
|
||||
Q_assert((uint32_t)wrap < TW_COUNT);
|
||||
Q_assert((uint32_t)filter < TextureFilter::Count);
|
||||
|
||||
const uint32_t baseIndex =
|
||||
(uint32_t)filter +
|
||||
(uint32_t)TextureFilter::Count * (uint32_t)wrap +
|
||||
(uint32_t)TextureFilter::Count * (uint32_t)TW_COUNT * minLOD;
|
||||
|
||||
return baseIndex;
|
||||
}
|
||||
|
||||
uint32_t GetSamplerIndex(textureWrap_t wrap, TextureFilter::Id filter, uint32_t minLOD)
|
||||
{
|
||||
const uint32_t baseIndex = GetBaseSamplerIndex(wrap, filter, minLOD);
|
||||
const uint32_t descIndex = renderPipeline->GetSamplerDescriptorIndexFromBaseIndex(baseIndex);
|
||||
|
||||
return descIndex;
|
||||
}
|
||||
|
||||
uint32_t GetSamplerIndex(const image_t* image)
|
||||
{
|
||||
TextureFilter::Id filter = TextureFilter::Anisotropic;
|
||||
if(r_lego->integer &&
|
||||
srp.renderMode == RenderMode::World &&
|
||||
(image->flags & (IMG_LMATLAS | IMG_EXTLMATLAS | IMG_NOPICMIP)) == 0)
|
||||
{
|
||||
filter = TextureFilter::Point;
|
||||
}
|
||||
else if((image->flags & IMG_NOAF) != 0 ||
|
||||
srp.renderMode != RenderMode::World)
|
||||
{
|
||||
filter = TextureFilter::Linear;
|
||||
}
|
||||
|
||||
int minLOD = 0;
|
||||
if(srp.renderMode == RenderMode::World &&
|
||||
(image->flags & IMG_NOPICMIP) == 0)
|
||||
{
|
||||
minLOD = Com_ClampInt(0, MaxTextureMips - 1, r_picmip->integer);
|
||||
}
|
||||
|
||||
return GetSamplerIndex(image->wrapClampMode, filter, (uint32_t)minLOD);
|
||||
}
|
||||
|
||||
void ReadTextureImage(void* outPixels, HTexture hreadback, int w, int h, int alignment, colorSpace_t colorSpace)
|
||||
{
|
||||
MappedTexture mapped;
|
||||
BeginTextureReadback(mapped, hreadback);
|
||||
|
||||
byte* const out0 = (byte*)outPixels;
|
||||
const byte* const in0 = mapped.mappedData;
|
||||
|
||||
if(colorSpace == CS_RGBA)
|
||||
{
|
||||
const int dstRowSizeNoPadding = w * 4;
|
||||
mapped.dstRowByteCount = AlignUp(dstRowSizeNoPadding, alignment);
|
||||
|
||||
for(int y = 0; y < mapped.rowCount; ++y)
|
||||
{
|
||||
byte* out = out0 + (mapped.rowCount - 1 - y) * mapped.dstRowByteCount;
|
||||
const byte* in = in0 + y * mapped.srcRowByteCount;
|
||||
memcpy(out, in, dstRowSizeNoPadding);
|
||||
}
|
||||
}
|
||||
else if(colorSpace == CS_BGR)
|
||||
{
|
||||
mapped.dstRowByteCount = AlignUp(w * 3, alignment);
|
||||
|
||||
for(int y = 0; y < mapped.rowCount; ++y)
|
||||
{
|
||||
byte* out = out0 + (mapped.rowCount - 1 - y) * mapped.dstRowByteCount;
|
||||
const byte* in = in0 + y * mapped.srcRowByteCount;
|
||||
for(int x = 0; x < mapped.columnCount; ++x)
|
||||
{
|
||||
out[2] = in[0];
|
||||
out[1] = in[1];
|
||||
out[0] = in[2];
|
||||
out += 3;
|
||||
in += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_assert(!"Unsupported color space");
|
||||
}
|
||||
|
||||
EndTextureReadback();
|
||||
}
|
||||
|
||||
void UpdateEntityData(bool& depthHack, int entityNum, double originalTime)
|
||||
{
|
||||
depthHack = false;
|
||||
|
||||
if(entityNum != ENTITYNUM_WORLD)
|
||||
{
|
||||
backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
|
||||
if(backEnd.currentEntity->intShaderTime)
|
||||
{
|
||||
backEnd.refdef.floatTime = originalTime - (double)backEnd.currentEntity->e.shaderTime.iShaderTime / 1000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime.fShaderTime;
|
||||
}
|
||||
// we have to reset the shaderTime as well otherwise image animations start
|
||||
// from the wrong frame
|
||||
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
|
||||
|
||||
// set up the transformation matrix
|
||||
R_RotateForEntity(backEnd.currentEntity, &backEnd.viewParms, &backEnd.orient);
|
||||
|
||||
if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK)
|
||||
{
|
||||
depthHack = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
backEnd.currentEntity = &tr.worldEntity;
|
||||
backEnd.refdef.floatTime = originalTime;
|
||||
backEnd.orient = backEnd.viewParms.world;
|
||||
// we have to reset the shaderTime as well otherwise image animations on
|
||||
// the world (like water) continue with the wrong frame
|
||||
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
|
||||
}
|
||||
}
|
||||
|
||||
cullType_t GetMirrorredCullType(cullType_t cullType)
|
||||
{
|
||||
switch(cullType)
|
||||
{
|
||||
case CT_BACK_SIDED: return CT_FRONT_SIDED;
|
||||
case CT_FRONT_SIDED: return CT_BACK_SIDED;
|
||||
default: return CT_TWO_SIDED;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AlphaTestShaderConstFromStateBits(unsigned int stateBits)
|
||||
{
|
||||
stateBits &= GLS_ATEST_BITS;
|
||||
switch(stateBits)
|
||||
{
|
||||
case GLS_ATEST_GE_80: return ATEST_GE_HALF;
|
||||
case GLS_ATEST_GT_0: return ATEST_GT_0;
|
||||
case GLS_ATEST_LT_80: return ATEST_LT_HALF;
|
||||
default: return ATEST_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void R_SelectRenderPipeline()
|
||||
{
|
||||
if(r_pipeline->integer == 0)
|
||||
{
|
||||
renderPipeline = grpp;
|
||||
}
|
||||
else
|
||||
{
|
||||
renderPipeline = crpp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FrameStats::EndFrame()
|
||||
{
|
||||
frameCount = min(frameCount + 1, (int)MaxFrames);
|
||||
frameIndex = (frameIndex + 1) % MaxFrames;
|
||||
Com_StatsFromArray(p2pMS, frameCount, temp, &p2pStats);
|
||||
}
|
||||
|
||||
|
||||
void RenderPassStats::EndFrame(uint32_t cpu, uint32_t gpu)
|
||||
{
|
||||
static uint32_t tempSamples[MaxStatsFrameCount];
|
||||
samplesCPU[index] = cpu;
|
||||
samplesGPU[index] = gpu;
|
||||
count = min(count + 1, (uint32_t)MaxStatsFrameCount);
|
||||
index = (index + 1) % MaxStatsFrameCount;
|
||||
Com_StatsFromArray((const int*)samplesCPU, count, (int*)tempSamples, &statsCPU);
|
||||
Com_StatsFromArray((const int*)samplesGPU, count, (int*)tempSamples, &statsGPU);
|
||||
}
|
||||
|
||||
|
||||
uint32_t SRP::BeginRenderPass(const char* name, float r, float g, float b)
|
||||
{
|
||||
if(!enableRenderPassQueries)
|
||||
{
|
||||
CmdBeginDebugLabel(name, r, g, b);
|
||||
return 0xDEADBEEF;
|
||||
}
|
||||
|
||||
RenderPassFrame& f = renderPasses[tr.frameCount % FrameCount];
|
||||
if(f.count >= ARRAY_LEN(f.passes))
|
||||
{
|
||||
Q_assert(0);
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
CmdBeginDebugLabel(name, r, g, b);
|
||||
|
||||
const uint32_t index = f.count++;
|
||||
RenderPassQueries& q = f.passes[index];
|
||||
Q_strncpyz(q.name, name, sizeof(q.name));
|
||||
q.cpuStartUS = Sys_Microseconds();
|
||||
q.queryIndex = CmdBeginDurationQuery();
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void SRP::EndRenderPass(uint32_t index)
|
||||
{
|
||||
if(!enableRenderPassQueries)
|
||||
{
|
||||
CmdEndDebugLabel();
|
||||
return;
|
||||
}
|
||||
|
||||
Q_assert(index != 0xDEADBEEF); // enableRenderPassQueries should still be false!
|
||||
RenderPassFrame& f = renderPasses[tr.frameCount % FrameCount];
|
||||
if(index >= f.count)
|
||||
{
|
||||
Q_assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
CmdEndDebugLabel();
|
||||
|
||||
RenderPassQueries& q = f.passes[index];
|
||||
q.cpuDurationUS = (uint32_t)(Sys_Microseconds() - q.cpuStartUS);
|
||||
CmdEndDurationQuery(q.queryIndex);
|
||||
}
|
||||
|
||||
void SRP::DrawGUI()
|
||||
{
|
||||
uint32_t durations[MaxDurationQueries];
|
||||
GetDurations(durations);
|
||||
|
||||
wholeFrameStats.EndFrame(rhie.renderToPresentUS, durations[0]);
|
||||
|
||||
const RenderPassFrame& currFrame = renderPasses[(tr.frameCount % FrameCount) ^ 1];
|
||||
RenderPassFrame& tempFrame = tempRenderPasses;
|
||||
|
||||
// see if the render pass list is the same as the previous frame's
|
||||
bool sameRenderPass = true;
|
||||
if(currFrame.count == tempRenderPasses.count)
|
||||
{
|
||||
for(uint32_t p = 0; p < currFrame.count; ++p)
|
||||
{
|
||||
if(Q_stricmp(currFrame.passes[p].name, tempRenderPasses.passes[p].name) != 0)
|
||||
{
|
||||
sameRenderPass = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sameRenderPass = false;
|
||||
}
|
||||
|
||||
// write out the displayed timings into the temp buffer
|
||||
tempFrame.count = currFrame.count;
|
||||
if(sameRenderPass)
|
||||
{
|
||||
for(uint32_t p = 0; p < currFrame.count; ++p)
|
||||
{
|
||||
const uint32_t index = currFrame.passes[p].queryIndex;
|
||||
if(index < MaxDurationQueries)
|
||||
{
|
||||
renderPassStats[p].EndFrame(currFrame.passes[p].cpuDurationUS, durations[index]);
|
||||
tempFrame.passes[p].gpuDurationUS = renderPassStats[p].statsGPU.median;
|
||||
tempFrame.passes[p].cpuDurationUS = renderPassStats[p].statsCPU.median;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(uint32_t p = 0; p < currFrame.count; ++p)
|
||||
{
|
||||
const uint32_t index = currFrame.passes[p].queryIndex;
|
||||
if(index < MaxDurationQueries)
|
||||
{
|
||||
tempFrame.passes[p].gpuDurationUS = durations[index];
|
||||
tempFrame.passes[p].cpuDurationUS = currFrame.passes[p].cpuDurationUS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool breakdownActive = false;
|
||||
ToggleBooleanWithShortcut(breakdownActive, ImGuiKey_F);
|
||||
GUI_AddMainMenuItem(GUI_MainMenu::Perf, "Frame breakdown", "Ctrl+F", &breakdownActive);
|
||||
if(breakdownActive)
|
||||
{
|
||||
if(ImGui::Begin("Frame breakdown", &breakdownActive, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
if(BeginTable("Frame breakdown", 3))
|
||||
{
|
||||
TableHeader(3, "Pass", "GPU [us]", "CPU [us]");
|
||||
|
||||
TableRow(3, "Whole frame",
|
||||
va("%d", (int)wholeFrameStats.statsGPU.median),
|
||||
va("%d", (int)wholeFrameStats.statsCPU.median));
|
||||
|
||||
for(uint32_t p = 0; p < currFrame.count; ++p)
|
||||
{
|
||||
const RenderPassQueries& rp = tempFrame.passes[p];
|
||||
if(rp.queryIndex < MaxDurationQueries)
|
||||
{
|
||||
TableRow(3, rp.name,
|
||||
va("%d", (int)rp.gpuDurationUS),
|
||||
va("%d", (int)rp.cpuDurationUS));
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
if(psoStatsValid)
|
||||
{
|
||||
ImGui::Text("PSO count: %d", (int)psoCount);
|
||||
ImGui::Text("PSO changes: %d", (int)psoChangeCount);
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// save the current render pass list in the temp buffer
|
||||
memcpy(&tempFrame, &currFrame, sizeof(tempFrame));
|
||||
|
||||
static bool frameTimeActive = false;
|
||||
GUI_AddMainMenuItem(GUI_MainMenu::Perf, "Frame stats", NULL, &frameTimeActive);
|
||||
if(frameTimeActive)
|
||||
{
|
||||
if(ImGui::Begin("Frame stats", &frameTimeActive, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
if(BeginTable("Frame stats", 2))
|
||||
{
|
||||
const FrameStats& fs = frameStats;
|
||||
const stats_t& s = fs.p2pStats;
|
||||
TableRow2("Skipped frames", fs.skippedFrames);
|
||||
TableRow2("Frame time target", rhie.targetFrameDurationMS);
|
||||
TableRow2("Frame time average", s.average);
|
||||
TableRow2("Frame time std dev.", s.stdDev);
|
||||
TableRow2("Input to render", (float)rhie.inputToRenderUS / 1000.0f);
|
||||
TableRow2("Input to present", (float)rhie.inputToPresentUS / 1000.0f);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
static bool graphsActive = false;
|
||||
ToggleBooleanWithShortcut(graphsActive, ImGuiKey_G);
|
||||
GUI_AddMainMenuItem(GUI_MainMenu::Perf, "Frame time graphs", "Ctrl+G", &graphsActive);
|
||||
if(graphsActive)
|
||||
{
|
||||
const int windowFlags =
|
||||
ImGuiWindowFlags_NoDecoration |
|
||||
ImGuiWindowFlags_NoBackground |
|
||||
ImGuiWindowFlags_NoMove;
|
||||
ImGui::SetNextWindowSize(ImVec2(glConfig.vidWidth, glConfig.vidHeight / 2), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowPos(ImVec2(0, glConfig.vidHeight / 2), ImGuiCond_Always);
|
||||
if(ImGui::Begin("Frame time graphs", &graphsActive, windowFlags))
|
||||
{
|
||||
const FrameStats& fs = frameStats;
|
||||
const double target = (double)rhie.targetFrameDurationMS;
|
||||
|
||||
static bool autoFit = false;
|
||||
ImGui::Checkbox("Auto-fit", &autoFit);
|
||||
|
||||
if(ImPlot::BeginPlot("Frame Times", ImVec2(-1, -1), ImPlotFlags_NoInputs))
|
||||
{
|
||||
const int axisFlags = 0; // ImPlotAxisFlags_NoTickLabels
|
||||
const int axisFlagsY = axisFlags | (autoFit ? ImPlotAxisFlags_AutoFit : 0);
|
||||
ImPlot::SetupAxes(NULL, NULL, axisFlags, axisFlagsY);
|
||||
ImPlot::SetupAxisLimits(ImAxis_X1, 0, FrameStats::MaxFrames, ImGuiCond_Always);
|
||||
if(!autoFit)
|
||||
{
|
||||
ImPlot::SetupAxisLimits(ImAxis_Y1, max(target - 2.0, 0.0), target + 2.0, ImGuiCond_Always);
|
||||
}
|
||||
|
||||
ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 1.0f);
|
||||
ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL, 1.0f);
|
||||
ImPlot::PlotInfLines("Target", &target, 1, ImPlotInfLinesFlags_Horizontal);
|
||||
|
||||
ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 1.0f);
|
||||
ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL, 1.0f);
|
||||
ImPlot::PlotLineG("Frame Time", &FrameTimeGetter, NULL, fs.frameCount, ImPlotLineFlags_None);
|
||||
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
GUI_DrawMainMenu();
|
||||
R_DrawGUI();
|
||||
}
|
||||
|
||||
void SRP::BeginFrame()
|
||||
{
|
||||
srp.renderPasses[tr.frameCount % FrameCount].count = 0;
|
||||
R_SetColorMappings();
|
||||
|
||||
// nothing is bound to the command list yet!
|
||||
srp.renderMode = RenderMode::None;
|
||||
}
|
||||
|
||||
void SRP::EndFrame()
|
||||
{
|
||||
tr.tracedWorldShaderIndex = -1;
|
||||
if(tr.traceWorldShader && tr.world != NULL)
|
||||
{
|
||||
// schedule a GPU -> CPU transfer
|
||||
{
|
||||
BufferBarrier barrier(traceRenderBuffer, ResourceStates::CopySourceBit);
|
||||
CmdBarrier(0, NULL, 1, &barrier);
|
||||
}
|
||||
CmdCopyBuffer(traceReadbackBuffer, traceRenderBuffer);
|
||||
{
|
||||
BufferBarrier barrier(traceRenderBuffer, ResourceStates::UnorderedAccessBit);
|
||||
CmdBarrier(0, NULL, 1, &barrier);
|
||||
}
|
||||
|
||||
// grab last frame's result
|
||||
uint32_t* shaderIndices = (uint32_t*)MapBuffer(traceReadbackBuffer);
|
||||
const uint32_t shaderIndex = shaderIndices[RHI::GetFrameIndex() ^ 1];
|
||||
UnmapBuffer(traceReadbackBuffer);
|
||||
if(shaderIndex < (uint32_t)tr.numShaders)
|
||||
{
|
||||
tr.tracedWorldShaderIndex = (int)shaderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
RHI::EndFrame();
|
||||
|
||||
if(rhie.presentToPresentUS > 0)
|
||||
{
|
||||
frameStats.p2pMS[frameStats.frameIndex] = (float)rhie.presentToPresentUS / 1000.0f;
|
||||
frameStats.EndFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
frameStats.skippedFrames++;
|
||||
}
|
||||
|
||||
if(backEnd.renderFrame)
|
||||
{
|
||||
Sys_V_EndFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void SRP::CreateShaderTraceBuffers()
|
||||
{
|
||||
{
|
||||
BufferDesc desc("shader trace opaque", 2 * sizeof(uint32_t), ResourceStates::UnorderedAccessBit);
|
||||
traceRenderBuffer = CreateBuffer(desc);
|
||||
}
|
||||
|
||||
{
|
||||
BufferDesc desc("shader trace opaque readback", 2 * sizeof(uint32_t), ResourceStates::Common);
|
||||
desc.memoryUsage = MemoryUsage::Readback;
|
||||
traceReadbackBuffer = CreateBuffer(desc);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -18,26 +18,10 @@ You should have received a copy of the GNU General Public License
|
|||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Gameplay Rendering Pipeline - texture mip-map generation
|
||||
// Shared Rendering Pipeline - texture mip-map generation
|
||||
|
||||
|
||||
// @TODO: test for OOB accesses in the shaders and return
|
||||
// (also, is it needed with feature level 12.0 and HLSL 5.1/6.0 ?)
|
||||
|
||||
|
||||
#include "grp_local.h"
|
||||
namespace start
|
||||
{
|
||||
#include "hlsl/mip_1_cs.h"
|
||||
}
|
||||
namespace down
|
||||
{
|
||||
#include "hlsl/mip_2_cs.h"
|
||||
}
|
||||
namespace end
|
||||
{
|
||||
#include "hlsl/mip_3_cs.h"
|
||||
}
|
||||
#include "srp_local.h"
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
@ -45,6 +29,8 @@ namespace end
|
|||
struct StartConstants
|
||||
{
|
||||
float gamma;
|
||||
uint32_t srcTexture;
|
||||
uint32_t dstTexture;
|
||||
};
|
||||
|
||||
struct DownConstants
|
||||
|
@ -56,6 +42,8 @@ struct DownConstants
|
|||
uint32_t clampMode; // 0 = repeat
|
||||
uint32_t srcMip;
|
||||
uint32_t dstMip;
|
||||
uint32_t srcTexture;
|
||||
uint32_t dstTexture;
|
||||
};
|
||||
|
||||
struct EndConstants
|
||||
|
@ -65,18 +53,22 @@ struct EndConstants
|
|||
float invGamma; // 1.0 / gamma
|
||||
uint32_t srcMip;
|
||||
uint32_t dstMip;
|
||||
uint32_t srcTexture;
|
||||
uint32_t dstTexture;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
void MipMapGenerator::Init()
|
||||
void MipMapGenerator::Init(bool ddhi_, const ShaderByteCode& g2l, const ShaderByteCode& down, const ShaderByteCode& l2g)
|
||||
{
|
||||
if(!grp.firstInit)
|
||||
if(!srp.firstInit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ddhi = ddhi_;
|
||||
|
||||
for(int t = 0; t < 2; ++t)
|
||||
{
|
||||
TextureDesc desc(va("mip-map generation #%d", t + 1), MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE);
|
||||
|
@ -88,26 +80,33 @@ void MipMapGenerator::Init()
|
|||
|
||||
const char* const stageNames[] = { "start", "down", "end" };
|
||||
const uint32_t stageRCByteCount[] = { sizeof(StartConstants), sizeof(DownConstants), sizeof(EndConstants) };
|
||||
const ShaderByteCode stageShaders[] = { ShaderByteCode(start::g_cs), ShaderByteCode(down::g_cs), ShaderByteCode(end::g_cs) };
|
||||
const uint32_t stageExtraMips[] = { 1, 0, MaxTextureMips };
|
||||
const ShaderByteCode stageShaders[] = { g2l, down, l2g };
|
||||
|
||||
for(int s = 0; s < 3; ++s)
|
||||
{
|
||||
Stage& stage = stages[s];
|
||||
if(ddhi)
|
||||
{
|
||||
RootSignatureDesc desc(va("mip-map %s", stageNames[s]));
|
||||
desc.pipelineType = PipelineType::Compute;
|
||||
desc.constants[ShaderStage::Compute].byteCount = stageRCByteCount[s];
|
||||
desc.AddRange(DescriptorType::RWTexture, 0, MipSlice::Count + stageExtraMips[s]);
|
||||
stage.rootSignature = CreateRootSignature(desc);
|
||||
stage.rootSignature = RHI_MAKE_NULL_HANDLE();
|
||||
}
|
||||
else
|
||||
{
|
||||
const DescriptorTableDesc desc(DescriptorTableDesc(va("mip-map %s", stageNames[s]), stage.rootSignature));
|
||||
stage.descriptorTable = CreateDescriptorTable(desc);
|
||||
{
|
||||
RootSignatureDesc desc(va("mip-map %s", stageNames[s]));
|
||||
desc.pipelineType = PipelineType::Compute;
|
||||
desc.constants[ShaderStage::Compute].byteCount = stageRCByteCount[s];
|
||||
desc.AddRange(DescriptorType::RWTexture, 0, MipSlice::Count + stageExtraMips[s]);
|
||||
stage.rootSignature = CreateRootSignature(desc);
|
||||
}
|
||||
{
|
||||
const DescriptorTableDesc desc(DescriptorTableDesc(va("mip-map %s", stageNames[s]), stage.rootSignature));
|
||||
stage.descriptorTable = CreateDescriptorTable(desc);
|
||||
|
||||
DescriptorTableUpdate update;
|
||||
update.SetRWTexturesSlice(ARRAY_LEN(textures), textures, 0, 0);
|
||||
UpdateDescriptorTable(stage.descriptorTable, update);
|
||||
DescriptorTableUpdate update;
|
||||
update.SetRWTexturesSlice(ARRAY_LEN(textures), textures, 0, 0);
|
||||
UpdateDescriptorTable(stage.descriptorTable, update);
|
||||
}
|
||||
}
|
||||
{
|
||||
ComputePipelineDesc desc(va("mip-map %s", stageNames[s]), stage.rootSignature);
|
||||
|
@ -119,7 +118,7 @@ void MipMapGenerator::Init()
|
|||
|
||||
void MipMapGenerator::GenerateMipMaps(HTexture texture)
|
||||
{
|
||||
// @FIXME:
|
||||
// @TODO: better look-up
|
||||
image_t* image = NULL;
|
||||
for(int i = 0; i < tr.numImages; ++i)
|
||||
{
|
||||
|
@ -153,19 +152,22 @@ void MipMapGenerator::GenerateMipMaps(HTexture texture)
|
|||
CmdBarrier(ARRAY_LEN(allBarriers), allBarriers);
|
||||
}
|
||||
|
||||
// this must happen after the BeginTempCommandList call because
|
||||
// it has a CPU wait that guarantees it's safe to update the descriptor tables
|
||||
if(!ddhi)
|
||||
{
|
||||
Stage& stage = stages[Stage::Start];
|
||||
DescriptorTableUpdate update;
|
||||
update.SetRWTexturesSlice(1, &texture, MipSlice::Count, 0);
|
||||
UpdateDescriptorTable(stage.descriptorTable, update);
|
||||
}
|
||||
{
|
||||
Stage& stage = stages[Stage::End];
|
||||
DescriptorTableUpdate update;
|
||||
update.SetRWTexturesChain(1, &texture, MipSlice::Count);
|
||||
UpdateDescriptorTable(stage.descriptorTable, update);
|
||||
// this must happen after the BeginTempCommandList call because
|
||||
// it has a CPU wait that guarantees it's safe to update the descriptor tables
|
||||
{
|
||||
Stage& stage = stages[Stage::Start];
|
||||
DescriptorTableUpdate update;
|
||||
update.SetRWTexturesSlice(1, &texture, MipSlice::Count, 0);
|
||||
UpdateDescriptorTable(stage.descriptorTable, update);
|
||||
}
|
||||
{
|
||||
Stage& stage = stages[Stage::End];
|
||||
DescriptorTableUpdate update;
|
||||
update.SetRWTexturesChain(1, &texture, MipSlice::Count);
|
||||
UpdateDescriptorTable(stage.descriptorTable, update);
|
||||
}
|
||||
}
|
||||
|
||||
int w = image->width;
|
||||
|
@ -180,10 +182,22 @@ void MipMapGenerator::GenerateMipMaps(HTexture texture)
|
|||
StartConstants rc = {};
|
||||
rc.gamma = r_mipGenGamma->value;
|
||||
|
||||
CmdBindRootSignature(stage.rootSignature);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindRootSignature(stage.rootSignature);
|
||||
}
|
||||
CmdBindPipeline(stage.pipeline);
|
||||
CmdBindDescriptorTable(stage.rootSignature, stage.descriptorTable);
|
||||
CmdSetRootConstants(stage.rootSignature, ShaderStage::Compute, &rc);
|
||||
if(ddhi)
|
||||
{
|
||||
rc.srcTexture = GetTextureIndexUAV(texture, 0);
|
||||
rc.dstTexture = GetTextureIndexUAV(textures[MipSlice::Float16_0], 0);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdBindDescriptorTable(stage.rootSignature, stage.descriptorTable);
|
||||
CmdSetRootConstants(stage.rootSignature, ShaderStage::Compute, &rc);
|
||||
}
|
||||
Dispatch(w, h);
|
||||
}
|
||||
|
||||
|
@ -207,10 +221,22 @@ void MipMapGenerator::GenerateMipMaps(HTexture texture)
|
|||
rc.srcMip = MipSlice::Float16_0;
|
||||
rc.dstMip = MipSlice::Count + destMip;
|
||||
|
||||
CmdBindRootSignature(stage.rootSignature);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindRootSignature(stage.rootSignature);
|
||||
}
|
||||
CmdBindPipeline(stage.pipeline);
|
||||
CmdBindDescriptorTable(stage.rootSignature, stage.descriptorTable);
|
||||
CmdSetRootConstants(stage.rootSignature, ShaderStage::Compute, &rc);
|
||||
if(ddhi)
|
||||
{
|
||||
rc.srcTexture = GetTextureIndexUAV(textures[MipSlice::Float16_0], 0);
|
||||
rc.dstTexture = GetTextureIndexUAV(texture, destMip);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdBindDescriptorTable(stage.rootSignature, stage.descriptorTable);
|
||||
CmdSetRootConstants(stage.rootSignature, ShaderStage::Compute, &rc);
|
||||
}
|
||||
CmdBarrier(ARRAY_LEN(tempBarriers), tempBarriers);
|
||||
Dispatch(w, h);
|
||||
}
|
||||
|
@ -229,9 +255,15 @@ void MipMapGenerator::GenerateMipMaps(HTexture texture)
|
|||
rc.clampMode = image->wrapClampMode == TW_REPEAT ? 0 : 1;
|
||||
memcpy(rc.weights, tr.mipFilter, sizeof(rc.weights));
|
||||
|
||||
CmdBindRootSignature(stage.rootSignature);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindRootSignature(stage.rootSignature);
|
||||
}
|
||||
CmdBindPipeline(stage.pipeline);
|
||||
CmdBindDescriptorTable(stage.rootSignature, stage.descriptorTable);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindDescriptorTable(stage.rootSignature, stage.descriptorTable);
|
||||
}
|
||||
|
||||
// down-sample on the X-axis
|
||||
rc.srcMip = MipSlice::Float16_0;
|
||||
|
@ -242,7 +274,16 @@ void MipMapGenerator::GenerateMipMaps(HTexture texture)
|
|||
rc.maxSize[1] = hs - 1;
|
||||
rc.offset[0] = 1;
|
||||
rc.offset[1] = 0;
|
||||
CmdSetRootConstants(stage.rootSignature, ShaderStage::Compute, &rc);
|
||||
if(ddhi)
|
||||
{
|
||||
rc.srcTexture = GetTextureIndexUAV(textures[MipSlice::Float16_0], 0);
|
||||
rc.dstTexture = GetTextureIndexUAV(textures[MipSlice::Float16_1], 0);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdSetRootConstants(stage.rootSignature, ShaderStage::Compute, &rc);
|
||||
}
|
||||
CmdBarrier(ARRAY_LEN(tempBarriers), tempBarriers);
|
||||
Dispatch(w, hs);
|
||||
|
||||
|
@ -255,7 +296,16 @@ void MipMapGenerator::GenerateMipMaps(HTexture texture)
|
|||
rc.maxSize[1] = hs - 1;
|
||||
rc.offset[0] = 0;
|
||||
rc.offset[1] = 1;
|
||||
CmdSetRootConstants(stage.rootSignature, ShaderStage::Compute, &rc);
|
||||
if(ddhi)
|
||||
{
|
||||
rc.srcTexture = GetTextureIndexUAV(textures[MipSlice::Float16_1], 0);
|
||||
rc.dstTexture = GetTextureIndexUAV(textures[MipSlice::Float16_0], 0);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdSetRootConstants(stage.rootSignature, ShaderStage::Compute, &rc);
|
||||
}
|
||||
CmdBarrier(ARRAY_LEN(tempBarriers), tempBarriers);
|
||||
Dispatch(w, h);
|
||||
}
|
||||
|
@ -272,10 +322,22 @@ void MipMapGenerator::GenerateMipMaps(HTexture texture)
|
|||
rc.srcMip = MipSlice::Float16_0;
|
||||
rc.dstMip = MipSlice::Count + destMip;
|
||||
|
||||
CmdBindRootSignature(stage.rootSignature);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindRootSignature(stage.rootSignature);
|
||||
}
|
||||
CmdBindPipeline(stage.pipeline);
|
||||
CmdBindDescriptorTable(stage.rootSignature, stage.descriptorTable);
|
||||
CmdSetRootConstants(stage.rootSignature, ShaderStage::Compute, &rc);
|
||||
if(ddhi)
|
||||
{
|
||||
rc.srcTexture = GetTextureIndexUAV(textures[MipSlice::Float16_0], 0);
|
||||
rc.dstTexture = GetTextureIndexUAV(texture, destMip);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdBindDescriptorTable(stage.rootSignature, stage.descriptorTable);
|
||||
CmdSetRootConstants(stage.rootSignature, ShaderStage::Compute, &rc);
|
||||
}
|
||||
CmdBarrier(ARRAY_LEN(tempBarriers), tempBarriers);
|
||||
Dispatch(w, h);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -21,9 +21,7 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
// Gameplay Rendering Pipeline - Nuklear integration
|
||||
|
||||
|
||||
#include "grp_local.h"
|
||||
#include "hlsl/nuklear_vs.h"
|
||||
#include "hlsl/nuklear_ps.h"
|
||||
#include "srp_local.h"
|
||||
|
||||
|
||||
#define MAX_NUKLEAR_VERTEX_COUNT (1024 * 1024)
|
||||
|
@ -53,9 +51,12 @@ struct NuklearVertex
|
|||
#pragma pack(pop)
|
||||
|
||||
|
||||
void Nuklear::Init()
|
||||
void Nuklear::Init(bool ddhi_, const ShaderByteCode& vs, const ShaderByteCode& ps, TextureFormat::Id rtFormat, HDescriptorTable descTable, RootSignatureDesc* rootSigDesc)
|
||||
{
|
||||
if(grp.firstInit)
|
||||
ddhi = ddhi_;
|
||||
descriptorTable = descTable;
|
||||
|
||||
if(srp.firstInit)
|
||||
{
|
||||
for(int i = 0; i < FrameCount; i++)
|
||||
{
|
||||
|
@ -70,8 +71,9 @@ void Nuklear::Init()
|
|||
fr->vertexBuffer = CreateBuffer(idx);
|
||||
}
|
||||
|
||||
if(!ddhi)
|
||||
{
|
||||
RootSignatureDesc desc = grp.rootSignatureDesc;
|
||||
RootSignatureDesc desc = *rootSigDesc;
|
||||
desc.name = "Nuklear";
|
||||
desc.constants[ShaderStage::Vertex].byteCount = sizeof(VertexRC);
|
||||
desc.constants[ShaderStage::Pixel].byteCount = sizeof(PixelRC);
|
||||
|
@ -82,8 +84,8 @@ void Nuklear::Init()
|
|||
{
|
||||
GraphicsPipelineDesc desc("Nuklear", rootSignature);
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(g_vs);
|
||||
desc.pixelShader = ShaderByteCode(g_ps);
|
||||
desc.vertexShader = vs;
|
||||
desc.pixelShader = ps;
|
||||
desc.vertexLayout.bindingStrides[0] = sizeof(NuklearVertex);
|
||||
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position,
|
||||
DataType::Float32, 2, offsetof(NuklearVertex, position));
|
||||
|
@ -96,7 +98,7 @@ void Nuklear::Init()
|
|||
desc.depthStencil.enableDepthTest = false;
|
||||
desc.depthStencil.enableDepthWrites = false;
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, grp.renderTargetFormat);
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, rtFormat);
|
||||
pipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
|
@ -109,24 +111,30 @@ void Nuklear::BeginFrame()
|
|||
numIndexes = 0;
|
||||
}
|
||||
|
||||
void Nuklear::Begin()
|
||||
void Nuklear::Begin(HTexture renderTarget)
|
||||
{
|
||||
if(grp.renderMode == RenderMode::Nuklear)
|
||||
if(srp.renderMode == RenderMode::Nuklear)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
grp.renderMode = RenderMode::Nuklear;
|
||||
srp.renderMode = RenderMode::Nuklear;
|
||||
|
||||
renderPassIndex = grp.BeginRenderPass("Nuklear", 0.75f, 0.75f, 1.0f);
|
||||
renderPassIndex = srp.BeginRenderPass("Nuklear", 0.75f, 0.75f, 1.0f);
|
||||
|
||||
FrameResources* const fr = &frameResources[GetFrameIndex()];
|
||||
|
||||
const uint32_t vertexStride = sizeof(NuklearVertex);
|
||||
CmdBindRenderTargets(1, &grp.renderTarget, NULL);
|
||||
CmdBindRootSignature(rootSignature);
|
||||
CmdBindRenderTargets(1, &renderTarget, NULL);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindRootSignature(rootSignature);
|
||||
}
|
||||
CmdBindPipeline(pipeline);
|
||||
CmdBindDescriptorTable(rootSignature, grp.descriptorTable);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindDescriptorTable(rootSignature, descriptorTable);
|
||||
}
|
||||
CmdBindVertexBuffers(1, &fr->vertexBuffer, &vertexStride, NULL);
|
||||
CmdBindIndexBuffer(fr->indexBuffer, IndexType::UInt32, 0);
|
||||
CmdSetViewport(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
@ -142,7 +150,14 @@ void Nuklear::Begin()
|
|||
0.0f, 0.0f, 0.5f, 0.0f,
|
||||
(R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f
|
||||
};
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Vertex, &vertexRC);
|
||||
if(ddhi)
|
||||
{
|
||||
CmdSetGraphicsRootConstants(0, sizeof(vertexRC), &vertexRC);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Vertex, &vertexRC);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
|
@ -152,9 +167,9 @@ void Nuklear::Begin()
|
|||
|
||||
void Nuklear::End()
|
||||
{
|
||||
grp.EndRenderPass(renderPassIndex);
|
||||
srp.EndRenderPass(renderPassIndex);
|
||||
|
||||
grp.renderMode = RenderMode::None;
|
||||
srp.renderMode = RenderMode::None;
|
||||
}
|
||||
|
||||
void Nuklear::Upload(const nuklearUploadCommand_t& cmd)
|
||||
|
@ -196,7 +211,14 @@ void Nuklear::Draw(const nuklearDrawCommand_t& cmd)
|
|||
PixelRC pixelRC = {};
|
||||
pixelRC.texture = (uint32_t)image->textureIndex;
|
||||
pixelRC.sampler = GetSamplerIndex(image->wrapClampMode, TextureFilter::Linear);
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Pixel, &pixelRC);
|
||||
if(ddhi)
|
||||
{
|
||||
CmdSetGraphicsRootConstants(sizeof(VertexRC), sizeof(pixelRC), &pixelRC);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Pixel, &pixelRC);
|
||||
}
|
||||
|
||||
if(memcmp(cmd.scissorRect, prevScissorRect, sizeof(prevScissorRect)) != 0)
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2022-2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2022-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -18,16 +18,13 @@ You should have received a copy of the GNU General Public License
|
|||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Gameplay Rendering Pipeline - UI/2D rendering
|
||||
// Shared Rendering Pipeline - UI/2D rendering
|
||||
|
||||
|
||||
#include "grp_local.h"
|
||||
#include "hlsl/ui_vs.h"
|
||||
#include "hlsl/ui_ps.h"
|
||||
#include "srp_local.h"
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
struct VertexRC
|
||||
{
|
||||
float scale[2];
|
||||
|
@ -38,16 +35,23 @@ struct PixelRC
|
|||
uint32_t texture;
|
||||
uint32_t sampler;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
void UI::Init()
|
||||
void UI::Init(bool ddhi_, const ShaderByteCode& vs, const ShaderByteCode& ps, TextureFormat::Id rtFormat, HDescriptorTable descTable, RootSignatureDesc* rootSigDesc)
|
||||
{
|
||||
if(grp.firstInit)
|
||||
ddhi = ddhi_;
|
||||
descriptorTable = descTable;
|
||||
|
||||
if(srp.firstInit)
|
||||
{
|
||||
if(ddhi)
|
||||
{
|
||||
RootSignatureDesc desc = grp.rootSignatureDesc;
|
||||
rootSignature = RHI_MAKE_NULL_HANDLE();
|
||||
}
|
||||
else
|
||||
{
|
||||
RootSignatureDesc desc = *rootSigDesc;
|
||||
desc.name = "UI";
|
||||
desc.constants[ShaderStage::Vertex].byteCount = 8;
|
||||
desc.constants[ShaderStage::Pixel].byteCount = 8;
|
||||
|
@ -71,8 +75,8 @@ void UI::Init()
|
|||
{
|
||||
GraphicsPipelineDesc desc("UI", rootSignature);
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(g_vs);
|
||||
desc.pixelShader = ShaderByteCode(g_ps);
|
||||
desc.vertexShader = vs;
|
||||
desc.pixelShader = ps;
|
||||
desc.vertexLayout.bindingStrides[0] = sizeof(UI::Vertex);
|
||||
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position,
|
||||
DataType::Float32, 2, offsetof(UI::Vertex, position));
|
||||
|
@ -85,7 +89,7 @@ void UI::Init()
|
|||
desc.depthStencil.enableDepthTest = false;
|
||||
desc.depthStencil.enableDepthWrites = false;
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, grp.renderTargetFormat);
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, rtFormat);
|
||||
pipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
|
@ -99,20 +103,29 @@ void UI::BeginFrame()
|
|||
renderPassIndex = UINT32_MAX;
|
||||
}
|
||||
|
||||
void UI::Begin()
|
||||
void UI::Begin(HTexture renderTarget)
|
||||
{
|
||||
grp.renderMode = RenderMode::UI;
|
||||
srp.renderMode = RenderMode::UI;
|
||||
|
||||
renderPassIndex = grp.BeginRenderPass("UI", 0.0f, 0.85f, 1.0f);
|
||||
renderPassIndex = srp.BeginRenderPass("UI", 0.0f, 0.85f, 1.0f);
|
||||
|
||||
CmdBindRenderTargets(1, &grp.renderTarget, NULL);
|
||||
const TextureBarrier tb(renderTarget, ResourceStates::RenderTargetBit);
|
||||
CmdBarrier(1, &tb);
|
||||
|
||||
CmdBindRenderTargets(1, &renderTarget, NULL);
|
||||
|
||||
// UI always uses the entire render surface
|
||||
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
||||
CmdBindRootSignature(rootSignature);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindRootSignature(rootSignature);
|
||||
}
|
||||
CmdBindPipeline(pipeline);
|
||||
CmdBindDescriptorTable(rootSignature, grp.descriptorTable);
|
||||
if(!ddhi)
|
||||
{
|
||||
CmdBindDescriptorTable(rootSignature, descriptorTable);
|
||||
}
|
||||
const uint32_t stride = sizeof(UI::Vertex);
|
||||
CmdBindVertexBuffers(1, &vertexBuffer, &stride, NULL);
|
||||
CmdBindIndexBuffer(indexBuffer, indexType, 0);
|
||||
|
@ -120,16 +133,23 @@ void UI::Begin()
|
|||
VertexRC vertexRC = {};
|
||||
vertexRC.scale[0] = 2.0f / glConfig.vidWidth;
|
||||
vertexRC.scale[1] = 2.0f / glConfig.vidHeight;
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Vertex, &vertexRC);
|
||||
if(ddhi)
|
||||
{
|
||||
CmdSetGraphicsRootConstants(0, sizeof(vertexRC), &vertexRC);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Vertex, &vertexRC);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::End()
|
||||
{
|
||||
DrawBatch();
|
||||
|
||||
grp.EndRenderPass(renderPassIndex);
|
||||
srp.EndRenderPass(renderPassIndex);
|
||||
|
||||
grp.renderMode = RenderMode::None;
|
||||
srp.renderMode = RenderMode::None;
|
||||
}
|
||||
|
||||
void UI::DrawBatch()
|
||||
|
@ -146,7 +166,14 @@ void UI::DrawBatch()
|
|||
PixelRC pixelRC = {};
|
||||
pixelRC.texture = GetBundleImage(bundle)->textureIndex;
|
||||
pixelRC.sampler = GetSamplerIndex(wrapMode, TextureFilter::Linear);
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Pixel, &pixelRC);
|
||||
if(ddhi)
|
||||
{
|
||||
CmdSetGraphicsRootConstants(sizeof(VertexRC), sizeof(PixelRC), &pixelRC);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdSetRootConstants(rootSignature, ShaderStage::Pixel, &pixelRC);
|
||||
}
|
||||
|
||||
CmdDrawIndexed(indexCount, firstIndex, 0);
|
||||
firstIndex += indexCount;
|
||||
|
@ -155,7 +182,7 @@ void UI::DrawBatch()
|
|||
vertexCount = 0;
|
||||
}
|
||||
|
||||
void UI::UISetColor(const uiSetColorCommand_t& cmd)
|
||||
void UI::CmdSetColor(const uiSetColorCommand_t& cmd)
|
||||
{
|
||||
const float rgbScale = tr.identityLight * 255.0f;
|
||||
byte* const colors = (byte*)&color;
|
||||
|
@ -165,7 +192,7 @@ void UI::UISetColor(const uiSetColorCommand_t& cmd)
|
|||
colors[3] = (byte)(cmd.color[3] * 255.0f);
|
||||
}
|
||||
|
||||
void UI::UIDrawQuad(const uiDrawQuadCommand_t& cmd)
|
||||
void UI::CmdDrawQuad(const uiDrawQuadCommand_t& cmd)
|
||||
{
|
||||
if(vertexCount + 4 > maxVertexCount ||
|
||||
indexCount + 6 > maxIndexCount)
|
||||
|
@ -217,7 +244,7 @@ void UI::UIDrawQuad(const uiDrawQuadCommand_t& cmd)
|
|||
vertices[v + 3].color = color;
|
||||
}
|
||||
|
||||
void UI::UIDrawTriangle(const uiDrawTriangleCommand_t& cmd)
|
||||
void UI::CmdDrawTriangle(const uiDrawTriangleCommand_t& cmd)
|
||||
{
|
||||
if(vertexCount + 3 > maxVertexCount ||
|
||||
indexCount + 3 > maxIndexCount)
|
|
@ -90,6 +90,7 @@ cvar_t *r_picmip;
|
|||
cvar_t *r_clear;
|
||||
cvar_t *r_vsync;
|
||||
cvar_t *r_lego;
|
||||
cvar_t *r_pipeline;
|
||||
cvar_t *r_lockpvs;
|
||||
cvar_t *r_noportals;
|
||||
cvar_t *r_portalOnly;
|
||||
|
@ -445,10 +446,16 @@ static const cvarTableItem_t r_cvars[] =
|
|||
},
|
||||
{
|
||||
&r_vsync, "r_vsync", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "enables v-sync",
|
||||
"V-Sync", CVARCAT_DISPLAY | CVARCAT_PERFORMANCE, "Enabling locks the framerate to the monitor's refresh rate", ""
|
||||
"V-Sync", CVARCAT_DISPLAY | CVARCAT_PERFORMANCE, "Enabling locks the framerate to the monitor's refresh rate", "",
|
||||
CVAR_GUI_VALUE("0", "Frame cap", "The framerate is capped by CNQ3's own limiter")
|
||||
CVAR_GUI_VALUE("1", "V-Sync", "The framerate matches the monitor's refresh rate")
|
||||
},
|
||||
{
|
||||
&r_pipeline, "r_pipeline", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "rendering pipeline",
|
||||
"Rendering pipeline", CVARCAT_GRAPHICS, "", "",
|
||||
CVAR_GUI_VALUE("0", "Gameplay", "Use to play the game")
|
||||
CVAR_GUI_VALUE("1", "Cinematic", "Use for screenshots and movies")
|
||||
},
|
||||
|
||||
//
|
||||
// latched variables that can only change over a restart
|
||||
|
@ -751,6 +758,7 @@ void R_Init()
|
|||
|
||||
R_InitMipFilter();
|
||||
|
||||
R_SelectRenderPipeline();
|
||||
renderPipeline->Init();
|
||||
|
||||
R_InitImages();
|
||||
|
@ -773,6 +781,9 @@ static void RE_Shutdown( qbool destroyWindow )
|
|||
|
||||
if ( tr.registered ) {
|
||||
ri.Cmd_UnregisterModule();
|
||||
if ( !destroyWindow && r_pipeline->latchedString != NULL ) {
|
||||
destroyWindow = qtrue;
|
||||
}
|
||||
renderPipeline->ShutDown( destroyWindow );
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include "../qcommon/qfiles.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "tr_public.h"
|
||||
#include "shaders/common/state_bits.h.hlsli" // contains all the shared GLS_* macros
|
||||
|
||||
|
||||
#define GLS_DEFAULT GLS_DEPTHMASK_TRUE
|
||||
#define GLS_DEFAULT_2D (GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
|
||||
extern const float s_flipMatrix[16];
|
||||
|
@ -427,6 +432,9 @@ struct shader_t {
|
|||
pipeline_t pipelines[MAX_SHADER_STAGES];
|
||||
int numPipelines;
|
||||
|
||||
pipeline_t transpPipelines[MAX_SHADER_STAGES];
|
||||
int numTranspPipelines;
|
||||
|
||||
shader_t* next;
|
||||
};
|
||||
|
||||
|
@ -473,6 +481,7 @@ typedef struct {
|
|||
float projectionMatrix[16];
|
||||
cplane_t frustum[4];
|
||||
vec3_t visBounds[2];
|
||||
float zNear;
|
||||
float zFar;
|
||||
} viewParms_t;
|
||||
|
||||
|
@ -1061,6 +1070,7 @@ extern cvar_t *r_picmip; // controls picmip values
|
|||
|
||||
extern cvar_t *r_vsync;
|
||||
extern cvar_t *r_lego;
|
||||
extern cvar_t *r_pipeline;
|
||||
|
||||
extern cvar_t *r_vertexLight; // vertex lighting mode for better performance
|
||||
extern cvar_t *r_uiFullScreen; // ui is running fullscreen
|
||||
|
@ -1112,49 +1122,11 @@ int R_CullPointAndRadius( const vec3_t origin, float radius );
|
|||
int R_CullLocalPointAndRadius( const vec3_t origin, float radius );
|
||||
|
||||
void R_RotateForEntity( const trRefEntity_t* ent, const viewParms_t* viewParms, orientationr_t* orient );
|
||||
void R_CreateWorldModelMatrix( const vec3_t origin, const vec3_t axis[3], float* viewMatrix );
|
||||
|
||||
typedef void (*updateAnimatedImage_t)( image_t* image, int w, int h, const byte* data, qbool dirty );
|
||||
const image_t* R_UpdateAndGetBundleImage( const textureBundle_t* bundle, updateAnimatedImage_t updateImage );
|
||||
|
||||
|
||||
#define GLS_SRCBLEND_ZERO 0x00000001
|
||||
#define GLS_SRCBLEND_ONE 0x00000002
|
||||
#define GLS_SRCBLEND_DST_COLOR 0x00000003
|
||||
#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004
|
||||
#define GLS_SRCBLEND_SRC_ALPHA 0x00000005
|
||||
#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006
|
||||
#define GLS_SRCBLEND_DST_ALPHA 0x00000007
|
||||
#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008
|
||||
#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009
|
||||
#define GLS_SRCBLEND_BITS 0x0000000f
|
||||
|
||||
#define GLS_DSTBLEND_ZERO 0x00000010
|
||||
#define GLS_DSTBLEND_ONE 0x00000020
|
||||
#define GLS_DSTBLEND_SRC_COLOR 0x00000030
|
||||
#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040
|
||||
#define GLS_DSTBLEND_SRC_ALPHA 0x00000050
|
||||
#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060
|
||||
#define GLS_DSTBLEND_DST_ALPHA 0x00000070
|
||||
#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080
|
||||
#define GLS_DSTBLEND_BITS 0x000000f0
|
||||
|
||||
#define GLS_BLEND_BITS 0x000000ff
|
||||
|
||||
#define GLS_DEPTHMASK_TRUE 0x00000100 // enable depth writes
|
||||
|
||||
#define GLS_POLYMODE_LINE 0x00001000 // wireframe polygon filling, not line rendering
|
||||
|
||||
#define GLS_DEPTHTEST_DISABLE 0x00010000 // disable depth tests
|
||||
#define GLS_DEPTHFUNC_EQUAL 0x00020000
|
||||
|
||||
#define GLS_ATEST_GT_0 0x10000000
|
||||
#define GLS_ATEST_LT_80 0x20000000
|
||||
#define GLS_ATEST_GE_80 0x40000000
|
||||
#define GLS_ATEST_BITS 0x70000000
|
||||
|
||||
#define GLS_DEFAULT GLS_DEPTHMASK_TRUE
|
||||
#define GLS_DEFAULT_2D (GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
void RE_LoadWorldMap( const char *mapname );
|
||||
void RE_SetWorldVisData( const byte *vis );
|
||||
qhandle_t RE_RegisterModel( const char *name );
|
||||
|
@ -1309,6 +1281,9 @@ struct shaderCommands_t
|
|||
|
||||
// how to process the colors of the current batch
|
||||
float greyscale;
|
||||
|
||||
// identifier of the code currently tessellating geometry
|
||||
int tessellator;
|
||||
};
|
||||
|
||||
extern shaderCommands_t tess;
|
||||
|
@ -1490,7 +1465,6 @@ struct drawSceneViewCommand_t : renderCommandBase_t {
|
|||
|
||||
struct endSceneCommand_t : renderCommandBase_t {
|
||||
viewParms_t viewParms;
|
||||
uint32_t padding2;
|
||||
};
|
||||
|
||||
struct nuklearUploadCommand_t : renderCommandBase_t {
|
||||
|
@ -1631,6 +1605,11 @@ void R_CameraAxisVectorsFromMatrix( const float* modelView, vec3_t axisX, vec3_t
|
|||
void R_MakeIdentityMatrix( float* m );
|
||||
void R_MakeOrthoProjectionMatrix( float* m, float w, float h );
|
||||
|
||||
// LinearDepth(depthZW, A, B) -> B / (depthZW - A)
|
||||
void R_LinearDepthConstantsFromProjectionMatrix( const float* projMatrix, float* A, float* B );
|
||||
void R_LinearDepthConstantsFromClipPlanes( float zNear, float zFar, float* A, float* B );
|
||||
void RB_LinearDepthConstants( float* A, float* B );
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -1693,20 +1672,18 @@ struct IRenderPipeline
|
|||
virtual void EndTextureUpload() = 0;
|
||||
|
||||
virtual void ExecuteRenderCommands(const byte* data, bool readbackRequested) = 0;
|
||||
|
||||
virtual void UISetColor(const uiSetColorCommand_t& cmd) = 0;
|
||||
virtual void UIDrawQuad(const uiDrawQuadCommand_t& cmd) = 0;
|
||||
virtual void UIDrawTriangle(const uiDrawTriangleCommand_t& cmd) = 0;
|
||||
virtual void DrawSceneView(const drawSceneViewCommand_t& cmd) = 0;
|
||||
virtual void TessellationOverflow() = 0;
|
||||
virtual void DrawSkyBox() = 0;
|
||||
virtual void DrawClouds() = 0;
|
||||
|
||||
virtual void ReadPixels(int w, int h, int alignment, colorSpace_t colorSpace, void* out) = 0;
|
||||
|
||||
virtual uint32_t GetSamplerDescriptorIndexFromBaseIndex(uint32_t baseIndex) = 0;
|
||||
};
|
||||
|
||||
extern IRenderPipeline* renderPipeline;
|
||||
|
||||
void R_SelectRenderPipeline();
|
||||
|
||||
struct RHIExport
|
||||
{
|
||||
uint32_t renderToPresentUS;
|
||||
|
|
|
@ -464,6 +464,26 @@ void R_MakeOrthoProjectionMatrix( float* m, float w, float h )
|
|||
}
|
||||
|
||||
|
||||
void R_LinearDepthConstantsFromProjectionMatrix( const float* projMatrix, float* A, float* B )
|
||||
{
|
||||
*A = -projMatrix[2 * 4 + 2];
|
||||
*B = projMatrix[3 * 4 + 2];
|
||||
}
|
||||
|
||||
|
||||
void R_LinearDepthConstantsFromClipPlanes( float n, float f, float* A, float* B )
|
||||
{
|
||||
*A = -n / (f - n);
|
||||
*B = f * (n / (f - n));
|
||||
}
|
||||
|
||||
|
||||
void RB_LinearDepthConstants( float* A, float* B )
|
||||
{
|
||||
R_LinearDepthConstantsFromProjectionMatrix( backEnd.viewParms.projectionMatrix, A, B );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
R_RotateForEntity
|
||||
|
@ -534,13 +554,40 @@ void R_RotateForEntity( const trRefEntity_t* ent, const viewParms_t* viewParms,
|
|||
}
|
||||
|
||||
|
||||
void R_CreateWorldModelMatrix( const vec3_t origin, const vec3_t axis[3], float* viewMatrix )
|
||||
{
|
||||
float viewerMatrix[16];
|
||||
|
||||
viewerMatrix[0] = axis[0][0];
|
||||
viewerMatrix[4] = axis[0][1];
|
||||
viewerMatrix[8] = axis[0][2];
|
||||
viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
|
||||
|
||||
viewerMatrix[1] = axis[1][0];
|
||||
viewerMatrix[5] = axis[1][1];
|
||||
viewerMatrix[9] = axis[1][2];
|
||||
viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
|
||||
|
||||
viewerMatrix[2] = axis[2][0];
|
||||
viewerMatrix[6] = axis[2][1];
|
||||
viewerMatrix[10] = axis[2][2];
|
||||
viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
|
||||
|
||||
viewerMatrix[3] = 0.0f;
|
||||
viewerMatrix[7] = 0.0f;
|
||||
viewerMatrix[11] = 0.0f;
|
||||
viewerMatrix[15] = 1.0f;
|
||||
|
||||
// convert from our coordinate system (looking down X)
|
||||
// to the back-end's coordinate system (looking down -Z)
|
||||
R_MultMatrix( viewerMatrix, s_flipMatrix, viewMatrix );
|
||||
}
|
||||
|
||||
|
||||
// sets up the modelview matrix for a given viewParm
|
||||
|
||||
static void R_RotateForViewer()
|
||||
{
|
||||
float viewerMatrix[16];
|
||||
vec3_t origin;
|
||||
|
||||
Com_Memset( &tr.orient, 0, sizeof(tr.orient) );
|
||||
tr.orient.axis[0][0] = 1;
|
||||
tr.orient.axis[1][1] = 1;
|
||||
|
@ -548,42 +595,20 @@ static void R_RotateForViewer()
|
|||
VectorCopy( tr.viewParms.orient.origin, tr.orient.viewOrigin );
|
||||
|
||||
// transform by the camera placement
|
||||
VectorCopy( tr.viewParms.orient.origin, origin );
|
||||
|
||||
viewerMatrix[0] = tr.viewParms.orient.axis[0][0];
|
||||
viewerMatrix[4] = tr.viewParms.orient.axis[0][1];
|
||||
viewerMatrix[8] = tr.viewParms.orient.axis[0][2];
|
||||
viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
|
||||
|
||||
viewerMatrix[1] = tr.viewParms.orient.axis[1][0];
|
||||
viewerMatrix[5] = tr.viewParms.orient.axis[1][1];
|
||||
viewerMatrix[9] = tr.viewParms.orient.axis[1][2];
|
||||
viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
|
||||
|
||||
viewerMatrix[2] = tr.viewParms.orient.axis[2][0];
|
||||
viewerMatrix[6] = tr.viewParms.orient.axis[2][1];
|
||||
viewerMatrix[10] = tr.viewParms.orient.axis[2][2];
|
||||
viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
|
||||
|
||||
viewerMatrix[3] = 0;
|
||||
viewerMatrix[7] = 0;
|
||||
viewerMatrix[11] = 0;
|
||||
viewerMatrix[15] = 1;
|
||||
|
||||
// convert from our coordinate system (looking down X)
|
||||
// to the back-end's coordinate system (looking down -Z)
|
||||
R_MultMatrix( viewerMatrix, s_flipMatrix, tr.orient.modelMatrix );
|
||||
R_CreateWorldModelMatrix( tr.viewParms.orient.origin, tr.viewParms.orient.axis, tr.orient.modelMatrix );
|
||||
|
||||
tr.viewParms.world = tr.orient;
|
||||
}
|
||||
|
||||
|
||||
static void SetFarClip()
|
||||
static void SetClipPlanes()
|
||||
{
|
||||
tr.viewParms.zNear = 1.0f;
|
||||
|
||||
// if not rendering the world (icons, menus, etc)
|
||||
// set a 2k far clip plane
|
||||
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
|
||||
tr.viewParms.zFar = 2048;
|
||||
tr.viewParms.zFar = 2048.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -614,37 +639,37 @@ static void R_SetupProjection()
|
|||
float zNear, zFar;
|
||||
|
||||
// dynamically compute far clip plane distance
|
||||
SetFarClip();
|
||||
SetClipPlanes();
|
||||
|
||||
//
|
||||
// set up projection matrix
|
||||
//
|
||||
zNear = 1.0f;
|
||||
zNear = tr.viewParms.zNear;
|
||||
zFar = tr.viewParms.zFar;
|
||||
|
||||
height = 2.0f * zNear * tan( tr.refdef.fov_y * M_PI / 360.0f );
|
||||
width = 2.0f * zNear * tan( tr.refdef.fov_x * M_PI / 360.0f );
|
||||
depth = zFar - zNear;
|
||||
|
||||
tr.viewParms.projectionMatrix[0] = 2 * zNear / width;
|
||||
tr.viewParms.projectionMatrix[4] = 0;
|
||||
tr.viewParms.projectionMatrix[8] = 0;
|
||||
tr.viewParms.projectionMatrix[12] = 0;
|
||||
tr.viewParms.projectionMatrix[ 0] = 2.0f * zNear / width;
|
||||
tr.viewParms.projectionMatrix[ 4] = 0.0f;
|
||||
tr.viewParms.projectionMatrix[ 8] = 0.0f;
|
||||
tr.viewParms.projectionMatrix[12] = 0.0f;
|
||||
|
||||
tr.viewParms.projectionMatrix[1] = 0;
|
||||
tr.viewParms.projectionMatrix[5] = 2 * zNear / height;
|
||||
tr.viewParms.projectionMatrix[9] = 0;
|
||||
tr.viewParms.projectionMatrix[13] = 0;
|
||||
tr.viewParms.projectionMatrix[ 1] = 0.0f;
|
||||
tr.viewParms.projectionMatrix[ 5] = 2.0f * zNear / height;
|
||||
tr.viewParms.projectionMatrix[ 9] = 0.0f;
|
||||
tr.viewParms.projectionMatrix[13] = 0.0f;
|
||||
|
||||
tr.viewParms.projectionMatrix[2] = 0;
|
||||
tr.viewParms.projectionMatrix[6] = 0;
|
||||
tr.viewParms.projectionMatrix[ 2] = 0.0f;
|
||||
tr.viewParms.projectionMatrix[ 6] = 0.0f;
|
||||
tr.viewParms.projectionMatrix[10] = zNear / depth;
|
||||
tr.viewParms.projectionMatrix[14] = zFar * zNear / depth;
|
||||
|
||||
tr.viewParms.projectionMatrix[3] = 0;
|
||||
tr.viewParms.projectionMatrix[7] = 0;
|
||||
tr.viewParms.projectionMatrix[11] = -1;
|
||||
tr.viewParms.projectionMatrix[15] = 0;
|
||||
tr.viewParms.projectionMatrix[ 3] = 0.0f;
|
||||
tr.viewParms.projectionMatrix[ 7] = 0.0f;
|
||||
tr.viewParms.projectionMatrix[11] = -1.0f;
|
||||
tr.viewParms.projectionMatrix[15] = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,44 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2022-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 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 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 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 Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// compiles core shaders as byte code to be embedded into the CNQ3 client
|
||||
|
||||
|
||||
#include <Windows.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <shlwapi.h>
|
||||
#include <sal.h>
|
||||
|
||||
#include "../renderer/uber_shaders.h"
|
||||
#include "../renderer/grp_uber_shaders.h"
|
||||
|
||||
|
||||
char repoPath[MAX_PATH];
|
||||
char outputPath[MAX_PATH];
|
||||
char bin2headerPath[MAX_PATH];
|
||||
char dxcPath[MAX_PATH];
|
||||
|
||||
const char* targetVS = "vs_6_0";
|
||||
const char* targetPS = "ps_6_0";
|
||||
const char* targetCS = "cs_6_0";
|
||||
|
||||
|
||||
#define PS(Data) #Data,
|
||||
|
@ -22,7 +57,7 @@ const char* uberShaderPixelStates[] =
|
|||
// -Wno-warning disables the warning
|
||||
|
||||
|
||||
const char* va(const char* format, ...)
|
||||
const char* va(_Printf_format_string_ const char* format, ...)
|
||||
{
|
||||
static char string[64][32000];
|
||||
static int index = 0;
|
||||
|
@ -49,12 +84,14 @@ void CompileShader(const ShaderArgs& args, int extraCount = 0, const char** extr
|
|||
{
|
||||
static char temp[4096];
|
||||
|
||||
const char* headerPath = va("%s\\%s", outputPath, args.headerPath);
|
||||
|
||||
// -Ges: Enable strict mode
|
||||
// -Gis: Force IEEE strictness
|
||||
// -Zi: Embed debug info
|
||||
// -Qembed_debug: Embed debug info in shader container
|
||||
strcpy(temp, va("dxc.exe -Fh %s -E %s -T %s -WX -Ges -Gis -Zi -Qembed_debug",
|
||||
args.headerPath, args.entryPoint, args.targetProfile));
|
||||
strcpy(temp, va("%s -Fh %s -E %s -T %s -WX -Ges -Gis -Zi -Qembed_debug",
|
||||
dxcPath, headerPath, args.entryPoint, args.targetProfile));
|
||||
|
||||
for(int i = 0; i < extraCount; ++i)
|
||||
{
|
||||
|
@ -93,7 +130,7 @@ void CompileSMAAShader(const SMAAArgs& smaaArgs)
|
|||
args.entryPoint = smaaArgs.vertexShader ? "vs" : "ps";
|
||||
args.headerPath = smaaArgs.headerPath;
|
||||
args.shaderPath = smaaArgs.shaderPath;
|
||||
args.targetProfile = smaaArgs.vertexShader ? "vs_6_0" : "ps_6_0";
|
||||
args.targetProfile = smaaArgs.vertexShader ? targetVS : targetPS;
|
||||
CompileShader(args, _countof(extras), extras);
|
||||
}
|
||||
|
||||
|
@ -130,7 +167,7 @@ void CompileVS(const char* headerPath, const char* shaderPath)
|
|||
args.entryPoint = "vs";
|
||||
args.headerPath = headerPath;
|
||||
args.shaderPath = shaderPath;
|
||||
args.targetProfile = "vs_6_0";
|
||||
args.targetProfile = targetVS;
|
||||
CompileShader(args, _countof(extras), extras);
|
||||
}
|
||||
|
||||
|
@ -142,7 +179,7 @@ void CompilePS(const char* headerPath, const char* shaderPath)
|
|||
args.entryPoint = "ps";
|
||||
args.headerPath = headerPath;
|
||||
args.shaderPath = shaderPath;
|
||||
args.targetProfile = "ps_6_0";
|
||||
args.targetProfile = targetPS;
|
||||
CompileShader(args, _countof(extras), extras);
|
||||
}
|
||||
|
||||
|
@ -154,7 +191,7 @@ void CompileCS(const char* headerPath, const char* shaderPath)
|
|||
args.entryPoint = "cs";
|
||||
args.headerPath = headerPath;
|
||||
args.shaderPath = shaderPath;
|
||||
args.targetProfile = "cs_6_0";
|
||||
args.targetProfile = targetCS;
|
||||
CompileShader(args, _countof(extras), extras);
|
||||
}
|
||||
|
||||
|
@ -177,7 +214,7 @@ void CompileUberVS(const char* headerPath, const char* shaderPath, int stageCoun
|
|||
args.entryPoint = "vs";
|
||||
args.headerPath = headerPath;
|
||||
args.shaderPath = shaderPath;
|
||||
args.targetProfile = "vs_6_0";
|
||||
args.targetProfile = targetVS;
|
||||
CompileShader(args, _countof(extras), extras);
|
||||
}
|
||||
|
||||
|
@ -213,26 +250,38 @@ void CompileUberPS(const char* stateString)
|
|||
args.entryPoint = "ps";
|
||||
args.headerPath = va("uber_shader_ps_%s.h", stateString);
|
||||
args.shaderPath = "uber_shader.hlsl";
|
||||
args.targetProfile = "ps_6_0";
|
||||
args.targetProfile = targetPS;
|
||||
CompileShader(args, extraCount, extras);
|
||||
}
|
||||
|
||||
int main(int /*argc*/, const char** argv)
|
||||
const char* Canonicalize(const char* path)
|
||||
{
|
||||
char dirPath[MAX_PATH];
|
||||
strcpy(dirPath, argv[0]);
|
||||
int l = strlen(dirPath);
|
||||
while(l-- > 0)
|
||||
{
|
||||
if(dirPath[l] == '/' || dirPath[l] == '\\')
|
||||
{
|
||||
dirPath[l] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
SetCurrentDirectoryA(dirPath);
|
||||
static char canonPath[MAX_PATH];
|
||||
|
||||
system("del *.h");
|
||||
PathCanonicalizeA(canonPath, path);
|
||||
|
||||
return canonPath;
|
||||
}
|
||||
|
||||
void InitDirectory(const char* dirName)
|
||||
{
|
||||
const char* rendererPath = va("%s\\code\\renderer", repoPath);
|
||||
const char* cd = Canonicalize(va("%s\\shaders\\%s", rendererPath, dirName));
|
||||
SetCurrentDirectoryA(cd);
|
||||
const char* out = Canonicalize(va("%s\\compshaders\\%s", rendererPath, dirName));
|
||||
strcpy(outputPath, out);
|
||||
CreateDirectoryA(outputPath, NULL);
|
||||
|
||||
system(va("del %s\\*.h", outputPath));
|
||||
system(va("del %s\\*.temp", outputPath));
|
||||
}
|
||||
|
||||
void ProcessGRP()
|
||||
{
|
||||
InitDirectory("grp");
|
||||
targetVS = "vs_6_0";
|
||||
targetPS = "ps_6_0";
|
||||
targetCS = "cs_6_0";
|
||||
|
||||
CompileVSAndPS("post_gamma", "post_gamma.hlsl");
|
||||
CompileVSAndPS("post_inverse_gamma", "post_inverse_gamma.hlsl");
|
||||
|
@ -249,25 +298,91 @@ int main(int /*argc*/, const char** argv)
|
|||
CompileCS("mip_3_cs.h", "mip_3.hlsl");
|
||||
|
||||
CompileSMAAShaders();
|
||||
system("type smaa*.h > complete_smaa.h");
|
||||
system(va("type %s\\smaa*.h > %s\\complete_smaa.h", outputPath, outputPath));
|
||||
|
||||
system("type shared.hlsli uber_shader.hlsl > uber_shader.temp"); // combines both files into one
|
||||
system("..\\..\\..\\tools\\bin2header.exe --output uber_shader.h --hname uber_shader_string uber_shader.temp");
|
||||
system("del uber_shader.temp");
|
||||
// type combines all files into one
|
||||
system(va("type ..\\common\\state_bits.h.hlsli ..\\common\\blend.hlsli shared.hlsli uber_shader.hlsl > %s\\uber_shader.temp", outputPath));
|
||||
system(va("%s --output %s\\uber_shader.h --hname uber_shader_string %s\\uber_shader.temp", bin2headerPath, outputPath, outputPath));
|
||||
system(va("del %s\\uber_shader.temp", outputPath));
|
||||
|
||||
for(int i = 0; i < 8; ++i)
|
||||
{
|
||||
CompileUberVS(va("uber_shader_vs_%i.h", i + 1), "uber_shader.hlsl", i + 1);
|
||||
}
|
||||
system("type uber_shader_vs_*.h > complete_uber_vs.h");
|
||||
system("del uber_shader_vs_*.h");
|
||||
system(va("type %s\\uber_shader_vs_*.h > %s\\complete_uber_vs.h", outputPath, outputPath));
|
||||
system(va("del %s\\uber_shader_vs_*.h", outputPath));
|
||||
|
||||
for(int i = 0; i < _countof(uberShaderPixelStates); ++i)
|
||||
{
|
||||
CompileUberPS(uberShaderPixelStates[i]);
|
||||
}
|
||||
system("type uber_shader_ps_*.h > complete_uber_ps.h");
|
||||
system("del uber_shader_ps_*.h");
|
||||
system(va("type %s\\uber_shader_ps_*.h > %s\\complete_uber_ps.h", outputPath, outputPath));
|
||||
system(va("del %s\\uber_shader_ps_*.h", outputPath));
|
||||
}
|
||||
|
||||
void ProcessCRP()
|
||||
{
|
||||
InitDirectory("crp");
|
||||
targetVS = "vs_6_6";
|
||||
targetPS = "ps_6_6";
|
||||
targetCS = "cs_6_6";
|
||||
|
||||
CompileVSAndPS("blit", "blit.hlsl");
|
||||
CompileVSAndPS("ui", "ui.hlsl");
|
||||
CompileVSAndPS("imgui", "imgui.hlsl");
|
||||
CompileVSAndPS("nuklear", "nuklear.hlsl");
|
||||
CompileCS("mip_1_cs.h", "mip_1.hlsl");
|
||||
CompileCS("mip_2_cs.h", "mip_2.hlsl");
|
||||
CompileCS("mip_3_cs.h", "mip_3.hlsl");
|
||||
|
||||
CompileVSAndPS("opaque", "opaque.hlsl");
|
||||
CompileVSAndPS("transp_draw", "transp_draw.hlsl");
|
||||
CompileVSAndPS("transp_resolve", "transp_resolve.hlsl");
|
||||
CompileVSAndPS("tone_map", "tone_map.hlsl");
|
||||
CompileVSAndPS("tone_map_inverse", "tone_map_inverse.hlsl");
|
||||
CompileVSAndPS("accumdof_accum", "accumdof_accum.hlsl");
|
||||
CompileVSAndPS("accumdof_norm", "accumdof_norm.hlsl");
|
||||
CompileVSAndPS("accumdof_debug", "accumdof_debug.hlsl");
|
||||
CompileCS("gatherdof_split.h", "gatherdof_split.hlsl");
|
||||
CompileCS("gatherdof_coc_tile_gen.h", "gatherdof_coc_tile_gen.hlsl");
|
||||
CompileCS("gatherdof_coc_tile_max.h", "gatherdof_coc_tile_max.hlsl");
|
||||
CompileCS("gatherdof_blur.h", "gatherdof_blur.hlsl");
|
||||
CompileCS("gatherdof_fill.h", "gatherdof_fill.hlsl");
|
||||
CompileVSAndPS("gatherdof_combine", "gatherdof_combine.hlsl");
|
||||
CompileVSAndPS("gatherdof_debug", "gatherdof_debug.hlsl");
|
||||
CompileVSAndPS("fog_inside", "fog_inside.hlsl");
|
||||
CompileVSAndPS("fog_outside", "fog_outside.hlsl");
|
||||
}
|
||||
|
||||
int main(int /*argc*/, const char** argv)
|
||||
{
|
||||
char dirPath[MAX_PATH];
|
||||
strcpy(dirPath, argv[0]);
|
||||
int l = strlen(dirPath);
|
||||
while(l-- > 0)
|
||||
{
|
||||
if(dirPath[l] == '/' || dirPath[l] == '\\')
|
||||
{
|
||||
dirPath[l] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
strcpy(repoPath, Canonicalize(va("%s\\..\\..", dirPath)));
|
||||
strcpy(bin2headerPath, Canonicalize(va("%s\\tools\\bin2header.exe", repoPath)));
|
||||
|
||||
char* path = getenv("DXCPATH");
|
||||
if(path != NULL)
|
||||
{
|
||||
strcpy(dxcPath, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(dxcPath, "dxc.exe");
|
||||
}
|
||||
system(va("%s --version", dxcPath));
|
||||
|
||||
ProcessGRP();
|
||||
ProcessCRP();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
@echo off
|
||||
set fxc="%FXCPATH%"
|
||||
if "%FXCPATH%"=="" if not "%DXSDK_DIR%"=="" set fxc="%DXSDK_DIR%Utilities\\bin\\x86\\fxc.exe"
|
||||
if "%FXCPATH%"=="" if "%DXSDK_DIR%"=="" set fxc="C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.20348.0\\x64\\fxc.exe"
|
||||
%fxc% %*
|
|
@ -640,17 +640,9 @@ solution "cnq3"
|
|||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
AddSourcesAndHeaders("shadercomp")
|
||||
postbuildcommands { string.format("{copyfile} \"%%{cfg.buildtarget.directory}/%%{cfg.buildtarget.basename}.exe\" \"%s/renderer/hlsl\"", make_path_src) }
|
||||
postbuildcommands { string.format("{copyfile} \"%%{cfg.buildtarget.directory}/%%{cfg.buildtarget.basename}.pdb\" \"%s/renderer/hlsl\"", make_path_src) }
|
||||
postbuildcommands { string.format("\"%s/renderer/hlsl/%%{cfg.buildtarget.name}\"", make_path_src) }
|
||||
postbuildcommands { "$(TargetPath)" }
|
||||
ApplyProjectSettings(true)
|
||||
--[[
|
||||
VC++ STILL requires absolute paths for these... maybe it will be fixed a few decades after I'm in the grave
|
||||
local debug_path_dir = string.format("%s/renderer/hlsl", make_path_src)
|
||||
local debug_path_exe = string.format("%s/%%{cfg.buildtarget.name}", debug_path_dir)
|
||||
debugdir(debug_path_dir)
|
||||
debugcommand(debug_path_exe)
|
||||
--]]
|
||||
links { "Shlwapi" }
|
||||
|
||||
project "renderer"
|
||||
|
||||
|
@ -662,8 +654,8 @@ solution "cnq3"
|
|||
includedirs { "/usr/local/include" }
|
||||
end
|
||||
if os.istarget("windows") then
|
||||
files { string.format("%s/renderer/hlsl/*.hlsl", path_src) }
|
||||
files { string.format("%s/renderer/hlsl/*.hlsli", path_src) }
|
||||
files { string.format("%s/renderer/shaders/**.hlsl", path_src) }
|
||||
files { string.format("%s/renderer/shaders/**.hlsli", path_src) }
|
||||
filter "files:**.hlsl"
|
||||
flags { "ExcludeFromBuild" }
|
||||
filter { }
|
||||
|
@ -686,6 +678,8 @@ solution "cnq3"
|
|||
if os.istarget("windows") then
|
||||
includedirs { path_src.."/imgui" }
|
||||
libdirs { path_src.."/nvapi" }
|
||||
files { string.format("premake5.lua", path_make) }
|
||||
vpaths { ["*"] = "../code/" } -- don't allow "code" to be the parent filter
|
||||
end
|
||||
if os.istarget("bsd") then
|
||||
includedirs { "/usr/local/include" }
|
||||
|
|
|
@ -199,16 +199,18 @@ copy "..\..\.bin\release\cnq3.pdb" "$(QUAKE3DIR)"</Command>
|
|||
<ClInclude Include="..\..\code\qcommon\vm_local.h" />
|
||||
<ClInclude Include="..\..\code\qcommon\vm_shim.h" />
|
||||
<ClInclude Include="..\..\code\renderer\D3D12MemAlloc.h" />
|
||||
<ClInclude Include="..\..\code\renderer\crp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\grp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\grp_uber_shaders.h" />
|
||||
<ClInclude Include="..\..\code\renderer\rhi_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\rhi_public.h" />
|
||||
<ClInclude Include="..\..\code\renderer\smaa_area_texture.h" />
|
||||
<ClInclude Include="..\..\code\renderer\smaa_search_texture.h" />
|
||||
<ClInclude Include="..\..\code\renderer\srp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\stb_image.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_help.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_public.h" />
|
||||
<ClInclude Include="..\..\code\renderer\uber_shaders.h" />
|
||||
<ClInclude Include="..\..\code\server\server.h" />
|
||||
<ClInclude Include="..\..\code\win32\resource.h" />
|
||||
<ClInclude Include="..\..\code\win32\win_help.h" />
|
||||
|
@ -288,6 +290,9 @@ copy "..\..\.bin\release\cnq3.pdb" "$(QUAKE3DIR)"</Command>
|
|||
<ClCompile Include="..\..\code\win32\win_syscon.cpp" />
|
||||
<ClCompile Include="..\..\code\win32\win_wndproc.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\premake5.lua" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="botlib.vcxproj">
|
||||
<Project>{A1A792F4-8D49-BDCA-7604-D11E6245441B}</Project>
|
||||
|
|
|
@ -243,9 +243,15 @@
|
|||
<ClInclude Include="..\..\code\renderer\D3D12MemAlloc.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\crp_local.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\grp_local.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\grp_uber_shaders.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\rhi_local.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
|
@ -258,6 +264,9 @@
|
|||
<ClInclude Include="..\..\code\renderer\smaa_search_texture.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\srp_local.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\stb_image.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
|
@ -270,9 +279,6 @@
|
|||
<ClInclude Include="..\..\code\renderer\tr_public.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\uber_shaders.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\server\server.h">
|
||||
<Filter>server</Filter>
|
||||
</ClInclude>
|
||||
|
@ -504,4 +510,7 @@
|
|||
<Filter>win32</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\premake5.lua" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -112,28 +112,41 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\code\renderer\D3D12MemAlloc.h" />
|
||||
<ClInclude Include="..\..\code\renderer\crp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\grp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\grp_uber_shaders.h" />
|
||||
<ClInclude Include="..\..\code\renderer\rhi_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\rhi_public.h" />
|
||||
<ClInclude Include="..\..\code\renderer\smaa_area_texture.h" />
|
||||
<ClInclude Include="..\..\code\renderer\smaa_search_texture.h" />
|
||||
<ClInclude Include="..\..\code\renderer\srp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\stb_image.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_help.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_public.h" />
|
||||
<ClInclude Include="..\..\code\renderer\uber_shaders.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\code\renderer\D3D12MemAlloc.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_imgui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dof_accum.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dof_gather.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_fog.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_tone_map.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_draw.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_resolve.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_mip_gen.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_nuklear.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_post.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_smaa.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_ui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_world.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\rhi_d3d12.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_imgui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_mip_gen.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_nuklear.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_ui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\stb_image.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\tr_backend.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\tr_bsp.cpp" />
|
||||
|
@ -159,59 +172,141 @@
|
|||
<ClCompile Include="..\..\code\renderer\tr_world.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\accumdof_accum.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\accumdof_debug.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\accumdof_norm.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_outside.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\blit.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\imgui.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_inside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\mip_1.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_outside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\mip_2.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_blur.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\mip_3.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_coc_tile_gen.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\nuklear.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_coc_tile_max.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\post_gamma.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_combine.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\post_inverse_gamma.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_debug.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\smaa_1.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_fill.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\smaa_2.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_split.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\smaa_3.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\imgui.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\uber_shader.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_1.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\ui.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_2.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_3.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\nuklear.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\opaque.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map_inverse.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\transp_draw.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\transp_resolve.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\ui.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\depth_pre_pass.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\dynamic_light.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\fog_inside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\fog_outside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\imgui.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\mip_1.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\mip_2.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\mip_3.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\nuklear.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\post_gamma.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\post_inverse_gamma.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\smaa_1.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\smaa_2.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\smaa_3.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\uber_shader.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\ui.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\code\renderer\hlsl\fog.hlsli" />
|
||||
<None Include="..\..\code\renderer\hlsl\shared.hlsli" />
|
||||
<None Include="..\..\code\renderer\hlsl\smaa.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\common\blend.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\common\mip_gen.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\common\state_bits.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\common.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\dof.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\fog.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\gatherdof.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\oit.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\world.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\world.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\fog.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\shared.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\smaa.hlsli" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
|
@ -1,34 +1,56 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="hlsl">
|
||||
<UniqueIdentifier>{98F1977C-8428-990D-2D15-7F10192B150F}</UniqueIdentifier>
|
||||
<Filter Include="shaders">
|
||||
<UniqueIdentifier>{0F45D591-7B24-542D-843C-DF03F09ABA8E}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="shaders\common">
|
||||
<UniqueIdentifier>{873F6737-730D-5B3D-5CA1-CB63480E37A2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="shaders\crp">
|
||||
<UniqueIdentifier>{A3AE1A56-0F64-934B-9858-8D22040D8A4F}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="shaders\grp">
|
||||
<UniqueIdentifier>{A7BF1A56-1375-934B-9C69-8D22081E8A4F}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\code\renderer\D3D12MemAlloc.h" />
|
||||
<ClInclude Include="..\..\code\renderer\crp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\grp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\grp_uber_shaders.h" />
|
||||
<ClInclude Include="..\..\code\renderer\rhi_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\rhi_public.h" />
|
||||
<ClInclude Include="..\..\code\renderer\smaa_area_texture.h" />
|
||||
<ClInclude Include="..\..\code\renderer\smaa_search_texture.h" />
|
||||
<ClInclude Include="..\..\code\renderer\srp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\stb_image.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_help.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_public.h" />
|
||||
<ClInclude Include="..\..\code\renderer\uber_shaders.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\code\renderer\D3D12MemAlloc.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_imgui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dof_accum.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dof_gather.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_fog.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_tone_map.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_draw.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_resolve.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_mip_gen.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_nuklear.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_post.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_smaa.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_ui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_world.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\rhi_d3d12.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_imgui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_mip_gen.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_nuklear.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_ui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\stb_image.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\tr_backend.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\tr_bsp.cpp" />
|
||||
|
@ -54,64 +76,166 @@
|
|||
<ClCompile Include="..\..\code\renderer\tr_world.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\accumdof_accum.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\accumdof_debug.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\accumdof_norm.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_outside.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\blit.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\imgui.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_inside.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\mip_1.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_outside.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\mip_2.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_blur.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\mip_3.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_coc_tile_gen.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\nuklear.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_coc_tile_max.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\post_gamma.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_combine.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\post_inverse_gamma.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_debug.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\smaa_1.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_fill.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\smaa_2.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_split.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\smaa_3.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\imgui.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\uber_shader.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_1.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\ui.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_2.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_3.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\nuklear.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\opaque.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map_inverse.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\transp_draw.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\transp_resolve.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\ui.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\depth_pre_pass.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\dynamic_light.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\fog_inside.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\fog_outside.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\imgui.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\mip_1.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\mip_2.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\mip_3.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\nuklear.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\post_gamma.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\post_inverse_gamma.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\smaa_1.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\smaa_2.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\smaa_3.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\uber_shader.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\ui.hlsl">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\code\renderer\hlsl\fog.hlsli">
|
||||
<Filter>hlsl</Filter>
|
||||
<None Include="..\..\code\renderer\shaders\common\blend.hlsli">
|
||||
<Filter>shaders\common</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\hlsl\shared.hlsli">
|
||||
<Filter>hlsl</Filter>
|
||||
<None Include="..\..\code\renderer\shaders\common\mip_gen.hlsli">
|
||||
<Filter>shaders\common</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\hlsl\smaa.hlsli">
|
||||
<Filter>hlsl</Filter>
|
||||
<None Include="..\..\code\renderer\shaders\common\state_bits.h.hlsli">
|
||||
<Filter>shaders\common</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\common.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\dof.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\fog.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\gatherdof.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\oit.h.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\world.h.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\world.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\grp\fog.hlsli">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\grp\shared.hlsli">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\grp\smaa.hlsli">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -72,13 +72,12 @@
|
|||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\.build\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions> %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /B /Y "$(TargetDir)\$(TargetName).exe" "..\..\code\renderer\hlsl"
|
||||
copy /B /Y "$(TargetDir)\$(TargetName).pdb" "..\..\code\renderer\hlsl"
|
||||
"../../code/renderer/hlsl/$(TargetFileName)"</Command>
|
||||
<Command>$(TargetPath)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release|x64'">
|
||||
|
@ -107,13 +106,12 @@ copy /B /Y "$(TargetDir)\$(TargetName).pdb" "..\..\code\renderer\hlsl"
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\.build\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions> %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /B /Y "$(TargetDir)\$(TargetName).exe" "..\..\code\renderer\hlsl"
|
||||
copy /B /Y "$(TargetDir)\$(TargetName).pdb" "..\..\code\renderer\hlsl"
|
||||
"../../code/renderer/hlsl/$(TargetFileName)"</Command>
|
||||
<Command>$(TargetPath)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -201,16 +201,18 @@ copy "..\..\.bin\release\cnq3.pdb" "$(QUAKE3DIR)"</Command>
|
|||
<ClInclude Include="..\..\code\qcommon\vm_local.h" />
|
||||
<ClInclude Include="..\..\code\qcommon\vm_shim.h" />
|
||||
<ClInclude Include="..\..\code\renderer\D3D12MemAlloc.h" />
|
||||
<ClInclude Include="..\..\code\renderer\crp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\grp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\grp_uber_shaders.h" />
|
||||
<ClInclude Include="..\..\code\renderer\rhi_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\rhi_public.h" />
|
||||
<ClInclude Include="..\..\code\renderer\smaa_area_texture.h" />
|
||||
<ClInclude Include="..\..\code\renderer\smaa_search_texture.h" />
|
||||
<ClInclude Include="..\..\code\renderer\srp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\stb_image.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_help.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_public.h" />
|
||||
<ClInclude Include="..\..\code\renderer\uber_shaders.h" />
|
||||
<ClInclude Include="..\..\code\server\server.h" />
|
||||
<ClInclude Include="..\..\code\win32\resource.h" />
|
||||
<ClInclude Include="..\..\code\win32\win_help.h" />
|
||||
|
@ -290,6 +292,9 @@ copy "..\..\.bin\release\cnq3.pdb" "$(QUAKE3DIR)"</Command>
|
|||
<ClCompile Include="..\..\code\win32\win_syscon.cpp" />
|
||||
<ClCompile Include="..\..\code\win32\win_wndproc.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\premake5.lua" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="botlib.vcxproj">
|
||||
<Project>{A1A792F4-8D49-BDCA-7604-D11E6245441B}</Project>
|
||||
|
|
|
@ -243,9 +243,15 @@
|
|||
<ClInclude Include="..\..\code\renderer\D3D12MemAlloc.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\crp_local.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\grp_local.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\grp_uber_shaders.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\rhi_local.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
|
@ -258,6 +264,9 @@
|
|||
<ClInclude Include="..\..\code\renderer\smaa_search_texture.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\srp_local.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\stb_image.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
|
@ -270,9 +279,6 @@
|
|||
<ClInclude Include="..\..\code\renderer\tr_public.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\renderer\uber_shaders.h">
|
||||
<Filter>renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\code\server\server.h">
|
||||
<Filter>server</Filter>
|
||||
</ClInclude>
|
||||
|
@ -504,4 +510,7 @@
|
|||
<Filter>win32</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\premake5.lua" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -114,28 +114,41 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\code\renderer\D3D12MemAlloc.h" />
|
||||
<ClInclude Include="..\..\code\renderer\crp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\grp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\grp_uber_shaders.h" />
|
||||
<ClInclude Include="..\..\code\renderer\rhi_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\rhi_public.h" />
|
||||
<ClInclude Include="..\..\code\renderer\smaa_area_texture.h" />
|
||||
<ClInclude Include="..\..\code\renderer\smaa_search_texture.h" />
|
||||
<ClInclude Include="..\..\code\renderer\srp_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\stb_image.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_help.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_local.h" />
|
||||
<ClInclude Include="..\..\code\renderer\tr_public.h" />
|
||||
<ClInclude Include="..\..\code\renderer\uber_shaders.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\code\renderer\D3D12MemAlloc.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_imgui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dof_accum.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dof_gather.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_fog.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_tone_map.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_draw.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_resolve.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_mip_gen.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_nuklear.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_post.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_smaa.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_ui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_world.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\rhi_d3d12.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_imgui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_mip_gen.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_nuklear.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\srp_ui.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\stb_image.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\tr_backend.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\tr_bsp.cpp" />
|
||||
|
@ -161,59 +174,141 @@
|
|||
<ClCompile Include="..\..\code\renderer\tr_world.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\accumdof_accum.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\accumdof_debug.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\accumdof_norm.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_outside.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\blit.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\imgui.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_inside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\mip_1.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_outside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\mip_2.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_blur.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\mip_3.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_coc_tile_gen.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\nuklear.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_coc_tile_max.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\post_gamma.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_combine.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\post_inverse_gamma.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_debug.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\smaa_1.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_fill.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\smaa_2.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gatherdof_split.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\smaa_3.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\imgui.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\uber_shader.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_1.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\ui.hlsl">
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_2.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_3.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\nuklear.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\opaque.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map_inverse.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\transp_draw.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\transp_resolve.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\ui.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\depth_pre_pass.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\dynamic_light.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\fog_inside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\fog_outside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\imgui.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\mip_1.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\mip_2.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\mip_3.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\nuklear.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\post_gamma.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\post_inverse_gamma.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\smaa_1.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\smaa_2.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\smaa_3.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\uber_shader.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\grp\ui.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\code\renderer\hlsl\fog.hlsli" />
|
||||
<None Include="..\..\code\renderer\hlsl\shared.hlsli" />
|
||||
<None Include="..\..\code\renderer\hlsl\smaa.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\common\blend.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\common\mip_gen.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\common\state_bits.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\common.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\dof.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\fog.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\gatherdof.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\oit.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\world.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\world.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\fog.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\shared.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\smaa.hlsli" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue