Skip to content

Commit

Permalink
[d3d9] Move building sampler key to CS thread
Browse files Browse the repository at this point in the history
All this bit twiddling is a bit slow. Introduces another structure
containing a minimal amount of sampler parameters taken from the
raw D3D9 state.
  • Loading branch information
doitsujin committed Sep 27, 2024
1 parent 8504f68 commit 0aad01d
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 49 deletions.
94 changes: 45 additions & 49 deletions src/d3d9/d3d9_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6636,71 +6636,67 @@ namespace dxvk {


void D3D9DeviceEx::BindSampler(DWORD Sampler) {
auto& state = m_state.samplerStates[Sampler];

D3DTEXTUREFILTERTYPE minFilter = D3DTEXTUREFILTERTYPE(state[D3DSAMP_MINFILTER]);
D3DTEXTUREFILTERTYPE magFilter = D3DTEXTUREFILTERTYPE(state[D3DSAMP_MAGFILTER]);
D3DTEXTUREFILTERTYPE mipFilter = D3DTEXTUREFILTERTYPE(state[D3DSAMP_MIPFILTER]);

DxvkSamplerKey key = { };
auto samplerInfo = RemapStateSamplerShader(Sampler);

key.setFilter(
DecodeFilter(minFilter),
DecodeFilter(magFilter),
DecodeMipFilter(mipFilter));
const uint32_t slot = computeResourceSlotId(
samplerInfo.first, DxsoBindingType::Image,
samplerInfo.second);

if (m_cubeTextures & (1u << Sampler)) {
key.setAddressModes(
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
EmitCs([this,
cSlot = slot,
cState = D3D9SamplerInfo(m_state.samplerStates[Sampler]),
cIsCube = bool(m_cubeTextures & (1u << Sampler)),
cIsDepth = bool(m_depthTextures & (1u << Sampler))
] (DxvkContext* ctx) {
DxvkSamplerKey key = { };

key.setLegacyCubeFilter(!m_d3d9Options.seamlessCubes);
} else {
key.setAddressModes(
DecodeAddressMode(D3DTEXTUREADDRESS(state[D3DSAMP_ADDRESSU])),
DecodeAddressMode(D3DTEXTUREADDRESS(state[D3DSAMP_ADDRESSV])),
DecodeAddressMode(D3DTEXTUREADDRESS(state[D3DSAMP_ADDRESSW])));
}
key.setFilter(
DecodeFilter(cState.minFilter),
DecodeFilter(cState.magFilter),
DecodeMipFilter(cState.mipFilter));

key.setDepthCompare(m_depthTextures & (1u << Sampler), VK_COMPARE_OP_LESS_OR_EQUAL);
if (cIsCube) {
key.setAddressModes(
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);

if (mipFilter) {
// Anisotropic filtering doesn't make any sense with only one mip
uint32_t anisotropy = state[D3DSAMP_MAXANISOTROPY];
key.setLegacyCubeFilter(!m_d3d9Options.seamlessCubes);
} else {
key.setAddressModes(
DecodeAddressMode(cState.addressU),
DecodeAddressMode(cState.addressV),
DecodeAddressMode(cState.addressW));
}

if (minFilter != D3DTEXF_ANISOTROPIC)
anisotropy = 0u;
key.setDepthCompare(cIsDepth, VK_COMPARE_OP_LESS_OR_EQUAL);

if (m_d3d9Options.samplerAnisotropy != -1 && minFilter > D3DTEXF_POINT)
anisotropy = m_d3d9Options.samplerAnisotropy;
if (cState.mipFilter) {
// Anisotropic filtering doesn't make any sense with only one mip
uint32_t anisotropy = cState.maxAnisotropy;

key.setAniso(anisotropy);
if (cState.minFilter != D3DTEXF_ANISOTROPIC)
anisotropy = 0u;

float lodBias = bit::cast<float>(state[D3DSAMP_MIPMAPLODBIAS]);
lodBias += m_d3d9Options.samplerLodBias;
if (m_d3d9Options.samplerAnisotropy != -1 && cState.minFilter > D3DTEXF_POINT)
anisotropy = m_d3d9Options.samplerAnisotropy;

if (m_d3d9Options.clampNegativeLodBias)
lodBias = std::max(lodBias, 0.0f);
key.setAniso(anisotropy);

key.setLodRange(float(state[D3DSAMP_MAXMIPLEVEL]), 16.0f, lodBias);
}
float lodBias = cState.mipLodBias;
lodBias += m_d3d9Options.samplerLodBias;

if (key.u.p.hasBorder)
DecodeD3DCOLOR(D3DCOLOR(state[D3DSAMP_BORDERCOLOR]), key.borderColor.float32);
if (m_d3d9Options.clampNegativeLodBias)
lodBias = std::max(lodBias, 0.0f);

auto samplerInfo = RemapStateSamplerShader(Sampler);
key.setLodRange(float(cState.maxMipLevel), 16.0f, lodBias);
}

const uint32_t slot = computeResourceSlotId(
samplerInfo.first, DxsoBindingType::Image,
samplerInfo.second);
if (key.u.p.hasBorder)
DecodeD3DCOLOR(cState.borderColor, key.borderColor.float32);

EmitCs([this,
cSlot = slot,
cKey = key
] (DxvkContext* ctx) {
VkShaderStageFlags stage = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
ctx->bindResourceSampler(stage, cSlot, m_dxvkDevice->createSampler(cKey));
ctx->bindResourceSampler(stage, cSlot, m_dxvkDevice->createSampler(key));
});
}

Expand Down
27 changes: 27 additions & 0 deletions src/d3d9/d3d9_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,33 @@ namespace dxvk {
T m_data;
};

struct D3D9SamplerInfo {
D3D9SamplerInfo() = default;

D3D9SamplerInfo(const std::array<DWORD, SamplerStateCount>& state)
: addressU(D3DTEXTUREADDRESS(state[D3DSAMP_ADDRESSU]))
, addressV(D3DTEXTUREADDRESS(state[D3DSAMP_ADDRESSV]))
, addressW(D3DTEXTUREADDRESS(state[D3DSAMP_ADDRESSW]))
, borderColor(D3DCOLOR(state[D3DSAMP_BORDERCOLOR]))
, magFilter(D3DTEXTUREFILTERTYPE(state[D3DSAMP_MAGFILTER]))
, minFilter(D3DTEXTUREFILTERTYPE(state[D3DSAMP_MINFILTER]))
, mipFilter(D3DTEXTUREFILTERTYPE(state[D3DSAMP_MIPFILTER]))
, mipLodBias(bit::cast<float>(state[D3DSAMP_MIPMAPLODBIAS]))
, maxMipLevel(state[D3DSAMP_MAXMIPLEVEL])
, maxAnisotropy(state[D3DSAMP_MAXMIPLEVEL]) { }

D3DTEXTUREADDRESS addressU;
D3DTEXTUREADDRESS addressV;
D3DTEXTUREADDRESS addressW;
D3DCOLOR borderColor;
D3DTEXTUREFILTERTYPE magFilter;
D3DTEXTUREFILTERTYPE minFilter;
D3DTEXTUREFILTERTYPE mipFilter;
float mipLodBias;
DWORD maxMipLevel;
DWORD maxAnisotropy;
};

template <template <typename T> typename ItemType>
struct D3D9State {
D3D9State();
Expand Down

0 comments on commit 0aad01d

Please sign in to comment.