Implement dynamic depth bias.

This commit is contained in:
Skyth 2025-01-14 23:57:01 +03:00
parent 3b9e072ecb
commit 05cfd9e85c
7 changed files with 90 additions and 16 deletions

View file

@ -1815,6 +1815,11 @@ namespace plume {
}
}
void D3D12CommandList::setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) {
assert(device->capabilities.dynamicDepthBias && "Dynamic depth bias is unsupported on this device.");
d3d->RSSetDepthBias(depthBias, depthBiasClamp, slopeScaledDepthBias);
}
void D3D12CommandList::clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) {
assert(targetFramebuffer != nullptr);
assert(attachmentIndex < targetFramebuffer->colorTargets.size());
@ -2718,6 +2723,10 @@ namespace plume {
psoDesc.RasterizerState.DepthBias = desc.depthBias;
psoDesc.RasterizerState.SlopeScaledDepthBias = desc.slopeScaledDepthBias;
if (desc.dynamicDepthBiasEnabled) {
psoDesc.Flags |= D3D12_PIPELINE_STATE_FLAG_DYNAMIC_DEPTH_BIAS;
}
switch (desc.cullMode) {
case RenderCullMode::NONE:
psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
@ -3307,6 +3316,14 @@ namespace plume {
triangleFanSupportOption = d3d12Options15.TriangleFanSupported;
}
// Check if dynamic depth bias is supported.
bool dynamicDepthBiasOption = false;
D3D12_FEATURE_DATA_D3D12_OPTIONS16 d3d12Options16 = {};
res = deviceOption->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS16, &d3d12Options16, sizeof(d3d12Options16));
if (SUCCEEDED(res)) {
dynamicDepthBiasOption = d3d12Options16.DynamicDepthBiasSupported;
}
// Pick this adapter and device if it has better feature support than the current one.
bool preferOverNothing = (adapter == nullptr) || (d3d == nullptr);
bool preferVideoMemory = adapterDesc.DedicatedVideoMemory > description.dedicatedVideoMemory;
@ -3328,6 +3345,7 @@ namespace plume {
capabilities.raytracingStateUpdate = rtStateUpdateSupportOption;
capabilities.sampleLocations = samplePositionsOption;
capabilities.triangleFan = triangleFanSupportOption;
capabilities.dynamicDepthBias = dynamicDepthBiasOption;
description.name = Utf16ToUtf8(adapterDesc.Description);
description.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory;

View file

@ -145,7 +145,7 @@ namespace plume {
};
struct D3D12CommandList : RenderCommandList {
ID3D12GraphicsCommandList4 *d3d = nullptr;
ID3D12GraphicsCommandList9 *d3d = nullptr;
ID3D12CommandAllocator *commandAllocator = nullptr;
D3D12Device *device = nullptr;
RenderCommandListType type = RenderCommandListType::UNKNOWN;
@ -184,6 +184,7 @@ namespace plume {
void setViewports(const RenderViewport *viewports, uint32_t count) override;
void setScissors(const RenderRect *scissorRects, uint32_t count) override;
void setFramebuffer(const RenderFramebuffer *framebuffer) override;
void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) override;
void clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) override;
void clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) override;
void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) override;

View file

@ -135,6 +135,7 @@ namespace plume {
virtual void setViewports(const RenderViewport *viewports, uint32_t count) = 0;
virtual void setScissors(const RenderRect *scissorRects, uint32_t count) = 0;
virtual void setFramebuffer(const RenderFramebuffer *framebuffer) = 0;
virtual void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) = 0;
virtual void clearColor(uint32_t attachmentIndex = 0, RenderColor colorValue = RenderColor(), const RenderRect *clearRects = nullptr, uint32_t clearRectsCount = 0) = 0;
virtual void clearDepth(bool clearDepth = true, float depthValue = 1.0f, const RenderRect *clearRects = nullptr, uint32_t clearRectsCount = 0) = 0;
virtual void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) = 0;

View file

@ -1171,6 +1171,7 @@ namespace plume {
bool depthClipEnabled = false;
int32_t depthBias = 0;
float slopeScaledDepthBias = 0.0f;
bool dynamicDepthBiasEnabled = false;
bool depthEnabled = false;
bool depthWriteEnabled = false;
RenderMultisampling multisampling;
@ -1778,6 +1779,7 @@ namespace plume {
// Draw.
bool triangleFan = false;
bool dynamicDepthBias = false;
};
struct RenderInterfaceCapabilities {

View file

@ -1432,7 +1432,10 @@ namespace plume {
rasterization.cullMode = toVk(desc.cullMode);
rasterization.frontFace = VK_FRONT_FACE_CLOCKWISE;
if (desc.depthBias != 0 || desc.slopeScaledDepthBias != 0.0f) {
if (desc.dynamicDepthBiasEnabled) {
rasterization.depthBiasEnable = true;
}
else if (desc.depthBias != 0 || desc.slopeScaledDepthBias != 0.0f) {
rasterization.depthBiasEnable = true;
rasterization.depthBiasConstantFactor = float(desc.depthBias);
rasterization.depthBiasSlopeFactor = desc.slopeScaledDepthBias;
@ -1510,6 +1513,10 @@ namespace plume {
dynamicStates.emplace_back(VK_DYNAMIC_STATE_VIEWPORT);
dynamicStates.emplace_back(VK_DYNAMIC_STATE_SCISSOR);
if (desc.dynamicDepthBiasEnabled) {
dynamicStates.emplace_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
}
VkPipelineDynamicStateCreateInfo dynamicState = {};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.pDynamicStates = dynamicStates.data();
@ -2848,6 +2855,10 @@ namespace plume {
}
}
void VulkanCommandList::setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) {
vkCmdSetDepthBias(vk, depthBias, depthBiasClamp, slopeScaledDepthBias);
}
static void clearCommonRectVector(uint32_t width, uint32_t height, const RenderRect *clearRects, uint32_t clearRectsCount, std::vector<VkClearRect> &rectVector) {
rectVector.clear();
@ -3783,6 +3794,7 @@ namespace plume {
capabilities.displayTiming = supportedOptionalExtensions.find(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME) != supportedOptionalExtensions.end();
capabilities.preferHDR = memoryHeapSize > (512 * 1024 * 1024);
capabilities.triangleFan = true;
capabilities.dynamicDepthBias = true;
// Fill Vulkan-only capabilities.
loadStoreOpNoneSupported = supportedOptionalExtensions.find(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME) != supportedOptionalExtensions.end();

View file

@ -307,6 +307,7 @@ namespace plume {
void setViewports(const RenderViewport *viewports, uint32_t count) override;
void setScissors(const RenderRect *scissorRects, uint32_t count) override;
void setFramebuffer(const RenderFramebuffer *framebuffer) override;
void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) override;
void clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) override;
void clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) override;
void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) override;

View file

@ -131,12 +131,18 @@ struct SharedConstants
float alphaThreshold{};
};
// Depth bias values here are only used when the render device has
// dynamic depth bias capability enabled. Otherwise, they get unused
// and the values get assigned in the pipeline state instead.
static GuestSurface* g_renderTarget;
static GuestSurface* g_depthStencil;
static RenderFramebuffer* g_framebuffer;
static RenderViewport g_viewport(0.0f, 0.0f, 1280.0f, 720.0f);
static bool g_halfPixel = true;
static PipelineState g_pipelineState;
static int32_t g_depthBias;
static float g_slopeScaledDepthBias;
static SharedConstants g_sharedConstants;
static RenderSamplerDesc g_samplerDescs[16];
static bool g_scissorTestEnable = false;
@ -150,6 +156,7 @@ struct DirtyStates
bool renderTargetAndDepthStencil;
bool viewport;
bool pipelineState;
bool depthBias;
bool sharedConstants;
bool scissorRect;
bool vertexShaderConstants;
@ -162,6 +169,7 @@ struct DirtyStates
: renderTargetAndDepthStencil(value)
, viewport(value)
, pipelineState(value)
, depthBias(value)
, sharedConstants(value)
, scissorRect(value)
, vertexShaderConstants(value)
@ -194,7 +202,7 @@ static constexpr bool g_vulkan = true;
static std::unique_ptr<RenderInterface> g_interface;
static std::unique_ptr<RenderDevice> g_device;
static bool g_triangleFanSupported;
static RenderDeviceCapabilities g_capabilities;
static constexpr size_t NUM_FRAMES = 2;
@ -1019,12 +1027,20 @@ static void ProcSetRenderState(const RenderCommand& cmd)
}
case D3DRS_SLOPESCALEDEPTHBIAS:
{
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.slopeScaledDepthBias, *reinterpret_cast<float*>(&value));
if (g_capabilities.dynamicDepthBias)
SetDirtyValue(g_dirtyStates.depthBias, g_slopeScaledDepthBias, *reinterpret_cast<float*>(&value));
else
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.slopeScaledDepthBias, *reinterpret_cast<float*>(&value));
break;
}
case D3DRS_DEPTHBIAS:
{
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.depthBias, int32_t(*reinterpret_cast<float*>(&value) * (1 << 24)));
if (g_capabilities.dynamicDepthBias)
SetDirtyValue(g_dirtyStates.depthBias, g_depthBias, int32_t(*reinterpret_cast<float*>(&value) * (1 << 24)));
else
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.depthBias, int32_t(*reinterpret_cast<float*>(&value)* (1 << 24)));
break;
}
case D3DRS_SRCBLENDALPHA:
@ -1430,7 +1446,7 @@ void Video::CreateHostDevice(const char *sdlVideoDriver)
g_device = g_interface->createDevice();
g_triangleFanSupported = g_device->getCapabilities().triangleFan;
g_capabilities = g_device->getCapabilities();
g_queue = g_device->createCommandQueue(RenderCommandListType::DIRECT);
@ -1991,9 +2007,8 @@ static void DrawProfiler()
ImGui::Text("Physical Heap Allocated: %d MB", int32_t(physicalDiagnostics.allocated / (1024 * 1024)));
ImGui::NewLine();
auto capabilities = g_device->getCapabilities();
ImGui::Text("Present Wait: %s", capabilities.presentWait ? "Supported" : "Unsupported");
ImGui::Text("Triangle Fan: %s", capabilities.triangleFan ? "Supported" : "Unsupported");
ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "Supported" : "Unsupported");
ImGui::Text("Triangle Fan: %s", g_capabilities.triangleFan ? "Supported" : "Unsupported");
ImGui::NewLine();
const char* sdlVideoDriver = SDL_GetCurrentVideoDriver();
@ -3164,6 +3179,8 @@ static void SanitizePipelineState(PipelineState& pipelineState)
pipelineState.depthStencilFormat = RenderFormat::UNKNOWN;
}
assert(!g_capabilities.dynamicDepthBias || (pipelineState.depthBias == 0 && pipelineState.slopeScaledDepthBias == 0.0f));
if (pipelineState.slopeScaledDepthBias == 0.0f)
pipelineState.slopeScaledDepthBias = 0.0f; // Remove sign.
@ -3214,6 +3231,7 @@ static std::unique_ptr<RenderPipeline> CreateGraphicsPipeline(const PipelineStat
desc.depthWriteEnabled = pipelineState.zWriteEnable;
desc.depthBias = pipelineState.depthBias;
desc.slopeScaledDepthBias = pipelineState.slopeScaledDepthBias;
desc.dynamicDepthBiasEnabled = g_capabilities.dynamicDepthBias;
desc.depthClipEnabled = true;
desc.primitiveTopology = pipelineState.primitiveTopology;
desc.cullMode = pipelineState.cullMode;
@ -3583,8 +3601,18 @@ static void FlushRenderStateForRenderThread()
auto& commandList = g_commandLists[g_frame];
if (g_dirtyStates.pipelineState)
{
commandList->setPipeline(CreateGraphicsPipelineInRenderThread(g_pipelineState));
// D3D12 sets the depth bias values to the values in the pipeline.
// TODO: Put the common depth bias values to shadow pipelines to reduce redundant calls.
if (!g_vulkan && g_capabilities.dynamicDepthBias)
g_dirtyStates.depthBias |= (g_depthBias != 0) || (g_slopeScaledDepthBias != 0.0f);
}
if (g_dirtyStates.depthBias && g_capabilities.dynamicDepthBias)
commandList->setDepthBias(g_depthBias, 0.0f, g_slopeScaledDepthBias);
if (g_dirtyStates.sharedConstants)
{
auto sharedConstants = g_uploadAllocators[g_frame].allocate<false>(&g_sharedConstants, sizeof(g_sharedConstants), 0x100);
@ -3622,7 +3650,7 @@ static RenderPrimitiveTopology ConvertPrimitiveType(uint32_t primitiveType)
case D3DPT_TRIANGLESTRIP:
return RenderPrimitiveTopology::TRIANGLE_STRIP;
case D3DPT_TRIANGLEFAN:
return g_triangleFanSupported ? RenderPrimitiveTopology::TRIANGLE_FAN : RenderPrimitiveTopology::TRIANGLE_LIST;
return g_capabilities.triangleFan ? RenderPrimitiveTopology::TRIANGLE_FAN : RenderPrimitiveTopology::TRIANGLE_LIST;
default:
assert(false && "Unknown primitive type");
return RenderPrimitiveTopology::UNKNOWN;
@ -3748,7 +3776,7 @@ static void ProcDrawPrimitiveUP(const RenderCommand& cmd)
if (args.primitiveType == D3DPT_QUADLIST)
indexCount = g_quadIndexData.prepare(args.primitiveCount);
else if (!g_triangleFanSupported && args.primitiveType == D3DPT_TRIANGLEFAN)
else if (!g_capabilities.triangleFan && args.primitiveType == D3DPT_TRIANGLEFAN)
indexCount = g_triangleFanIndexData.prepare(args.primitiveCount);
if (args.csdFilterState != CsdFilterState::Unknown &&
@ -4994,7 +5022,7 @@ static const be<uint16_t> g_particleTestIndexBuffer[] =
bool ParticleTestIndexBufferMidAsmHook(PPCRegister& r30)
{
if (!g_triangleFanSupported)
if (!g_capabilities.triangleFan)
{
auto buffer = CreateIndexBuffer(sizeof(g_particleTestIndexBuffer), 0, D3DFMT_INDEX16);
void* memory = LockIndexBuffer(buffer, 0, 0, 0);
@ -5009,7 +5037,7 @@ bool ParticleTestIndexBufferMidAsmHook(PPCRegister& r30)
void ParticleTestDrawIndexedPrimitiveMidAsmHook(PPCRegister& r7)
{
if (!g_triangleFanSupported)
if (!g_capabilities.triangleFan)
r7.u64 = std::size(g_particleTestIndexBuffer);
}
@ -5289,8 +5317,13 @@ static void CompileMeshPipeline(const Mesh& mesh, CompilationArgs& args)
pipelineState.vertexDeclaration = mesh.vertexDeclaration;
pipelineState.cullMode = mesh.material->m_DoubleSided ? RenderCullMode::NONE : RenderCullMode::BACK;
pipelineState.zFunc = RenderComparisonFunction::LESS_EQUAL;
pipelineState.depthBias = (1 << 24) * (*reinterpret_cast<be<float>*>(g_memory.Translate(0x83302760)));
pipelineState.slopeScaledDepthBias = *reinterpret_cast<be<float>*>(g_memory.Translate(0x83302764));
if (!g_capabilities.dynamicDepthBias)
{
pipelineState.depthBias = (1 << 24) * (*reinterpret_cast<be<float>*>(g_memory.Translate(0x83302760)));
pipelineState.slopeScaledDepthBias = *reinterpret_cast<be<float>*>(g_memory.Translate(0x83302764));
}
pipelineState.colorWriteEnable = 0;
pipelineState.primitiveTopology = RenderPrimitiveTopology::TRIANGLE_STRIP;
pipelineState.vertexStrides[0] = mesh.vertexSize;
@ -5941,9 +5974,15 @@ static void ModelConsumerThread()
pipelineState.vertexDeclaration = g_vertexDeclarations[reinterpret_cast<XXH64_hash_t>(pipelineState.vertexDeclaration)];
}
if (!g_triangleFanSupported && pipelineState.primitiveTopology == RenderPrimitiveTopology::TRIANGLE_FAN)
if (!g_capabilities.triangleFan && pipelineState.primitiveTopology == RenderPrimitiveTopology::TRIANGLE_FAN)
pipelineState.primitiveTopology = RenderPrimitiveTopology::TRIANGLE_LIST;
if (g_capabilities.dynamicDepthBias)
{
pipelineState.depthBias = 0;
pipelineState.slopeScaledDepthBias = 0.0f;
}
if (Config::GITextureFiltering == EGITextureFiltering::Bicubic)
pipelineState.specConstants |= SPEC_CONSTANT_BICUBIC_GI_FILTER;