VideoCommon: Expose SamplerState to shaders
The benefit to exposing this over the raw BP state is that adjustments Dolphin makes, such as LOD biases from arbitrary mipmap detection, will work properly.
This commit is contained in:
parent
9ef228503a
commit
4a9b26de86
|
@ -303,43 +303,43 @@ StateCache::~StateCache() = default;
|
|||
ID3D11SamplerState* StateCache::Get(SamplerState state)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_lock);
|
||||
auto it = m_sampler.find(state.hex);
|
||||
auto it = m_sampler.find(state);
|
||||
if (it != m_sampler.end())
|
||||
return it->second.Get();
|
||||
|
||||
D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
|
||||
if (state.mipmap_filter == SamplerState::Filter::Linear)
|
||||
if (state.tm0.mipmap_filter == FilterMode::Linear)
|
||||
{
|
||||
if (state.min_filter == SamplerState::Filter::Linear)
|
||||
sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||
if (state.tm0.min_filter == FilterMode::Linear)
|
||||
sampdc.Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
|
||||
D3D11_FILTER_MIN_MAG_MIP_LINEAR :
|
||||
D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
|
||||
else
|
||||
sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||
sampdc.Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
|
||||
D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR :
|
||||
D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state.min_filter == SamplerState::Filter::Linear)
|
||||
sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||
if (state.tm0.min_filter == FilterMode::Linear)
|
||||
sampdc.Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
|
||||
D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT :
|
||||
D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
||||
else
|
||||
sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||
sampdc.Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
|
||||
D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT :
|
||||
D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
}
|
||||
|
||||
static constexpr std::array<D3D11_TEXTURE_ADDRESS_MODE, 3> address_modes = {
|
||||
{D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_WRAP, D3D11_TEXTURE_ADDRESS_MIRROR}};
|
||||
sampdc.AddressU = address_modes[static_cast<u32>(state.wrap_u.Value())];
|
||||
sampdc.AddressV = address_modes[static_cast<u32>(state.wrap_v.Value())];
|
||||
sampdc.MaxLOD = state.max_lod / 16.f;
|
||||
sampdc.MinLOD = state.min_lod / 16.f;
|
||||
sampdc.MipLODBias = (s32)state.lod_bias / 256.f;
|
||||
sampdc.AddressU = address_modes[static_cast<u32>(state.tm0.wrap_u.Value())];
|
||||
sampdc.AddressV = address_modes[static_cast<u32>(state.tm0.wrap_v.Value())];
|
||||
sampdc.MaxLOD = state.tm1.max_lod / 16.f;
|
||||
sampdc.MinLOD = state.tm1.min_lod / 16.f;
|
||||
sampdc.MipLODBias = state.tm0.lod_bias / 256.f;
|
||||
|
||||
if (state.anisotropic_filtering)
|
||||
if (state.tm0.anisotropic_filtering)
|
||||
{
|
||||
sampdc.Filter = D3D11_FILTER_ANISOTROPIC;
|
||||
sampdc.MaxAnisotropy = 1u << g_ActiveConfig.iMaxAnisotropy;
|
||||
|
@ -348,7 +348,7 @@ ID3D11SamplerState* StateCache::Get(SamplerState state)
|
|||
ComPtr<ID3D11SamplerState> res;
|
||||
HRESULT hr = D3D::device->CreateSamplerState(&sampdc, res.GetAddressOf());
|
||||
CHECK(SUCCEEDED(hr), "Creating D3D sampler state failed");
|
||||
return m_sampler.emplace(state.hex, std::move(res)).first->second.Get();
|
||||
return m_sampler.emplace(state, std::move(res)).first->second.Get();
|
||||
}
|
||||
|
||||
ID3D11BlendState* StateCache::Get(BlendingState state)
|
||||
|
|
|
@ -37,7 +37,7 @@ private:
|
|||
std::unordered_map<u32, ComPtr<ID3D11DepthStencilState>> m_depth;
|
||||
std::unordered_map<u32, ComPtr<ID3D11RasterizerState>> m_raster;
|
||||
std::unordered_map<u32, ComPtr<ID3D11BlendState>> m_blend;
|
||||
std::unordered_map<SamplerState::StorageType, ComPtr<ID3D11SamplerState>> m_sampler;
|
||||
std::unordered_map<SamplerState, ComPtr<ID3D11SamplerState>> m_sampler;
|
||||
std::mutex m_lock;
|
||||
};
|
||||
|
||||
|
|
|
@ -85,32 +85,32 @@ SamplerHeapManager::~SamplerHeapManager() = default;
|
|||
|
||||
static void GetD3DSamplerDesc(D3D12_SAMPLER_DESC* desc, const SamplerState& state)
|
||||
{
|
||||
if (state.mipmap_filter == SamplerState::Filter::Linear)
|
||||
if (state.tm0.mipmap_filter == FilterMode::Linear)
|
||||
{
|
||||
if (state.min_filter == SamplerState::Filter::Linear)
|
||||
if (state.tm0.min_filter == FilterMode::Linear)
|
||||
{
|
||||
desc->Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||
desc->Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
|
||||
D3D12_FILTER_MIN_MAG_MIP_LINEAR :
|
||||
D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc->Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||
desc->Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
|
||||
D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR :
|
||||
D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state.min_filter == SamplerState::Filter::Linear)
|
||||
if (state.tm0.min_filter == FilterMode::Linear)
|
||||
{
|
||||
desc->Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||
desc->Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
|
||||
D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT :
|
||||
D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc->Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||
desc->Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
|
||||
D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT :
|
||||
D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
}
|
||||
|
@ -119,15 +119,15 @@ static void GetD3DSamplerDesc(D3D12_SAMPLER_DESC* desc, const SamplerState& stat
|
|||
static constexpr std::array<D3D12_TEXTURE_ADDRESS_MODE, 3> address_modes = {
|
||||
{D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_WRAP,
|
||||
D3D12_TEXTURE_ADDRESS_MODE_MIRROR}};
|
||||
desc->AddressU = address_modes[static_cast<u32>(state.wrap_u.Value())];
|
||||
desc->AddressV = address_modes[static_cast<u32>(state.wrap_v.Value())];
|
||||
desc->AddressU = address_modes[static_cast<u32>(state.tm0.wrap_u.Value())];
|
||||
desc->AddressV = address_modes[static_cast<u32>(state.tm0.wrap_v.Value())];
|
||||
desc->AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
desc->MaxLOD = state.max_lod / 16.f;
|
||||
desc->MinLOD = state.min_lod / 16.f;
|
||||
desc->MipLODBias = static_cast<s32>(state.lod_bias) / 256.f;
|
||||
desc->MaxLOD = state.tm1.max_lod / 16.f;
|
||||
desc->MinLOD = state.tm1.min_lod / 16.f;
|
||||
desc->MipLODBias = static_cast<s32>(state.tm0.lod_bias) / 256.f;
|
||||
desc->ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
||||
|
||||
if (state.anisotropic_filtering)
|
||||
if (state.tm0.anisotropic_filtering)
|
||||
{
|
||||
desc->Filter = D3D12_FILTER_ANISOTROPIC;
|
||||
desc->MaxAnisotropy = 1u << g_ActiveConfig.iMaxAnisotropy;
|
||||
|
@ -136,7 +136,7 @@ static void GetD3DSamplerDesc(D3D12_SAMPLER_DESC* desc, const SamplerState& stat
|
|||
|
||||
bool SamplerHeapManager::Lookup(const SamplerState& ss, D3D12_CPU_DESCRIPTOR_HANDLE* handle)
|
||||
{
|
||||
const auto it = m_sampler_map.find(ss.hex);
|
||||
const auto it = m_sampler_map.find(ss);
|
||||
if (it != m_sampler_map.end())
|
||||
{
|
||||
*handle = it->second;
|
||||
|
@ -158,7 +158,7 @@ bool SamplerHeapManager::Lookup(const SamplerState& ss, D3D12_CPU_DESCRIPTOR_HAN
|
|||
m_current_offset * m_descriptor_increment_size};
|
||||
g_dx_context->GetDevice()->CreateSampler(&desc, new_handle);
|
||||
|
||||
m_sampler_map.emplace(ss.hex, new_handle);
|
||||
m_sampler_map.emplace(ss, new_handle);
|
||||
m_current_offset++;
|
||||
*handle = new_handle;
|
||||
return true;
|
||||
|
|
|
@ -68,6 +68,6 @@ private:
|
|||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_cpu{};
|
||||
|
||||
std::unordered_map<SamplerState::StorageType, D3D12_CPU_DESCRIPTOR_HANDLE> m_sampler_map;
|
||||
std::unordered_map<SamplerState, D3D12_CPU_DESCRIPTOR_HANDLE> m_sampler_map;
|
||||
};
|
||||
} // namespace DX12
|
||||
|
|
|
@ -71,16 +71,16 @@ void SamplerCache::InvalidateBinding(u32 stage)
|
|||
void SamplerCache::SetParameters(GLuint sampler_id, const SamplerState& params)
|
||||
{
|
||||
GLenum min_filter;
|
||||
GLenum mag_filter = (params.mag_filter == SamplerState::Filter::Point) ? GL_NEAREST : GL_LINEAR;
|
||||
if (params.mipmap_filter == SamplerState::Filter::Linear)
|
||||
GLenum mag_filter = (params.tm0.mag_filter == FilterMode::Near) ? GL_NEAREST : GL_LINEAR;
|
||||
if (params.tm0.mipmap_filter == FilterMode::Linear)
|
||||
{
|
||||
min_filter = (params.min_filter == SamplerState::Filter::Point) ? GL_NEAREST_MIPMAP_LINEAR :
|
||||
GL_LINEAR_MIPMAP_LINEAR;
|
||||
min_filter = (params.tm0.min_filter == FilterMode::Near) ? GL_NEAREST_MIPMAP_LINEAR :
|
||||
GL_LINEAR_MIPMAP_LINEAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_filter = (params.min_filter == SamplerState::Filter::Point) ? GL_NEAREST_MIPMAP_NEAREST :
|
||||
GL_LINEAR_MIPMAP_NEAREST;
|
||||
min_filter = (params.tm0.min_filter == FilterMode::Near) ? GL_NEAREST_MIPMAP_NEAREST :
|
||||
GL_LINEAR_MIPMAP_NEAREST;
|
||||
}
|
||||
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filter);
|
||||
|
@ -90,17 +90,17 @@ void SamplerCache::SetParameters(GLuint sampler_id, const SamplerState& params)
|
|||
{GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT}};
|
||||
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S,
|
||||
address_modes[static_cast<u32>(params.wrap_u.Value())]);
|
||||
address_modes[static_cast<u32>(params.tm0.wrap_u.Value())]);
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T,
|
||||
address_modes[static_cast<u32>(params.wrap_v.Value())]);
|
||||
address_modes[static_cast<u32>(params.tm0.wrap_v.Value())]);
|
||||
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, params.min_lod / 16.f);
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, params.max_lod / 16.f);
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, params.tm1.min_lod / 16.f);
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, params.tm1.max_lod / 16.f);
|
||||
|
||||
if (!static_cast<Renderer*>(g_renderer.get())->IsGLES())
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, params.lod_bias / 256.f);
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, params.tm0.lod_bias / 256.f);
|
||||
|
||||
if (params.anisotropic_filtering && g_ogl_config.bSupportsAniso)
|
||||
if (params.tm0.anisotropic_filtering && g_ogl_config.bSupportsAniso)
|
||||
{
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
static_cast<float>(1 << g_ActiveConfig.iMaxAnisotropy));
|
||||
|
|
|
@ -315,28 +315,28 @@ VkSampler ObjectCache::GetSampler(const SamplerState& info)
|
|||
VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT}};
|
||||
|
||||
VkSamplerCreateInfo create_info = {
|
||||
VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
0, // VkSamplerCreateFlags flags
|
||||
filters[static_cast<u32>(info.mag_filter.Value())], // VkFilter magFilter
|
||||
filters[static_cast<u32>(info.min_filter.Value())], // VkFilter minFilter
|
||||
mipmap_modes[static_cast<u32>(info.mipmap_filter.Value())], // VkSamplerMipmapMode mipmapMode
|
||||
address_modes[static_cast<u32>(info.wrap_u.Value())], // VkSamplerAddressMode addressModeU
|
||||
address_modes[static_cast<u32>(info.wrap_v.Value())], // VkSamplerAddressMode addressModeV
|
||||
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW
|
||||
info.lod_bias / 256.0f, // float mipLodBias
|
||||
VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
0, // VkSamplerCreateFlags flags
|
||||
filters[u32(info.tm0.mag_filter.Value())], // VkFilter magFilter
|
||||
filters[u32(info.tm0.min_filter.Value())], // VkFilter minFilter
|
||||
mipmap_modes[u32(info.tm0.mipmap_filter.Value())], // VkSamplerMipmapMode mipmapMode
|
||||
address_modes[u32(info.tm0.wrap_u.Value())], // VkSamplerAddressMode addressModeU
|
||||
address_modes[u32(info.tm0.wrap_v.Value())], // VkSamplerAddressMode addressModeV
|
||||
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW
|
||||
info.tm0.lod_bias / 256.0f, // float mipLodBias
|
||||
VK_FALSE, // VkBool32 anisotropyEnable
|
||||
0.0f, // float maxAnisotropy
|
||||
VK_FALSE, // VkBool32 compareEnable
|
||||
VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp
|
||||
info.min_lod / 16.0f, // float minLod
|
||||
info.max_lod / 16.0f, // float maxLod
|
||||
info.tm1.min_lod / 16.0f, // float minLod
|
||||
info.tm1.max_lod / 16.0f, // float maxLod
|
||||
VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor
|
||||
VK_FALSE // VkBool32 unnormalizedCoordinates
|
||||
};
|
||||
|
||||
// Can we use anisotropic filtering with this sampler?
|
||||
if (info.anisotropic_filtering && g_vulkan_context->SupportsAnisotropicFiltering())
|
||||
if (info.tm0.anisotropic_filtering && g_vulkan_context->SupportsAnisotropicFiltering())
|
||||
{
|
||||
// Cap anisotropy to device limits.
|
||||
create_info.anisotropyEnable = VK_TRUE;
|
||||
|
|
|
@ -49,7 +49,7 @@ Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale
|
|||
{
|
||||
UpdateActiveConfig();
|
||||
for (SamplerState& m_sampler_state : m_sampler_states)
|
||||
m_sampler_state.hex = RenderState::GetPointSamplerState().hex;
|
||||
m_sampler_state = RenderState::GetPointSamplerState();
|
||||
}
|
||||
|
||||
Renderer::~Renderer() = default;
|
||||
|
@ -545,7 +545,7 @@ void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
|
|||
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
|
||||
{
|
||||
// Skip lookup if the state hasn't changed.
|
||||
if (m_sampler_states[index].hex == state.hex)
|
||||
if (m_sampler_states[index] == state)
|
||||
return;
|
||||
|
||||
// Look up new state and replace in state tracker.
|
||||
|
@ -557,7 +557,7 @@ void Renderer::SetSamplerState(u32 index, const SamplerState& state)
|
|||
}
|
||||
|
||||
StateTracker::GetInstance()->SetSampler(index, sampler);
|
||||
m_sampler_states[index].hex = state.hex;
|
||||
m_sampler_states[index] = state;
|
||||
}
|
||||
|
||||
void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
|
||||
|
@ -588,7 +588,7 @@ void Renderer::ResetSamplerStates()
|
|||
// Invalidate all sampler states, next draw will re-initialize them.
|
||||
for (u32 i = 0; i < m_sampler_states.size(); i++)
|
||||
{
|
||||
m_sampler_states[i].hex = RenderState::GetPointSamplerState().hex;
|
||||
m_sampler_states[i] = RenderState::GetPointSamplerState();
|
||||
StateTracker::GetInstance()->SetSampler(i, g_object_cache->GetPointSampler());
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ struct PixelShaderConstants
|
|||
float4 zslope;
|
||||
std::array<float, 2> efbscale; // .xy
|
||||
|
||||
// Constants from here onwards are only used in ubershaders.
|
||||
// Constants from here onwards are only used in ubershaders, other than pack2.
|
||||
u32 genmode; // .z
|
||||
u32 alphaTest; // .w
|
||||
u32 fogParam3; // .x
|
||||
|
@ -44,7 +44,7 @@ struct PixelShaderConstants
|
|||
u32 dither; // .z (bool)
|
||||
u32 bounding_box; // .w (bool)
|
||||
std::array<uint4, 16> pack1; // .xy - combiners, .z - tevind, .w - iref
|
||||
std::array<uint4, 8> pack2; // .x - tevorder, .y - tevksel
|
||||
std::array<uint4, 8> pack2; // .x - tevorder, .y - tevksel, .z/.w - SamplerState tm0/tm1
|
||||
std::array<int4, 32> konst; // .rgba
|
||||
// The following are used in ubershaders when using shader_framebuffer_fetch blending
|
||||
u32 blend_enable;
|
||||
|
|
|
@ -414,7 +414,7 @@ void WritePixelShaderCommonHeader(ShaderCode& out, APIType api_type,
|
|||
"\tbool bpmem_dither;\n"
|
||||
"\tbool bpmem_bounding_box;\n"
|
||||
"\tuint4 bpmem_pack1[16];\n" // .xy - combiners, .z - tevind
|
||||
"\tuint4 bpmem_pack2[8];\n" // .x - tevorder, .y - tevksel
|
||||
"\tuint4 bpmem_pack2[8];\n" // .x - tevorder, .y - tevksel, .zw - SamplerState tm0/tm1
|
||||
"\tint4 konstLookup[32];\n"
|
||||
"\tbool blend_enable;\n"
|
||||
"\tuint blend_src_factor;\n"
|
||||
|
|
|
@ -282,6 +282,15 @@ void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height)
|
|||
constants.texdims[texmapid][1] = height;
|
||||
}
|
||||
|
||||
void PixelShaderManager::SetSamplerState(int texmapid, u32 tm0, u32 tm1)
|
||||
{
|
||||
if (constants.pack2[texmapid][2] != tm0 || constants.pack2[texmapid][3] != tm1)
|
||||
dirty = true;
|
||||
|
||||
constants.pack2[texmapid][2] = tm0;
|
||||
constants.pack2[texmapid][3] = tm1;
|
||||
}
|
||||
|
||||
void PixelShaderManager::SetZTextureBias()
|
||||
{
|
||||
constants.zbias[1][3] = bpmem.ztex1.bias;
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
static void SetAlphaTestChanged();
|
||||
static void SetDestAlphaChanged();
|
||||
static void SetTexDims(int texmapid, u32 width, u32 height);
|
||||
static void SetSamplerState(int texmapid, u32 tm0, u32 tm1);
|
||||
static void SetZTextureBias();
|
||||
static void SetViewportChanged();
|
||||
static void SetEfbScaleChanged(float scalex, float scaley);
|
||||
|
|
|
@ -202,27 +202,42 @@ void BlendingState::ApproximateLogicOpWithBlending()
|
|||
void SamplerState::Generate(const BPMemory& bp, u32 index)
|
||||
{
|
||||
auto tex = bp.tex.GetUnit(index);
|
||||
const TexMode0& tm0 = tex.texMode0;
|
||||
const TexMode1& tm1 = tex.texMode1;
|
||||
const TexMode0& bp_tm0 = tex.texMode0;
|
||||
const TexMode1& bp_tm1 = tex.texMode1;
|
||||
|
||||
// GX can configure the mip filter to none. However, D3D and Vulkan can't express this in their
|
||||
// sampler states. Therefore, we set the min/max LOD to zero if this option is used.
|
||||
min_filter = tm0.min_filter == FilterMode::Linear ? Filter::Linear : Filter::Point;
|
||||
mipmap_filter = tm0.mipmap_filter == MipMode::Linear ? Filter::Linear : Filter::Point;
|
||||
mag_filter = tm0.mag_filter == FilterMode::Linear ? Filter::Linear : Filter::Point;
|
||||
tm0.min_filter = bp_tm0.min_filter;
|
||||
tm0.mipmap_filter =
|
||||
bp_tm0.mipmap_filter == MipMode::Linear ? FilterMode::Linear : FilterMode::Near;
|
||||
tm0.mag_filter = bp_tm0.mag_filter;
|
||||
|
||||
// If mipmaps are disabled, clamp min/max lod
|
||||
max_lod = tm0.mipmap_filter != MipMode::None ? tm1.max_lod.Value() : 0;
|
||||
min_lod = std::min(max_lod.Value(), static_cast<u64>(tm1.min_lod));
|
||||
lod_bias = tm0.mipmap_filter != MipMode::None ? tm0.lod_bias * (256 / 32) : 0;
|
||||
if (bp_tm0.mipmap_filter == MipMode::None)
|
||||
{
|
||||
tm1.max_lod = 0;
|
||||
tm1.min_lod = 0;
|
||||
tm0.lod_bias = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: When comparing, max is checked first, then min; if max is less than min, max wins
|
||||
tm1.max_lod = bp_tm1.max_lod.Value();
|
||||
tm1.min_lod = std::min(tm1.max_lod.Value(), bp_tm1.min_lod.Value());
|
||||
tm0.lod_bias = bp_tm0.lod_bias * (256 / 32);
|
||||
}
|
||||
|
||||
// Address modes
|
||||
// Wrap modes
|
||||
// Hardware testing indicates that wrap_mode set to 3 behaves the same as clamp.
|
||||
static constexpr std::array<AddressMode, 4> address_modes = {
|
||||
{AddressMode::Clamp, AddressMode::Repeat, AddressMode::MirroredRepeat, AddressMode::Clamp}};
|
||||
wrap_u = address_modes[u32(tm0.wrap_s.Value())];
|
||||
wrap_v = address_modes[u32(tm0.wrap_t.Value())];
|
||||
anisotropic_filtering = 0;
|
||||
auto filter_invalid_wrap = [](WrapMode mode) {
|
||||
return (mode <= WrapMode::Mirror) ? mode : WrapMode::Clamp;
|
||||
};
|
||||
tm0.wrap_u = filter_invalid_wrap(bp_tm0.wrap_s);
|
||||
tm0.wrap_v = filter_invalid_wrap(bp_tm0.wrap_t);
|
||||
|
||||
tm0.diag_lod = bp_tm0.diag_lod;
|
||||
tm0.anisotropic_filtering = false; // TODO: Respect BP anisotropic filtering mode
|
||||
tm0.lod_clamp = bp_tm0.lod_clamp; // TODO: What does this do?
|
||||
}
|
||||
|
||||
namespace RenderState
|
||||
|
@ -315,37 +330,42 @@ BlendingState GetNoColorWriteBlendState()
|
|||
SamplerState GetInvalidSamplerState()
|
||||
{
|
||||
SamplerState state;
|
||||
state.hex = UINT64_C(0xFFFFFFFFFFFFFFFF);
|
||||
state.tm0.hex = 0xFFFFFFFF;
|
||||
state.tm1.hex = 0xFFFFFFFF;
|
||||
return state;
|
||||
}
|
||||
|
||||
SamplerState GetPointSamplerState()
|
||||
{
|
||||
SamplerState state = {};
|
||||
state.min_filter = SamplerState::Filter::Point;
|
||||
state.mag_filter = SamplerState::Filter::Point;
|
||||
state.mipmap_filter = SamplerState::Filter::Point;
|
||||
state.wrap_u = SamplerState::AddressMode::Clamp;
|
||||
state.wrap_v = SamplerState::AddressMode::Clamp;
|
||||
state.min_lod = 0;
|
||||
state.max_lod = 255;
|
||||
state.lod_bias = 0;
|
||||
state.anisotropic_filtering = false;
|
||||
state.tm0.min_filter = FilterMode::Near;
|
||||
state.tm0.mag_filter = FilterMode::Near;
|
||||
state.tm0.mipmap_filter = FilterMode::Near;
|
||||
state.tm0.wrap_u = WrapMode::Clamp;
|
||||
state.tm0.wrap_v = WrapMode::Clamp;
|
||||
state.tm1.min_lod = 0;
|
||||
state.tm1.max_lod = 255;
|
||||
state.tm0.lod_bias = 0;
|
||||
state.tm0.anisotropic_filtering = false;
|
||||
state.tm0.diag_lod = LODType::Edge;
|
||||
state.tm0.lod_clamp = false;
|
||||
return state;
|
||||
}
|
||||
|
||||
SamplerState GetLinearSamplerState()
|
||||
{
|
||||
SamplerState state = {};
|
||||
state.min_filter = SamplerState::Filter::Linear;
|
||||
state.mag_filter = SamplerState::Filter::Linear;
|
||||
state.mipmap_filter = SamplerState::Filter::Linear;
|
||||
state.wrap_u = SamplerState::AddressMode::Clamp;
|
||||
state.wrap_v = SamplerState::AddressMode::Clamp;
|
||||
state.min_lod = 0;
|
||||
state.max_lod = 255;
|
||||
state.lod_bias = 0;
|
||||
state.anisotropic_filtering = false;
|
||||
state.tm0.min_filter = FilterMode::Linear;
|
||||
state.tm0.mag_filter = FilterMode::Linear;
|
||||
state.tm0.mipmap_filter = FilterMode::Linear;
|
||||
state.tm0.wrap_u = WrapMode::Clamp;
|
||||
state.tm0.wrap_v = WrapMode::Clamp;
|
||||
state.tm1.min_lod = 0;
|
||||
state.tm1.max_lod = 255;
|
||||
state.tm0.lod_bias = 0;
|
||||
state.tm0.anisotropic_filtering = false;
|
||||
state.tm0.diag_lod = LODType::Edge;
|
||||
state.tm0.lod_clamp = false;
|
||||
return state;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,30 +145,16 @@ union BlendingState
|
|||
u32 hex;
|
||||
};
|
||||
|
||||
union SamplerState
|
||||
struct SamplerState
|
||||
{
|
||||
using StorageType = u64;
|
||||
|
||||
enum class Filter : StorageType
|
||||
{
|
||||
Point,
|
||||
Linear
|
||||
};
|
||||
|
||||
enum class AddressMode : StorageType
|
||||
{
|
||||
Clamp,
|
||||
Repeat,
|
||||
MirroredRepeat
|
||||
};
|
||||
|
||||
void Generate(const BPMemory& bp, u32 index);
|
||||
|
||||
SamplerState() = default;
|
||||
SamplerState(const SamplerState&) = default;
|
||||
SamplerState& operator=(const SamplerState& rhs)
|
||||
{
|
||||
hex = rhs.hex;
|
||||
tm0.hex = rhs.tm0.hex;
|
||||
tm1.hex = rhs.tm1.hex;
|
||||
return *this;
|
||||
}
|
||||
SamplerState(SamplerState&&) = default;
|
||||
|
@ -179,22 +165,54 @@ union SamplerState
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const SamplerState& rhs) const { return hex == rhs.hex; }
|
||||
bool operator==(const SamplerState& rhs) const { return Hex() == rhs.Hex(); }
|
||||
bool operator!=(const SamplerState& rhs) const { return !operator==(rhs); }
|
||||
bool operator<(const SamplerState& rhs) const { return hex < rhs.hex; }
|
||||
BitField<0, 1, Filter> min_filter;
|
||||
BitField<1, 1, Filter> mag_filter;
|
||||
BitField<2, 1, Filter> mipmap_filter;
|
||||
BitField<3, 2, AddressMode> wrap_u;
|
||||
BitField<5, 2, AddressMode> wrap_v;
|
||||
BitField<7, 16, s64> lod_bias; // multiplied by 256
|
||||
BitField<23, 8, u64> min_lod; // multiplied by 16
|
||||
BitField<31, 8, u64> max_lod; // multiplied by 16
|
||||
BitField<39, 1, u64> anisotropic_filtering;
|
||||
bool operator<(const SamplerState& rhs) const { return Hex() < rhs.Hex(); }
|
||||
|
||||
StorageType hex;
|
||||
constexpr u64 Hex() const { return tm0.hex | (static_cast<u64>(tm1.hex) << 32); }
|
||||
|
||||
// Based on BPMemory TexMode0/TexMode1, but with slightly higher precision and some
|
||||
// simplifications
|
||||
union TM0
|
||||
{
|
||||
// BP's mipmap_filter can be None, but that is represented here by setting min_lod and max_lod
|
||||
// to 0
|
||||
BitField<0, 1, FilterMode> min_filter;
|
||||
BitField<1, 1, FilterMode> mag_filter;
|
||||
BitField<2, 1, FilterMode> mipmap_filter;
|
||||
// Guaranteed to be valid values (i.e. not 3)
|
||||
BitField<3, 2, WrapMode> wrap_u;
|
||||
BitField<5, 2, WrapMode> wrap_v;
|
||||
BitField<7, 1, LODType> diag_lod;
|
||||
BitField<8, 16, s32> lod_bias; // multiplied by 256, higher precision than normal
|
||||
BitField<24, 1, bool, u32> lod_clamp; // TODO: This isn't currently implemented
|
||||
BitField<25, 1, bool, u32> anisotropic_filtering; // TODO: This doesn't use the BP one yet
|
||||
u32 hex;
|
||||
};
|
||||
union TM1
|
||||
{
|
||||
// Min is guaranteed to be less than or equal to max
|
||||
BitField<0, 8, u32> min_lod; // multiplied by 16
|
||||
BitField<8, 8, u32> max_lod; // multiplied by 16
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
TM0 tm0;
|
||||
TM1 tm1;
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<SamplerState>
|
||||
{
|
||||
std::size_t operator()(SamplerState const& state) const noexcept
|
||||
{
|
||||
return std::hash<u64>{}(state.Hex());
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace RenderState
|
||||
{
|
||||
RasterizationState GetInvalidRasterizationState();
|
||||
|
|
|
@ -988,15 +988,15 @@ static void SetSamplerState(u32 index, float custom_tex_scale, bool custom_tex,
|
|||
// Force texture filtering config option.
|
||||
if (g_ActiveConfig.bForceFiltering)
|
||||
{
|
||||
state.min_filter = SamplerState::Filter::Linear;
|
||||
state.mag_filter = SamplerState::Filter::Linear;
|
||||
state.mipmap_filter = tm0.mipmap_filter != MipMode::None ? SamplerState::Filter::Linear :
|
||||
SamplerState::Filter::Point;
|
||||
state.tm0.min_filter = FilterMode::Linear;
|
||||
state.tm0.mag_filter = FilterMode::Linear;
|
||||
state.tm0.mipmap_filter =
|
||||
tm0.mipmap_filter != MipMode::None ? FilterMode::Linear : FilterMode::Near;
|
||||
}
|
||||
|
||||
// Custom textures may have a greater number of mips
|
||||
if (custom_tex)
|
||||
state.max_lod = 255;
|
||||
state.tm1.max_lod = 255;
|
||||
|
||||
// Anisotropic filtering option.
|
||||
if (g_ActiveConfig.iMaxAnisotropy != 0 && IsAnisostropicEnhancementSafe(tm0))
|
||||
|
@ -1008,15 +1008,15 @@ static void SetSamplerState(u32 index, float custom_tex_scale, bool custom_tex,
|
|||
// Letting the game set other combinations will have varying arbitrary results;
|
||||
// possibly being interpreted as equal to bilinear/trilinear, implicitly
|
||||
// disabling anisotropy, or changing the anisotropic algorithm employed.
|
||||
state.min_filter = SamplerState::Filter::Linear;
|
||||
state.mag_filter = SamplerState::Filter::Linear;
|
||||
state.tm0.min_filter = FilterMode::Linear;
|
||||
state.tm0.mag_filter = FilterMode::Linear;
|
||||
if (tm0.mipmap_filter != MipMode::None)
|
||||
state.mipmap_filter = SamplerState::Filter::Linear;
|
||||
state.anisotropic_filtering = 1;
|
||||
state.tm0.mipmap_filter = FilterMode::Linear;
|
||||
state.tm0.anisotropic_filtering = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.anisotropic_filtering = 0;
|
||||
state.tm0.anisotropic_filtering = false;
|
||||
}
|
||||
|
||||
if (has_arbitrary_mips && tm0.mipmap_filter != MipMode::None)
|
||||
|
@ -1025,14 +1025,15 @@ static void SetSamplerState(u32 index, float custom_tex_scale, bool custom_tex,
|
|||
// that have arbitrary contents, eg. are used for fog effects where the
|
||||
// distance they kick in at is important to preserve at any resolution.
|
||||
// Correct this with the upscaling factor of custom textures.
|
||||
s64 lod_offset = std::log2(g_renderer->GetEFBScale() / custom_tex_scale) * 256.f;
|
||||
state.lod_bias = std::clamp<s64>(state.lod_bias + lod_offset, -32768, 32767);
|
||||
s32 lod_offset = std::log2(g_renderer->GetEFBScale() / custom_tex_scale) * 256.f;
|
||||
state.tm0.lod_bias = std::clamp<s32>(state.tm0.lod_bias + lod_offset, -32768, 32767);
|
||||
|
||||
// Anisotropic also pushes mips farther away so it cannot be used either
|
||||
state.anisotropic_filtering = 0;
|
||||
state.tm0.anisotropic_filtering = false;
|
||||
}
|
||||
|
||||
g_renderer->SetSamplerState(index, state);
|
||||
PixelShaderManager::SetSamplerState(index, state.tm0.hex, state.tm1.hex);
|
||||
}
|
||||
|
||||
void TextureCacheBase::BindTextures(BitSet32 used_textures)
|
||||
|
|
Loading…
Reference in New Issue