Specialization constant implementation for Vulkan.

This commit is contained in:
Skyth 2024-11-20 13:57:38 +03:00
parent 349f07cf77
commit 0e8d1e2aa0
6 changed files with 59 additions and 36 deletions

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.hlsli" #include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.h"
#ifdef __spirv__ #ifdef __spirv__

View file

@ -13,6 +13,7 @@
#include <ui/window.h> #include <ui/window.h>
#include <cfg/config.h> #include <cfg/config.h>
#include "../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.h"
#include "shader/copy_vs.hlsl.dxil.h" #include "shader/copy_vs.hlsl.dxil.h"
#include "shader/copy_vs.hlsl.spirv.h" #include "shader/copy_vs.hlsl.spirv.h"
#include "shader/gamma_correction_ps.hlsl.dxil.h" #include "shader/gamma_correction_ps.hlsl.dxil.h"
@ -70,13 +71,7 @@ struct PipelineState
RenderFormat depthStencilFormat{}; RenderFormat depthStencilFormat{};
RenderSampleCounts sampleCount = RenderSampleCount::COUNT_1; RenderSampleCounts sampleCount = RenderSampleCount::COUNT_1;
bool enableAlphaToCoverage = false; bool enableAlphaToCoverage = false;
}; uint32_t specConstants = 0;
enum class AlphaTestMode : uint32_t
{
Disabled,
AlphaThreshold,
AlphaToCoverage
}; };
struct SharedConstants struct SharedConstants
@ -85,12 +80,9 @@ struct SharedConstants
uint32_t texture3DIndices[16]{}; uint32_t texture3DIndices[16]{};
uint32_t textureCubeIndices[16]{}; uint32_t textureCubeIndices[16]{};
uint32_t samplerIndices[16]{}; uint32_t samplerIndices[16]{};
AlphaTestMode alphaTestMode{};
float alphaThreshold{};
uint32_t booleans{}; uint32_t booleans{};
uint32_t swappedTexcoords{}; uint32_t swappedTexcoords{};
uint32_t inputLayoutFlags{}; float alphaThreshold{};
uint32_t enableGIBicubicFiltering{};
}; };
static GuestSurface* g_renderTarget; static GuestSurface* g_renderTarget;
@ -723,18 +715,23 @@ static void SetRenderStateUnimplemented(GuestDevice* device, uint32_t value)
static void SetAlphaTestMode(bool enable) static void SetAlphaTestMode(bool enable)
{ {
AlphaTestMode alphaTestMode = AlphaTestMode::Disabled; uint32_t specConstants = 0;
bool enableAlphaToCoverage = false;
if (enable) if (enable)
{ {
if (Config::AlphaToCoverage && g_renderTarget != nullptr && g_renderTarget->sampleCount != RenderSampleCount::COUNT_1) enableAlphaToCoverage = Config::AlphaToCoverage && g_renderTarget != nullptr && g_renderTarget->sampleCount != RenderSampleCount::COUNT_1;
alphaTestMode = AlphaTestMode::AlphaToCoverage;
if (enableAlphaToCoverage)
specConstants = SPEC_CONSTANT_ALPHA_TO_COVERAGE;
else else
alphaTestMode = AlphaTestMode::AlphaThreshold; specConstants = SPEC_CONSTANT_ALPHA_TEST;
} }
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.alphaTestMode, alphaTestMode); specConstants |= (g_pipelineState.specConstants & ~(SPEC_CONSTANT_ALPHA_TEST | SPEC_CONSTANT_ALPHA_TO_COVERAGE));
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.enableAlphaToCoverage, alphaTestMode == AlphaTestMode::AlphaToCoverage);
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.enableAlphaToCoverage, enableAlphaToCoverage);
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.specConstants, specConstants);
} }
static RenderBlend ConvertBlendMode(uint32_t blendMode) static RenderBlend ConvertBlendMode(uint32_t blendMode)
@ -1373,7 +1370,10 @@ static void BeginCommandList()
g_sharedConstants.textureCubeIndices[i] = TEXTURE_DESCRIPTOR_NULL_TEXTURE_CUBE; g_sharedConstants.textureCubeIndices[i] = TEXTURE_DESCRIPTOR_NULL_TEXTURE_CUBE;
} }
g_sharedConstants.enableGIBicubicFiltering = (Config::GITextureFiltering == EGITextureFiltering::Bicubic); if (Config::GITextureFiltering == EGITextureFiltering::Bicubic)
g_pipelineState.specConstants |= SPEC_CONSTANT_BICUBIC_GI_FILTER;
else
g_pipelineState.specConstants &= ~SPEC_CONSTANT_BICUBIC_GI_FILTER;
auto& commandList = g_commandLists[g_frame]; auto& commandList = g_commandLists[g_frame];
@ -2190,7 +2190,7 @@ static void ProcSetRenderTarget(const RenderCommand& cmd)
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.sampleCount, args.renderTarget != nullptr ? args.renderTarget->sampleCount : RenderSampleCount::COUNT_1); SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.sampleCount, args.renderTarget != nullptr ? args.renderTarget->sampleCount : RenderSampleCount::COUNT_1);
// When alpha to coverage is enabled, update the alpha test mode as it's dependent on sample count. // When alpha to coverage is enabled, update the alpha test mode as it's dependent on sample count.
SetAlphaTestMode(g_sharedConstants.alphaTestMode != AlphaTestMode::Disabled); SetAlphaTestMode((g_pipelineState.specConstants & (SPEC_CONSTANT_ALPHA_TEST | SPEC_CONSTANT_ALPHA_TO_COVERAGE)) != 0);
} }
static void SetDepthStencilSurface(GuestDevice* device, GuestSurface* depthStencil) static void SetDepthStencilSurface(GuestDevice* device, GuestSurface* depthStencil)
@ -2432,6 +2432,12 @@ static RenderPipeline* CreateGraphicsPipeline(PipelineState pipelineState)
pipelineState.blendOpAlpha = RenderBlendOperation::ADD; pipelineState.blendOpAlpha = RenderBlendOperation::ADD;
} }
uint32_t specConstantsMask = pipelineState.vertexShader->specConstantsMask;
if (pipelineState.pixelShader != nullptr)
specConstantsMask |= pipelineState.pixelShader->specConstantsMask;
pipelineState.specConstants &= specConstantsMask;
auto& pipeline = g_pipelines[XXH3_64bits(&pipelineState, sizeof(PipelineState))]; auto& pipeline = g_pipelines[XXH3_64bits(&pipelineState, sizeof(PipelineState))];
if (pipeline == nullptr) if (pipeline == nullptr)
{ {
@ -2463,6 +2469,15 @@ static RenderPipeline* CreateGraphicsPipeline(PipelineState pipelineState)
desc.inputElements = pipelineState.vertexDeclaration->inputElements.get(); desc.inputElements = pipelineState.vertexDeclaration->inputElements.get();
desc.inputElementsCount = pipelineState.vertexDeclaration->inputElementCount; desc.inputElementsCount = pipelineState.vertexDeclaration->inputElementCount;
RenderSpecConstant specConstant{};
specConstant.value = pipelineState.specConstants;
if (specConstantsMask != 0)
{
desc.specConstants = &specConstant;
desc.specConstantsCount = 1;
}
RenderInputSlot inputSlots[16]{}; RenderInputSlot inputSlots[16]{};
uint32_t inputSlotIndices[16]{}; uint32_t inputSlotIndices[16]{};
uint32_t inputSlotCount = 0; uint32_t inputSlotCount = 0;
@ -2613,6 +2628,15 @@ static void FlushRenderStateForMainThread(GuestDevice* device, LocalRenderComman
static void ProcSetBooleans(const RenderCommand& cmd) static void ProcSetBooleans(const RenderCommand& cmd)
{ {
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.booleans, cmd.setBooleans.booleans); SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.booleans, cmd.setBooleans.booleans);
// mrgHasBone
uint32_t specConstants = g_pipelineState.specConstants;
if ((cmd.setBooleans.booleans & 0x1) != 0)
specConstants |= SPEC_CONSTANT_HAS_BONE;
else
specConstants &= ~SPEC_CONSTANT_HAS_BONE;
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.specConstants, specConstants);
} }
static void ProcSetSamplerState(const RenderCommand& cmd) static void ProcSetSamplerState(const RenderCommand& cmd)
@ -3036,18 +3060,13 @@ static GuestVertexDeclaration* CreateVertexDeclaration(GuestVertexElement* verte
vertexDeclaration->indexVertexStream = vertexElement->stream; vertexDeclaration->indexVertexStream = vertexElement->stream;
break; break;
case D3DDECLUSAGE_BLENDWEIGHT:
case D3DDECLUSAGE_BLENDINDICES:
vertexDeclaration->inputLayoutFlags |= INPUT_LAYOUT_FLAG_HAS_BONE_WEIGHTS;
break;
case D3DDECLUSAGE_NORMAL: case D3DDECLUSAGE_NORMAL:
case D3DDECLUSAGE_TANGENT: case D3DDECLUSAGE_TANGENT:
case D3DDECLUSAGE_BINORMAL: case D3DDECLUSAGE_BINORMAL:
if (vertexElement->type == D3DDECLTYPE_FLOAT3) if (vertexElement->type == D3DDECLTYPE_FLOAT3)
inputElement.format = RenderFormat::R32G32B32_UINT; inputElement.format = RenderFormat::R32G32B32_UINT;
else else
vertexDeclaration->inputLayoutFlags |= INPUT_LAYOUT_FLAG_HAS_R11G11B10_NORMAL; vertexDeclaration->hasR11G11B10Normal = true;
break; break;
case D3DDECLUSAGE_TEXCOORD: case D3DDECLUSAGE_TEXCOORD:
@ -3149,7 +3168,14 @@ static void ProcSetVertexDeclaration(const RenderCommand& cmd)
if (args.vertexDeclaration != nullptr) if (args.vertexDeclaration != nullptr)
{ {
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.swappedTexcoords, args.vertexDeclaration->swappedTexcoords); SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.swappedTexcoords, args.vertexDeclaration->swappedTexcoords);
SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.inputLayoutFlags, args.vertexDeclaration->inputLayoutFlags);
uint32_t specConstants = g_pipelineState.specConstants;
if (args.vertexDeclaration->hasR11G11B10Normal)
specConstants |= SPEC_CONSTANT_R11G11B10_NORMAL;
else
specConstants &= ~SPEC_CONSTANT_R11G11B10_NORMAL;
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.specConstants, specConstants);
} }
SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.vertexDeclaration, args.vertexDeclaration); SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.vertexDeclaration, args.vertexDeclaration);
} }
@ -3171,6 +3197,7 @@ static GuestShader* CreateShader(const be<uint32_t>* function, ResourceType reso
if (findResult->userData == nullptr) if (findResult->userData == nullptr)
{ {
shader = g_userHeap.AllocPhysical<GuestShader>(resourceType); shader = g_userHeap.AllocPhysical<GuestShader>(resourceType);
shader->specConstantsMask = findResult->specConstantsMask;
if (g_vulkan) if (g_vulkan)
shader->shader = g_device->createShader(g_shaderCache.get() + findResult->spirvOffset, findResult->spirvSize, "main", RenderShaderFormat::SPIRV); shader->shader = g_device->createShader(g_shaderCache.get() + findResult->spirvOffset, findResult->spirvSize, "main", RenderShaderFormat::SPIRV);

View file

@ -226,12 +226,6 @@ struct GuestVertexElement
uint8_t padding; uint8_t padding;
}; };
enum InputLayoutFlags
{
INPUT_LAYOUT_FLAG_HAS_R11G11B10_NORMAL = 1 << 0,
INPUT_LAYOUT_FLAG_HAS_BONE_WEIGHTS = 1 << 1
};
struct GuestVertexDeclaration : GuestResource struct GuestVertexDeclaration : GuestResource
{ {
std::unique_ptr<RenderInputElement[]> inputElements; std::unique_ptr<RenderInputElement[]> inputElements;
@ -239,7 +233,7 @@ struct GuestVertexDeclaration : GuestResource
uint32_t inputElementCount = 0; uint32_t inputElementCount = 0;
uint32_t vertexElementCount = 0; uint32_t vertexElementCount = 0;
uint32_t swappedTexcoords = 0; uint32_t swappedTexcoords = 0;
uint32_t inputLayoutFlags = 0; bool hasR11G11B10Normal = false;
uint32_t indexVertexStream = 0; uint32_t indexVertexStream = 0;
}; };
@ -247,6 +241,7 @@ struct GuestVertexDeclaration : GuestResource
struct GuestShader : GuestResource struct GuestShader : GuestResource
{ {
std::unique_ptr<RenderShader> shader; std::unique_ptr<RenderShader> shader;
uint32_t specConstantsMask = 0;
}; };
struct GuestViewport struct GuestViewport

View file

@ -26,7 +26,7 @@ add_custom_command(
) )
set(SHADER_RECOMP_ROOT "${SWA_THIRDPARTY_ROOT}/ShaderRecomp/ShaderRecomp") set(SHADER_RECOMP_ROOT "${SWA_THIRDPARTY_ROOT}/ShaderRecomp/ShaderRecomp")
set(SHADER_RECOMP_INCLUDE "${SHADER_RECOMP_ROOT}/shader_common.hlsli") set(SHADER_RECOMP_INCLUDE "${SHADER_RECOMP_ROOT}/shader_common.h")
target_compile_definitions(ShaderRecomp PRIVATE target_compile_definitions(ShaderRecomp PRIVATE
SHADER_RECOMP_INPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/private\" SHADER_RECOMP_INPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/private\"

View file

@ -7,6 +7,7 @@ struct ShaderCacheEntry
const uint32_t dxilSize; const uint32_t dxilSize;
const uint32_t spirvOffset; const uint32_t spirvOffset;
const uint32_t spirvSize; const uint32_t spirvSize;
const uint32_t specConstantsMask;
void* userData; void* userData;
}; };

@ -1 +1 @@
Subproject commit 30f598604767602e3afce56b947e99dba2b51211 Subproject commit 73f17ee29ad7fe5333df326a50e7f96867e63b20