From fd035c0f7042a2839854fc1e705931cefa363058 Mon Sep 17 00:00:00 2001 From: myT <> Date: Thu, 3 Aug 2023 02:38:29 +0200 Subject: [PATCH] added r_shadingRate --- code/renderer/grp_local.h | 2 + code/renderer/grp_world.cpp | 39 ++++++++++++++++++ code/renderer/rhi_d3d12.cpp | 80 +++++++++++++++++++++++++++++++++++-- code/renderer/rhi_local.h | 18 +++++++++ code/renderer/tr_help.h | 17 ++++++++ code/renderer/tr_init.cpp | 2 + code/renderer/tr_local.h | 1 + 7 files changed, 155 insertions(+), 4 deletions(-) diff --git a/code/renderer/grp_local.h b/code/renderer/grp_local.h index c3ad19b..eeb7db1 100644 --- a/code/renderer/grp_local.h +++ b/code/renderer/grp_local.h @@ -360,6 +360,8 @@ struct World int psoChangeCount; bool batchDepthHack; bool batchOldDepthHack; + ShadingRate::Id batchShadingRate; + ShadingRate::Id batchOldShadingRate; // dynamic GeometryBuffers dynBuffers[FrameCount]; diff --git a/code/renderer/grp_world.cpp b/code/renderer/grp_world.cpp index 06f9dfc..06070df 100644 --- a/code/renderer/grp_world.cpp +++ b/code/renderer/grp_world.cpp @@ -399,6 +399,8 @@ void World::Begin() CmdSetViewportAndScissor(backEnd.viewParms); batchOldDepthHack = false; batchDepthHack = false; + batchOldShadingRate = ShadingRate::SR_1x1; + batchShadingRate = ShadingRate::SR_1x1; TextureBarrier tb(depthTexture, ResourceStates::DepthWriteBit); CmdBarrier(1, &tb); @@ -562,6 +564,12 @@ void World::EndBatch() batchOldDepthHack = batchDepthHack; } + if(batchShadingRate != batchOldShadingRate) + { + CmdSetShadingRate(batchShadingRate); + batchOldShadingRate = batchShadingRate; + } + for(int p = 0; p < shader->numPipelines; ++p) { const pipeline_t& pipeline = shader->pipelines[p]; @@ -631,6 +639,8 @@ void World::EndSkyBatch() SCOPED_RENDER_PASS("Sky", 0.0, 0.5f, 1.0f); + CmdSetShadingRate(ShadingRate::SR_1x1); + const viewParms_t& vp = backEnd.viewParms; CmdSetViewport(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight, 0.0f, 0.0f); RB_DrawSky(); @@ -640,6 +650,8 @@ void World::EndSkyBatch() batchOldDepthHack = false; batchDepthHack = false; + batchOldShadingRate = ShadingRate::SR_1x1; + batchShadingRate = ShadingRate::SR_1x1; } void World::RestartBatch() @@ -920,6 +932,10 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd) bool oldHasStaticGeo = false; backEnd.currentEntity = &tr.worldEntity; + ShadingRate::Id lowShadingRate = (ShadingRate::Id)r_shadingRate->integer; + batchShadingRate = ShadingRate::SR_1x1; + batchOldShadingRate = ShadingRate::SR_1x1; + int ds; const drawSurf_t* drawSurf; for(ds = 0, drawSurf = drawSurfs; ds < surfCount; ++ds, ++drawSurf) @@ -929,6 +945,8 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd) EndSkyBatch(); EndBatch(); + CmdSetShadingRate(lowShadingRate); + batchOldShadingRate = lowShadingRate; DrawFog(); if(transpCount > 0) @@ -982,6 +1000,7 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd) EndBatch(); BeginBatch(shader, hasStaticGeo); tess.greyscale = drawSurf->greyscale; + batchShadingRate = lowShadingRate; } if(entityChanged) @@ -996,6 +1015,7 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd) { EndBatch(); BeginBatch(tess.shader, batchHasStaticGeo); + batchShadingRate = lowShadingRate; } memcpy(tess.indexes + tess.numIndexes, statIndices + chunk.firstCPUIndex, chunk.indexCount * sizeof(uint32_t)); @@ -1005,6 +1025,19 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd) { R_TessellateSurface(drawSurf->surface); } + + // we want full rate for nopicmipped sprites and nopicmipped alpha tests + if((shader->imgflags & IMG_NOPICMIP) != 0) + { + if(entityNum != ENTITYNUM_WORLD && tr.refdef.entities[entityNum].e.reType == RT_SPRITE) + { + batchShadingRate = ShadingRate::SR_1x1; + } + else if(shader->isAlphaTestedOpaque) + { + batchShadingRate = ShadingRate::SR_1x1; + } + } } backEnd.refdef.floatTime = originalTime; @@ -1012,6 +1045,8 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd) EndSkyBatch(); EndBatch(); + CmdSetShadingRate(ShadingRate::SR_1x1); + if(transpCount <= 0) { DrawFog(); @@ -1024,6 +1059,10 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd) CmdSetViewportAndScissor(backEnd.viewParms); batchOldDepthHack = false; batchDepthHack = false; + + CmdSetShadingRate(ShadingRate::SR_1x1); + batchOldShadingRate = ShadingRate::SR_1x1; + batchShadingRate = ShadingRate::SR_1x1; } void World::BindVertexBuffers(bool staticGeo, uint32_t firstStage, uint32_t stageCount) diff --git a/code/renderer/rhi_d3d12.cpp b/code/renderer/rhi_d3d12.cpp index 2c3d769..cc0308a 100644 --- a/code/renderer/rhi_d3d12.cpp +++ b/code/renderer/rhi_d3d12.cpp @@ -533,11 +533,11 @@ namespace RHI IDXGISwapChain3* swapChain; HTexture renderTargets[FrameCount]; ID3D12CommandAllocator* mainCommandAllocators[FrameCount]; - ID3D12GraphicsCommandList* mainCommandList; + ID3D12GraphicsCommandList6* mainCommandList; ID3D12CommandAllocator* tempCommandAllocator; - ID3D12GraphicsCommandList* tempCommandList; + ID3D12GraphicsCommandList6* tempCommandList; bool tempCommandListOpen; - ID3D12GraphicsCommandList* commandList; // not owned, don't release it! + ID3D12GraphicsCommandList6* commandList; // not owned, don't release it! uint32_t swapChainBufferCount; uint32_t renderFrameCount; HANDLE frameLatencyWaitableObject; @@ -555,6 +555,8 @@ namespace RHI bool isTearingSupported; bool vsync; bool frameBegun; + bool baseVRSSupport; + bool extendedVRSSupport; HMODULE dxcModule; HMODULE dxilModule; @@ -1646,6 +1648,21 @@ namespace RHI } } + D3D12_SHADING_RATE GetD3DShadingRate(ShadingRate::Id shadingRate) + { + switch(shadingRate) + { + case ShadingRate::SR_1x1: return D3D12_SHADING_RATE_1X1; + case ShadingRate::SR_1x2: return D3D12_SHADING_RATE_1X2; + case ShadingRate::SR_2x1: return D3D12_SHADING_RATE_2X1; + case ShadingRate::SR_2x2: return D3D12_SHADING_RATE_2X2; + case ShadingRate::SR_2x4: return D3D12_SHADING_RATE_2X4; + case ShadingRate::SR_4x2: return D3D12_SHADING_RATE_4X2; + case ShadingRate::SR_4x4: return D3D12_SHADING_RATE_4X4; + default: Q_assert(!"Unsupported shading rate"); return D3D12_SHADING_RATE_1X1; + } + } + static D3D12_BLEND GetAlphaBlendFromColorBlend(D3D12_BLEND colorBlend) { switch(colorBlend) @@ -2178,7 +2195,23 @@ namespace RHI case D3D12_RAYTRACING_TIER_1_1: tier = "1.1"; default: break; } - TableRow(2, "Raytracing tier (DXR)", tier); + TableRow(2, "Raytracing (DXR) tier", tier); + } + + D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = { 0 }; + if(SUCCEEDED(rhi.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, sizeof(options6)))) + { + const char* tier = "Unknown"; + switch(options6.VariableShadingRateTier) + { + case D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED: tier = "N/A"; + case D3D12_VARIABLE_SHADING_RATE_TIER_1: tier = "1"; + case D3D12_VARIABLE_SHADING_RATE_TIER_2: tier = "2"; + default: break; + } + TableRow(2, "Variable shading rate (VRS) tier", tier); + + TableRow(2, "VRS: 2x4, 4x2, 4x4 support", options6.AdditionalShadingRatesSupported ? "YES" : "NO"); } NvU64 cvvTotal, cvvFree; @@ -2710,6 +2743,19 @@ namespace RHI D3D(dxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&rhi.dxcUtils))); D3D(dxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&rhi.dxcCompiler))); + { + D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {}; + if(SUCCEEDED(rhi.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, sizeof(options6)))) + { + rhi.baseVRSSupport = options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED; + rhi.extendedVRSSupport = rhi.baseVRSSupport && options6.AdditionalShadingRatesSupported; + } + + const char* modeLists[] = { "1x1", "1x1 2x1 1x2 2x2", "1x1 2x1 1x2 2x2 4x2 2x4 4x4" }; + const int listIndex = rhi.extendedVRSSupport ? 2 : (rhi.baseVRSSupport ? 1 : 0); + ri.Printf(PRINT_ALL, "Supported VRS modes: %s\n", modeLists[listIndex]); + } + glInfo.maxTextureSize = MAX_TEXTURE_SIZE; glInfo.maxAnisotropy = 16; glInfo.depthFadeSupport = qfalse; @@ -4273,6 +4319,32 @@ namespace RHI rhi.commandList->CopyBufferRegion(dst.buffer, 0, src.buffer, 0, byteCount); } + void CmdSetShadingRate(ShadingRate::Id shadingRate) + { + Q_assert(CanWriteCommands()); + + if(!rhi.baseVRSSupport) + { + return; + } + + if(!rhi.extendedVRSSupport) + { + switch(shadingRate) + { + case ShadingRate::SR_2x4: + case ShadingRate::SR_4x2: + case ShadingRate::SR_4x4: + shadingRate = ShadingRate::SR_2x2; + break; + default: + break; + } + } + + rhi.commandList->RSSetShadingRate(GetD3DShadingRate(shadingRate), NULL); + } + uint32_t GetDurationCount() { return rhi.resolvedQueries.durationQueryCount; diff --git a/code/renderer/rhi_local.h b/code/renderer/rhi_local.h index 17cc8b9..5c3b4e4 100644 --- a/code/renderer/rhi_local.h +++ b/code/renderer/rhi_local.h @@ -234,6 +234,23 @@ namespace RHI }; }; + struct ShadingRate + { + enum Id + { + // Guaranteed modes: + SR_1x1, + SR_2x1, + SR_1x2, + SR_2x2, + // Additional modes: + SR_4x2, + SR_2x4, + SR_4x4, + Count + }; + }; + struct RootSignatureDesc { RootSignatureDesc() = default; @@ -716,6 +733,7 @@ namespace RHI void CmdEndDebugLabel(); void CmdSetStencilReference(uint8_t stencilRef); void CmdCopyBuffer(HBuffer dest, HBuffer source); + void CmdSetShadingRate(ShadingRate::Id shadingRate); #if 0 void CmdClearUAV(HTexture htexture, uint32_t mip); diff --git a/code/renderer/tr_help.h b/code/renderer/tr_help.h index 62f83da..08fc37b 100644 --- a/code/renderer/tr_help.h +++ b/code/renderer/tr_help.h @@ -142,6 +142,23 @@ S_COLOR_VAL " 2 " S_COLOR_HELP "= None" S_COLOR_VAL "2500 " S_COLOR_HELP "should be enough to deal with delayed thread wake-ups.\n" \ "Use the frame graph to confirm that higher values help on your system." +#define help_r_shadingRate \ +"variable-rate shading (VRS) mode\n" \ +S_COLOR_VAL " 0 " S_COLOR_HELP "= 1x1 (VRS off)\n" \ +S_COLOR_VAL " 1 " S_COLOR_HELP "= 2x1 (base mode)\n" \ +S_COLOR_VAL " 2 " S_COLOR_HELP "= 1x2 (base mode)\n" \ +S_COLOR_VAL " 3 " S_COLOR_HELP "= 2x2 (base mode)\n" \ +S_COLOR_VAL " 4 " S_COLOR_HELP "= 4x2 (extended mode)\n" \ +S_COLOR_VAL " 5 " S_COLOR_HELP "= 2x4 (extended mode)\n" \ +S_COLOR_VAL " 6 " S_COLOR_HELP "= 4x4 (extended mode)\n" \ +"The numbers are the horizontal and vertical subsampling factors.\n" \ +"1x1 is forced for the sky, nopicmipped sprites (e.g. simple items)\n" \ +"and nopicmipped alpha tested surfaces (e.g. grates).\n" \ +"If extended modes are not supported, 2x2 is used instead.\n" \ +"Prefer horizontal subsampling as many maps have textures\n" \ +"with thin horizontal lines, which become an aliased mess when\n" \ +"vertically subsampled." + #define help_r_ignoreShaderSortKey \ "ignores the shader sort key of transparent surfaces\n" \ "Instead, it sorts by depth and original registration order only.\n" \ diff --git a/code/renderer/tr_init.cpp b/code/renderer/tr_init.cpp index dc88735..e0c946c 100644 --- a/code/renderer/tr_init.cpp +++ b/code/renderer/tr_init.cpp @@ -60,6 +60,7 @@ cvar_t *r_mapGreyscale; cvar_t *r_mapGreyscaleCTF; cvar_t *r_teleporterFlash; cvar_t *r_sleepThreshold; +cvar_t *r_shadingRate; cvar_t *r_novis; cvar_t *r_nocull; cvar_t *r_nocurves; @@ -392,6 +393,7 @@ static const cvarTableItem_t r_cvars[] = { &r_mapGreyscaleCTF, "r_mapGreyscaleCTF", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "1", help_r_mapGreyscaleCTF }, { &r_teleporterFlash, "r_teleporterFlash", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "draws bright colors when being teleported" }, { &r_sleepThreshold, "r_sleepThreshold", "2500", CVAR_ARCHIVE, CVART_INTEGER, "2000", "4000", help_r_sleepThreshold }, + { &r_shadingRate, "r_shadingRate", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "6", help_r_shadingRate }, // // temporary variables that can change at any time diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index e6de826..8d3f561 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -1061,6 +1061,7 @@ extern cvar_t *r_mapGreyscale; // how monochrome the map looks extern cvar_t *r_mapGreyscaleCTF; // how monochrome CTF map surfaces look extern cvar_t *r_teleporterFlash; // 1 is default Q3 behavior, 0 is pure black extern cvar_t *r_sleepThreshold; // time cushion in us for a call to Sleep(1+) +extern cvar_t *r_shadingRate; // variable-rate shading (VRS) mode extern cvar_t *r_fullbright; // avoid lightmap pass extern cvar_t *r_depthFade; // fades marked shaders based on depth extern cvar_t *r_dither; // enables dithering