VideoBackends: Move SamplerState to common
This commit is contained in:
parent
340aabbb06
commit
24ddea04ce
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#include "VideoBackends/D3D/D3DBase.h"
|
#include "VideoBackends/D3D/D3DBase.h"
|
||||||
#include "VideoBackends/D3D/D3DState.h"
|
#include "VideoBackends/D3D/D3DState.h"
|
||||||
#include "VideoCommon/SamplerCommon.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
|
||||||
namespace DX11
|
namespace DX11
|
||||||
{
|
{
|
||||||
|
@ -265,90 +265,55 @@ void StateManager::SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceVie
|
||||||
|
|
||||||
ID3D11SamplerState* StateCache::Get(SamplerState state)
|
ID3D11SamplerState* StateCache::Get(SamplerState state)
|
||||||
{
|
{
|
||||||
auto it = m_sampler.find(state.packed);
|
auto it = m_sampler.find(state.hex);
|
||||||
|
|
||||||
if (it != m_sampler.end())
|
if (it != m_sampler.end())
|
||||||
{
|
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned int d3dMipFilters[4] = {
|
|
||||||
TexMode0::TEXF_NONE, TexMode0::TEXF_POINT, TexMode0::TEXF_LINEAR,
|
|
||||||
TexMode0::TEXF_NONE, // reserved
|
|
||||||
};
|
|
||||||
const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] = {
|
|
||||||
D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_WRAP, D3D11_TEXTURE_ADDRESS_MIRROR,
|
|
||||||
D3D11_TEXTURE_ADDRESS_WRAP // reserved
|
|
||||||
};
|
|
||||||
|
|
||||||
D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
|
D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
|
||||||
|
if (state.mipmap_filter == SamplerState::Filter::Linear)
|
||||||
unsigned int mip = d3dMipFilters[state.min_filter & 3];
|
|
||||||
|
|
||||||
if (state.max_anisotropy > 1 && !SamplerCommon::IsBpTexMode0PointFiltering(state))
|
|
||||||
{
|
{
|
||||||
sampdc.Filter = D3D11_FILTER_ANISOTROPIC;
|
if (state.min_filter == SamplerState::Filter::Linear)
|
||||||
sampdc.MaxAnisotropy = (u32)state.max_anisotropy;
|
sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||||
|
D3D11_FILTER_MIN_MAG_MIP_LINEAR :
|
||||||
|
D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
|
||||||
|
else
|
||||||
|
sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||||
|
D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR :
|
||||||
|
D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
|
||||||
}
|
}
|
||||||
else if (state.min_filter & 4) // linear min filter
|
else
|
||||||
{
|
{
|
||||||
if (state.mag_filter) // linear mag filter
|
if (state.min_filter == SamplerState::Filter::Linear)
|
||||||
{
|
sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||||
if (mip == TexMode0::TEXF_NONE)
|
D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT :
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
||||||
else if (mip == TexMode0::TEXF_POINT)
|
else
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ?
|
||||||
else if (mip == TexMode0::TEXF_LINEAR)
|
D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT :
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||||
}
|
|
||||||
else // point mag filter
|
|
||||||
{
|
|
||||||
if (mip == TexMode0::TEXF_NONE)
|
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
|
||||||
else if (mip == TexMode0::TEXF_POINT)
|
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
|
||||||
else if (mip == TexMode0::TEXF_LINEAR)
|
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // point min filter
|
|
||||||
{
|
|
||||||
if (state.mag_filter) // linear mag filter
|
|
||||||
{
|
|
||||||
if (mip == TexMode0::TEXF_NONE)
|
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
|
|
||||||
else if (mip == TexMode0::TEXF_POINT)
|
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
|
|
||||||
else if (mip == TexMode0::TEXF_LINEAR)
|
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
|
|
||||||
}
|
|
||||||
else // point mag filter
|
|
||||||
{
|
|
||||||
if (mip == TexMode0::TEXF_NONE)
|
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
|
||||||
else if (mip == TexMode0::TEXF_POINT)
|
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
|
||||||
else if (mip == TexMode0::TEXF_LINEAR)
|
|
||||||
sampdc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sampdc.AddressU = d3dClamps[state.wrap_s];
|
static constexpr std::array<D3D11_TEXTURE_ADDRESS_MODE, 3> address_modes = {
|
||||||
sampdc.AddressV = d3dClamps[state.wrap_t];
|
{D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_WRAP, D3D11_TEXTURE_ADDRESS_MIRROR}};
|
||||||
|
sampdc.AddressU = address_modes[static_cast<u32>(state.wrap_u.Value())];
|
||||||
sampdc.MaxLOD = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f;
|
sampdc.AddressV = address_modes[static_cast<u32>(state.wrap_v.Value())];
|
||||||
sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD);
|
sampdc.MaxLOD = state.max_lod / 16.f;
|
||||||
|
sampdc.MinLOD = state.min_lod / 16.f;
|
||||||
sampdc.MipLODBias = (s32)state.lod_bias / 32.0f;
|
sampdc.MipLODBias = (s32)state.lod_bias / 32.0f;
|
||||||
|
|
||||||
ID3D11SamplerState* res = nullptr;
|
if (state.anisotropic_filtering)
|
||||||
|
{
|
||||||
|
sampdc.Filter = D3D11_FILTER_ANISOTROPIC;
|
||||||
|
sampdc.MaxAnisotropy = 1u << g_ActiveConfig.iMaxAnisotropy;
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D11SamplerState* res = nullptr;
|
||||||
HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res);
|
HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
PanicAlert("Fail %s %d\n", __FILE__, __LINE__);
|
PanicAlert("Fail %s %d\n", __FILE__, __LINE__);
|
||||||
|
|
||||||
D3D::SetDebugObjectName(res, "sampler state used to emulate the GX pipeline");
|
D3D::SetDebugObjectName(res, "sampler state used to emulate the GX pipeline");
|
||||||
m_sampler.emplace(state.packed, res);
|
m_sampler.emplace(state.hex, res);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,20 +20,6 @@ struct ID3D11RasterizerState;
|
||||||
|
|
||||||
namespace DX11
|
namespace DX11
|
||||||
{
|
{
|
||||||
union SamplerState
|
|
||||||
{
|
|
||||||
BitField<0, 3, u64> min_filter;
|
|
||||||
BitField<3, 1, u64> mag_filter;
|
|
||||||
BitField<4, 8, u64> min_lod;
|
|
||||||
BitField<12, 8, u64> max_lod;
|
|
||||||
BitField<20, 8, s64> lod_bias;
|
|
||||||
BitField<28, 2, u64> wrap_s;
|
|
||||||
BitField<30, 2, u64> wrap_t;
|
|
||||||
BitField<32, 5, u64> max_anisotropy;
|
|
||||||
|
|
||||||
u64 packed;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StateCache
|
class StateCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -54,7 +40,7 @@ private:
|
||||||
std::unordered_map<u32, ID3D11DepthStencilState*> m_depth;
|
std::unordered_map<u32, ID3D11DepthStencilState*> m_depth;
|
||||||
std::unordered_map<u32, ID3D11RasterizerState*> m_raster;
|
std::unordered_map<u32, ID3D11RasterizerState*> m_raster;
|
||||||
std::unordered_map<u32, ID3D11BlendState*> m_blend;
|
std::unordered_map<u32, ID3D11BlendState*> m_blend;
|
||||||
std::unordered_map<u64, ID3D11SamplerState*> m_sampler;
|
std::unordered_map<u32, ID3D11SamplerState*> m_sampler;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace D3D
|
namespace D3D
|
||||||
|
|
|
@ -249,7 +249,7 @@ Renderer::Renderer() : ::Renderer(D3D::GetBackBufferWidth(), D3D::GetBackBufferH
|
||||||
|
|
||||||
// Setup GX pipeline state
|
// Setup GX pipeline state
|
||||||
for (auto& sampler : s_gx_state.samplers)
|
for (auto& sampler : s_gx_state.samplers)
|
||||||
sampler.packed = 0;
|
sampler.hex = RenderState::GetPointSamplerState().hex;
|
||||||
|
|
||||||
s_gx_state.zmode.testenable = false;
|
s_gx_state.zmode.testenable = false;
|
||||||
s_gx_state.zmode.updateenable = false;
|
s_gx_state.zmode.updateenable = false;
|
||||||
|
@ -870,12 +870,8 @@ void Renderer::ApplyState()
|
||||||
StateCache::GetPrimitiveTopology(s_gx_state.raster.primitive));
|
StateCache::GetPrimitiveTopology(s_gx_state.raster.primitive));
|
||||||
FramebufferManager::SetIntegerEFBRenderTarget(s_gx_state.blend.logicopenable);
|
FramebufferManager::SetIntegerEFBRenderTarget(s_gx_state.blend.logicopenable);
|
||||||
|
|
||||||
for (size_t stage = 0; stage < s_gx_state.samplers.size(); stage++)
|
for (u32 stage = 0; stage < static_cast<u32>(s_gx_state.samplers.size()); stage++)
|
||||||
{
|
|
||||||
// TODO: cache SamplerState directly, not d3d object
|
|
||||||
s_gx_state.samplers[stage].max_anisotropy = UINT64_C(1) << g_ActiveConfig.iMaxAnisotropy;
|
|
||||||
D3D::stateman->SetSampler(stage, s_gx_state_cache.Get(s_gx_state.samplers[stage]));
|
D3D::stateman->SetSampler(stage, s_gx_state_cache.Get(s_gx_state.samplers[stage]));
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11Buffer* vertexConstants = VertexShaderCache::GetConstantBuffer();
|
ID3D11Buffer* vertexConstants = VertexShaderCache::GetConstantBuffer();
|
||||||
|
|
||||||
|
@ -902,38 +898,9 @@ void Renderer::SetDepthState(const DepthState& state)
|
||||||
s_gx_state.zmode.hex = state.hex;
|
s_gx_state.zmode.hex = state.hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex)
|
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
|
||||||
{
|
{
|
||||||
const FourTexUnits& tex = bpmem.tex[texindex];
|
s_gx_state.samplers[index].hex = state.hex;
|
||||||
const TexMode0& tm0 = tex.texMode0[stage];
|
|
||||||
const TexMode1& tm1 = tex.texMode1[stage];
|
|
||||||
|
|
||||||
if (texindex)
|
|
||||||
stage += 4;
|
|
||||||
|
|
||||||
if (g_ActiveConfig.bForceFiltering)
|
|
||||||
{
|
|
||||||
// Only use mipmaps if the game says they are available.
|
|
||||||
s_gx_state.samplers[stage].min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4;
|
|
||||||
s_gx_state.samplers[stage].mag_filter = 1; // linear mag
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_gx_state.samplers[stage].min_filter = (u32)tm0.min_filter;
|
|
||||||
s_gx_state.samplers[stage].mag_filter = (u32)tm0.mag_filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_gx_state.samplers[stage].wrap_s = (u32)tm0.wrap_s;
|
|
||||||
s_gx_state.samplers[stage].wrap_t = (u32)tm0.wrap_t;
|
|
||||||
s_gx_state.samplers[stage].max_lod = (u32)tm1.max_lod;
|
|
||||||
s_gx_state.samplers[stage].min_lod = (u32)tm1.min_lod;
|
|
||||||
s_gx_state.samplers[stage].lod_bias = (s32)tm0.lod_bias;
|
|
||||||
|
|
||||||
// custom textures may have higher resolution, so disable the max_lod
|
|
||||||
if (custom_tex)
|
|
||||||
{
|
|
||||||
s_gx_state.samplers[stage].max_lod = 255;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetInterlacingMode()
|
void Renderer::SetInterlacingMode()
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
void SetScissorRect(const EFBRectangle& rc) override;
|
void SetScissorRect(const EFBRectangle& rc) override;
|
||||||
void SetRasterizationState(const RasterizationState& state) override;
|
void SetRasterizationState(const RasterizationState& state) override;
|
||||||
void SetDepthState(const DepthState& state) override;
|
void SetDepthState(const DepthState& state) override;
|
||||||
void SetSamplerState(int stage, int texindex, bool custom_tex) override;
|
void SetSamplerState(u32 index, const SamplerState& state) override;
|
||||||
void SetInterlacingMode() override;
|
void SetInterlacingMode() override;
|
||||||
void SetViewport() override;
|
void SetViewport() override;
|
||||||
void SetFullscreen(bool enable_fullscreen) override;
|
void SetFullscreen(bool enable_fullscreen) override;
|
||||||
|
|
|
@ -1119,7 +1119,8 @@ bool ProgramShaderCache::ShaderCompileWorkItem::Compile()
|
||||||
gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, m_uid.guid.GetUidData());
|
gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, m_uid.guid.GetUidData());
|
||||||
|
|
||||||
CompileShader(m_program, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer());
|
CompileShader(m_program, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer());
|
||||||
DrawPrerenderArray(m_program, m_uid.guid.GetUidData()->primitive_type);
|
DrawPrerenderArray(m_program,
|
||||||
|
static_cast<PrimitiveType>(m_uid.guid.GetUidData()->primitive_type));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1157,7 +1158,8 @@ bool ProgramShaderCache::UberShaderCompileWorkItem::Compile()
|
||||||
gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, m_uid.guid.GetUidData());
|
gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, m_uid.guid.GetUidData());
|
||||||
|
|
||||||
CompileShader(m_program, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer());
|
CompileShader(m_program, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer());
|
||||||
DrawPrerenderArray(m_program, m_uid.guid.GetUidData()->primitive_type);
|
DrawPrerenderArray(m_program,
|
||||||
|
static_cast<PrimitiveType>(m_uid.guid.GetUidData()->primitive_type));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1503,9 +1503,13 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
||||||
|
|
||||||
g_Config.iSaveTargetId = 0;
|
g_Config.iSaveTargetId = 0;
|
||||||
|
|
||||||
|
int old_anisotropy = g_ActiveConfig.iMaxAnisotropy;
|
||||||
UpdateActiveConfig();
|
UpdateActiveConfig();
|
||||||
g_texture_cache->OnConfigChanged(g_ActiveConfig);
|
g_texture_cache->OnConfigChanged(g_ActiveConfig);
|
||||||
|
|
||||||
|
if (old_anisotropy != g_ActiveConfig.iMaxAnisotropy)
|
||||||
|
g_sampler_cache->Clear();
|
||||||
|
|
||||||
// Invalidate shader cache when the host config changes.
|
// Invalidate shader cache when the host config changes.
|
||||||
if (CheckForHostConfigChanges())
|
if (CheckForHostConfigChanges())
|
||||||
ProgramShaderCache::Reload();
|
ProgramShaderCache::Reload();
|
||||||
|
@ -1834,13 +1838,9 @@ void Renderer::SetDepthState(const DepthState& state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex)
|
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
|
||||||
{
|
{
|
||||||
auto const& tex = bpmem.tex[texindex];
|
g_sampler_cache->SetSamplerState(index, state);
|
||||||
auto const& tm0 = tex.texMode0[stage];
|
|
||||||
auto const& tm1 = tex.texMode1[stage];
|
|
||||||
|
|
||||||
g_sampler_cache->SetSamplerState((texindex * 4) + stage, tm0, tm1, custom_tex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetInterlacingMode()
|
void Renderer::SetInterlacingMode()
|
||||||
|
|
|
@ -81,7 +81,7 @@ public:
|
||||||
void SetScissorRect(const EFBRectangle& rc) override;
|
void SetScissorRect(const EFBRectangle& rc) override;
|
||||||
void SetRasterizationState(const RasterizationState& state) override;
|
void SetRasterizationState(const RasterizationState& state) override;
|
||||||
void SetDepthState(const DepthState& state) override;
|
void SetDepthState(const DepthState& state) override;
|
||||||
void SetSamplerState(int stage, int texindex, bool custom_tex) override;
|
void SetSamplerState(u32 index, const SamplerState& state) override;
|
||||||
void SetInterlacingMode() override;
|
void SetInterlacingMode() override;
|
||||||
void SetViewport() override;
|
void SetViewport() override;
|
||||||
|
|
||||||
|
|
|
@ -15,141 +15,106 @@ namespace OGL
|
||||||
{
|
{
|
||||||
std::unique_ptr<SamplerCache> g_sampler_cache;
|
std::unique_ptr<SamplerCache> g_sampler_cache;
|
||||||
|
|
||||||
SamplerCache::SamplerCache() : m_last_max_anisotropy()
|
SamplerCache::SamplerCache()
|
||||||
{
|
{
|
||||||
glGenSamplers(2, m_sampler_id);
|
glGenSamplers(1, &m_point_sampler);
|
||||||
glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glGenSamplers(1, &m_linear_sampler);
|
||||||
glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glSamplerParameteri(m_point_sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glSamplerParameteri(m_point_sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glSamplerParameteri(m_point_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glSamplerParameteri(m_point_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glSamplerParameteri(m_linear_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glSamplerParameteri(m_linear_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glSamplerParameteri(m_linear_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glSamplerParameteri(m_linear_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
SamplerCache::~SamplerCache()
|
SamplerCache::~SamplerCache()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
glDeleteSamplers(2, m_sampler_id);
|
glDeleteSamplers(1, &m_point_sampler);
|
||||||
|
glDeleteSamplers(1, &m_linear_sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SamplerCache::BindNearestSampler(int stage)
|
void SamplerCache::BindNearestSampler(int stage)
|
||||||
{
|
{
|
||||||
glBindSampler(stage, m_sampler_id[0]);
|
glBindSampler(stage, m_point_sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SamplerCache::BindLinearSampler(int stage)
|
void SamplerCache::BindLinearSampler(int stage)
|
||||||
{
|
{
|
||||||
glBindSampler(stage, m_sampler_id[1]);
|
glBindSampler(stage, m_linear_sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1,
|
void SamplerCache::SetSamplerState(u32 stage, const SamplerState& state)
|
||||||
bool custom_tex)
|
|
||||||
{
|
{
|
||||||
// TODO: can this go somewhere else?
|
if (m_active_samplers[stage].first == state && m_active_samplers[stage].second != 0)
|
||||||
if (m_last_max_anisotropy != g_ActiveConfig.iMaxAnisotropy)
|
return;
|
||||||
|
|
||||||
|
auto it = m_cache.find(state);
|
||||||
|
if (it == m_cache.end())
|
||||||
{
|
{
|
||||||
m_last_max_anisotropy = g_ActiveConfig.iMaxAnisotropy;
|
GLuint sampler;
|
||||||
Clear();
|
glGenSamplers(1, &sampler);
|
||||||
|
SetParameters(sampler, state);
|
||||||
|
it = m_cache.emplace(state, sampler).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
Params params(tm0, tm1);
|
m_active_samplers[stage].first = state;
|
||||||
|
m_active_samplers[stage].second = it->second;
|
||||||
// take equivalent forced linear when bForceFiltering
|
glBindSampler(stage, it->second);
|
||||||
if (g_ActiveConfig.bForceFiltering)
|
|
||||||
{
|
|
||||||
params.tm0.min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4;
|
|
||||||
params.tm0.mag_filter = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom textures may have higher resolution, so disable the max_lod
|
|
||||||
if (custom_tex)
|
|
||||||
{
|
|
||||||
params.tm1.max_lod = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Should keep a circular buffer for each stage of recently used samplers.
|
|
||||||
|
|
||||||
auto& active_sampler = m_active_samplers[stage];
|
|
||||||
if (active_sampler.first != params || !active_sampler.second.sampler_id)
|
|
||||||
{
|
|
||||||
// Active sampler does not match parameters (or is invalid), bind the proper one.
|
|
||||||
active_sampler.first = params;
|
|
||||||
active_sampler.second = GetEntry(params);
|
|
||||||
glBindSampler(stage, active_sampler.second.sampler_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SamplerCache::Value& SamplerCache::GetEntry(const Params& params)
|
void SamplerCache::InvalidateBinding(u32 stage)
|
||||||
{
|
{
|
||||||
auto& val = m_cache[params];
|
m_active_samplers[stage].second = 0;
|
||||||
if (!val.sampler_id)
|
|
||||||
{
|
|
||||||
// Sampler not found in cache, create it.
|
|
||||||
glGenSamplers(1, &val.sampler_id);
|
|
||||||
SetParameters(val.sampler_id, params);
|
|
||||||
|
|
||||||
// TODO: Maybe kill old samplers if the cache gets huge. It doesn't seem to get huge though.
|
|
||||||
// ERROR_LOG(VIDEO, "Sampler cache size is now %ld.", m_cache.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SamplerCache::SetParameters(GLuint sampler_id, const Params& params)
|
void SamplerCache::SetParameters(GLuint sampler_id, const SamplerState& params)
|
||||||
{
|
{
|
||||||
static const GLint min_filters[8] = {
|
GLenum min_filter;
|
||||||
GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST,
|
GLenum mag_filter = (params.mag_filter == SamplerState::Filter::Point) ? GL_NEAREST : GL_LINEAR;
|
||||||
GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR,
|
if (params.mipmap_filter == SamplerState::Filter::Linear)
|
||||||
};
|
|
||||||
|
|
||||||
static const GLint wrap_settings[4] = {
|
|
||||||
GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT, GL_REPEAT,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto& tm0 = params.tm0;
|
|
||||||
auto& tm1 = params.tm1;
|
|
||||||
|
|
||||||
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, wrap_settings[tm0.wrap_s]);
|
|
||||||
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, wrap_settings[tm0.wrap_t]);
|
|
||||||
|
|
||||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, tm1.min_lod / 16.f);
|
|
||||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, tm1.max_lod / 16.f);
|
|
||||||
|
|
||||||
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
|
|
||||||
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, (s32)tm0.lod_bias / 32.f);
|
|
||||||
|
|
||||||
GLint min_filter = min_filters[tm0.min_filter];
|
|
||||||
GLint mag_filter = tm0.mag_filter ? GL_LINEAR : GL_NEAREST;
|
|
||||||
|
|
||||||
if (g_ActiveConfig.iMaxAnisotropy > 0 && g_ogl_config.bSupportsAniso &&
|
|
||||||
!SamplerCommon::IsBpTexMode0PointFiltering(tm0))
|
|
||||||
{
|
{
|
||||||
// https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
|
min_filter = (params.min_filter == SamplerState::Filter::Point) ? GL_NEAREST_MIPMAP_LINEAR :
|
||||||
// For predictable results on all hardware/drivers, only use one of:
|
GL_LINEAR_MIPMAP_LINEAR;
|
||||||
// GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear])
|
}
|
||||||
// GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear])
|
else
|
||||||
// Letting the game set other combinations will have varying arbitrary results;
|
{
|
||||||
// possibly being interpreted as equal to bilinear/trilinear, implicitly
|
min_filter = (params.min_filter == SamplerState::Filter::Point) ? GL_NEAREST_MIPMAP_NEAREST :
|
||||||
// disabling anisotropy, or changing the anisotropic algorithm employed.
|
GL_LINEAR_MIPMAP_NEAREST;
|
||||||
min_filter =
|
|
||||||
SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
|
|
||||||
mag_filter = GL_LINEAR;
|
|
||||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
|
||||||
(float)(1 << g_ActiveConfig.iMaxAnisotropy));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filter);
|
glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filter);
|
||||||
glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, mag_filter);
|
glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, mag_filter);
|
||||||
|
|
||||||
|
static constexpr std::array<GLenum, 3> address_modes = {
|
||||||
|
{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())]);
|
||||||
|
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T,
|
||||||
|
address_modes[static_cast<u32>(params.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);
|
||||||
|
|
||||||
|
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
|
||||||
|
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, params.lod_bias / 32.f);
|
||||||
|
|
||||||
|
if (params.anisotropic_filtering && g_ogl_config.bSupportsAniso)
|
||||||
|
{
|
||||||
|
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||||
|
static_cast<float>(1 << g_ActiveConfig.iMaxAnisotropy));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SamplerCache::Clear()
|
void SamplerCache::Clear()
|
||||||
{
|
{
|
||||||
for (auto& p : m_cache)
|
for (auto& p : m_cache)
|
||||||
{
|
glDeleteSamplers(1, &p.second);
|
||||||
glDeleteSamplers(1, &p.second.sampler_id);
|
for (auto& p : m_active_samplers)
|
||||||
}
|
p.second = 0;
|
||||||
m_cache.clear();
|
m_cache.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -24,49 +25,21 @@ public:
|
||||||
SamplerCache(SamplerCache&&) = delete;
|
SamplerCache(SamplerCache&&) = delete;
|
||||||
SamplerCache& operator=(SamplerCache&&) = delete;
|
SamplerCache& operator=(SamplerCache&&) = delete;
|
||||||
|
|
||||||
void SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1, bool custom_tex);
|
void SetSamplerState(u32 stage, const SamplerState& state);
|
||||||
|
void InvalidateBinding(u32 stage);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
void BindNearestSampler(int stage);
|
void BindNearestSampler(int stage);
|
||||||
void BindLinearSampler(int stage);
|
void BindLinearSampler(int stage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Params
|
static void SetParameters(GLuint sampler_id, const SamplerState& params);
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
TexMode0 tm0;
|
|
||||||
TexMode1 tm1;
|
|
||||||
};
|
|
||||||
|
|
||||||
u64 hex;
|
std::map<SamplerState, GLuint> m_cache;
|
||||||
};
|
std::array<std::pair<SamplerState, GLuint>, 8> m_active_samplers{};
|
||||||
|
|
||||||
Params() : hex() {}
|
GLuint m_point_sampler;
|
||||||
Params(const TexMode0& _tm0, const TexMode1& _tm1) : tm0(_tm0), tm1(_tm1)
|
GLuint m_linear_sampler;
|
||||||
{
|
|
||||||
static_assert(sizeof(Params) == 8, "Assuming I can treat this as a 64bit int.");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const Params& other) const { return hex < other.hex; }
|
|
||||||
bool operator!=(const Params& other) const { return hex != other.hex; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Value
|
|
||||||
{
|
|
||||||
Value() : sampler_id() {}
|
|
||||||
GLuint sampler_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetParameters(GLuint sampler_id, const Params& params);
|
|
||||||
Value& GetEntry(const Params& params);
|
|
||||||
|
|
||||||
std::map<Params, Value> m_cache;
|
|
||||||
std::pair<Params, Value> m_active_samplers[8];
|
|
||||||
|
|
||||||
int m_last_max_anisotropy;
|
|
||||||
u32 m_sampler_id[2];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::unique_ptr<SamplerCache> g_sampler_cache;
|
extern std::unique_ptr<SamplerCache> g_sampler_cache;
|
||||||
|
|
|
@ -132,20 +132,4 @@ union MultisamplingState
|
||||||
u32 hex;
|
u32 hex;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sampler info
|
|
||||||
union SamplerState
|
|
||||||
{
|
|
||||||
BitField<0, 1, VkFilter> min_filter;
|
|
||||||
BitField<1, 1, VkFilter> mag_filter;
|
|
||||||
BitField<2, 1, VkSamplerMipmapMode> mipmap_mode;
|
|
||||||
BitField<3, 2, VkSamplerAddressMode> wrap_u;
|
|
||||||
BitField<5, 2, VkSamplerAddressMode> wrap_v;
|
|
||||||
BitField<7, 8, u32> min_lod;
|
|
||||||
BitField<15, 8, u32> max_lod;
|
|
||||||
BitField<23, 8, s32> lod_bias;
|
|
||||||
BitField<31, 1, u32> enable_anisotropic_filtering;
|
|
||||||
|
|
||||||
u32 bits;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -312,29 +312,36 @@ VkSampler ObjectCache::GetSampler(const SamplerState& info)
|
||||||
if (iter != m_sampler_cache.end())
|
if (iter != m_sampler_cache.end())
|
||||||
return iter->second;
|
return iter->second;
|
||||||
|
|
||||||
|
static constexpr std::array<VkFilter, 4> filters = {{VK_FILTER_NEAREST, VK_FILTER_LINEAR}};
|
||||||
|
static constexpr std::array<VkSamplerMipmapMode, 2> mipmap_modes = {
|
||||||
|
{VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR}};
|
||||||
|
static constexpr std::array<VkSamplerAddressMode, 4> address_modes = {
|
||||||
|
{VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||||
|
VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT}};
|
||||||
|
|
||||||
VkSamplerCreateInfo create_info = {
|
VkSamplerCreateInfo create_info = {
|
||||||
VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType
|
||||||
nullptr, // const void* pNext
|
nullptr, // const void* pNext
|
||||||
0, // VkSamplerCreateFlags flags
|
0, // VkSamplerCreateFlags flags
|
||||||
info.mag_filter, // VkFilter magFilter
|
filters[static_cast<u32>(info.mag_filter.Value())], // VkFilter magFilter
|
||||||
info.min_filter, // VkFilter minFilter
|
filters[static_cast<u32>(info.min_filter.Value())], // VkFilter minFilter
|
||||||
info.mipmap_mode, // VkSamplerMipmapMode mipmapMode
|
mipmap_modes[static_cast<u32>(info.mipmap_filter.Value())], // VkSamplerMipmapMode mipmapMode
|
||||||
info.wrap_u, // VkSamplerAddressMode addressModeU
|
address_modes[static_cast<u32>(info.wrap_u.Value())], // VkSamplerAddressMode addressModeU
|
||||||
info.wrap_v, // VkSamplerAddressMode addressModeV
|
address_modes[static_cast<u32>(info.wrap_v.Value())], // VkSamplerAddressMode addressModeV
|
||||||
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW
|
||||||
static_cast<float>(info.lod_bias / 32.0f), // float mipLodBias
|
info.lod_bias / 32.0f, // float mipLodBias
|
||||||
VK_FALSE, // VkBool32 anisotropyEnable
|
VK_FALSE, // VkBool32 anisotropyEnable
|
||||||
0.0f, // float maxAnisotropy
|
0.0f, // float maxAnisotropy
|
||||||
VK_FALSE, // VkBool32 compareEnable
|
VK_FALSE, // VkBool32 compareEnable
|
||||||
VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp
|
VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp
|
||||||
static_cast<float>(info.min_lod / 16.0f), // float minLod
|
info.min_lod / 16.0f, // float minLod
|
||||||
static_cast<float>(info.max_lod / 16.0f), // float maxLod
|
info.max_lod / 16.0f, // float maxLod
|
||||||
VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor
|
VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor
|
||||||
VK_FALSE // VkBool32 unnormalizedCoordinates
|
VK_FALSE // VkBool32 unnormalizedCoordinates
|
||||||
};
|
};
|
||||||
|
|
||||||
// Can we use anisotropic filtering with this sampler?
|
// Can we use anisotropic filtering with this sampler?
|
||||||
if (info.enable_anisotropic_filtering && g_vulkan_context->SupportsAnisotropicFiltering())
|
if (info.anisotropic_filtering && g_vulkan_context->SupportsAnisotropicFiltering())
|
||||||
{
|
{
|
||||||
// Cap anisotropy to device limits.
|
// Cap anisotropy to device limits.
|
||||||
create_info.anisotropyEnable = VK_TRUE;
|
create_info.anisotropyEnable = VK_TRUE;
|
||||||
|
|
|
@ -52,10 +52,8 @@ Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain)
|
||||||
m_swap_chain(std::move(swap_chain))
|
m_swap_chain(std::move(swap_chain))
|
||||||
{
|
{
|
||||||
UpdateActiveConfig();
|
UpdateActiveConfig();
|
||||||
|
|
||||||
// Set to something invalid, forcing all states to be re-initialized.
|
|
||||||
for (size_t i = 0; i < m_sampler_states.size(); i++)
|
for (size_t i = 0; i < m_sampler_states.size(); i++)
|
||||||
m_sampler_states[i].bits = std::numeric_limits<decltype(m_sampler_states[i].bits)>::max();
|
m_sampler_states[i].hex = RenderState::GetPointSamplerState().hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::~Renderer()
|
Renderer::~Renderer()
|
||||||
|
@ -1282,65 +1280,22 @@ void Renderer::SetBlendingState(const BlendingState& state)
|
||||||
StateTracker::GetInstance()->SetBlendState(state);
|
StateTracker::GetInstance()->SetBlendState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex)
|
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
|
||||||
{
|
{
|
||||||
const FourTexUnits& tex = bpmem.tex[texindex];
|
|
||||||
const TexMode0& tm0 = tex.texMode0[stage];
|
|
||||||
const TexMode1& tm1 = tex.texMode1[stage];
|
|
||||||
SamplerState new_state = {};
|
|
||||||
|
|
||||||
if (g_ActiveConfig.bForceFiltering)
|
|
||||||
{
|
|
||||||
new_state.min_filter = VK_FILTER_LINEAR;
|
|
||||||
new_state.mag_filter = VK_FILTER_LINEAR;
|
|
||||||
new_state.mipmap_mode = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ?
|
|
||||||
VK_SAMPLER_MIPMAP_MODE_LINEAR :
|
|
||||||
VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Constants for these?
|
|
||||||
new_state.min_filter = (tm0.min_filter & 4) != 0 ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
|
||||||
new_state.mipmap_mode = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ?
|
|
||||||
VK_SAMPLER_MIPMAP_MODE_LINEAR :
|
|
||||||
VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
new_state.mag_filter = tm0.mag_filter != 0 ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If mipmaps are disabled, clamp min/max lod
|
|
||||||
new_state.max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod : 0;
|
|
||||||
new_state.min_lod = std::min(new_state.max_lod.Value(), tm1.min_lod);
|
|
||||||
new_state.lod_bias = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm0.lod_bias : 0;
|
|
||||||
|
|
||||||
// Custom textures may have a greater number of mips
|
|
||||||
if (custom_tex)
|
|
||||||
new_state.max_lod = 255;
|
|
||||||
|
|
||||||
// Address modes
|
|
||||||
static const VkSamplerAddressMode address_modes[] = {
|
|
||||||
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
|
||||||
VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT};
|
|
||||||
new_state.wrap_u = address_modes[tm0.wrap_s];
|
|
||||||
new_state.wrap_v = address_modes[tm0.wrap_t];
|
|
||||||
|
|
||||||
// Only use anisotropic filtering for textures that would be linearly filtered.
|
|
||||||
new_state.enable_anisotropic_filtering = SamplerCommon::IsBpTexMode0PointFiltering(tm0) ? 0 : 1;
|
|
||||||
|
|
||||||
// Skip lookup if the state hasn't changed.
|
// Skip lookup if the state hasn't changed.
|
||||||
size_t bind_index = (texindex * 4) + stage;
|
if (m_sampler_states[index].hex == state.hex)
|
||||||
if (m_sampler_states[bind_index].bits == new_state.bits)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Look up new state and replace in state tracker.
|
// Look up new state and replace in state tracker.
|
||||||
VkSampler sampler = g_object_cache->GetSampler(new_state);
|
VkSampler sampler = g_object_cache->GetSampler(state);
|
||||||
if (sampler == VK_NULL_HANDLE)
|
if (sampler == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
ERROR_LOG(VIDEO, "Failed to create sampler");
|
ERROR_LOG(VIDEO, "Failed to create sampler");
|
||||||
sampler = g_object_cache->GetPointSampler();
|
sampler = g_object_cache->GetPointSampler();
|
||||||
}
|
}
|
||||||
|
|
||||||
StateTracker::GetInstance()->SetSampler(bind_index, sampler);
|
StateTracker::GetInstance()->SetSampler(index, sampler);
|
||||||
m_sampler_states[bind_index].bits = new_state.bits;
|
m_sampler_states[index].hex = state.hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::ResetSamplerStates()
|
void Renderer::ResetSamplerStates()
|
||||||
|
@ -1352,7 +1307,7 @@ void Renderer::ResetSamplerStates()
|
||||||
// Invalidate all sampler states, next draw will re-initialize them.
|
// Invalidate all sampler states, next draw will re-initialize them.
|
||||||
for (size_t i = 0; i < m_sampler_states.size(); i++)
|
for (size_t i = 0; i < m_sampler_states.size(); i++)
|
||||||
{
|
{
|
||||||
m_sampler_states[i].bits = std::numeric_limits<decltype(m_sampler_states[i].bits)>::max();
|
m_sampler_states[i].hex = RenderState::GetPointSamplerState().hex;
|
||||||
StateTracker::GetInstance()->SetSampler(i, g_object_cache->GetPointSampler());
|
StateTracker::GetInstance()->SetSampler(i, g_object_cache->GetPointSampler());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ public:
|
||||||
void SetScissorRect(const EFBRectangle& rc) override;
|
void SetScissorRect(const EFBRectangle& rc) override;
|
||||||
void SetRasterizationState(const RasterizationState& state) override;
|
void SetRasterizationState(const RasterizationState& state) override;
|
||||||
void SetDepthState(const DepthState& state) override;
|
void SetDepthState(const DepthState& state) override;
|
||||||
void SetSamplerState(int stage, int texindex, bool custom_tex) override;
|
void SetSamplerState(u32 index, const SamplerState& state) override;
|
||||||
void SetInterlacingMode() override;
|
void SetInterlacingMode() override;
|
||||||
void SetViewport() override;
|
void SetViewport() override;
|
||||||
|
|
||||||
|
|
|
@ -977,18 +977,6 @@ std::string ShaderCache::GetUtilityShaderHeader() const
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comparison operators for PipelineInfos
|
|
||||||
// Since these all boil down to POD types, we can just memcmp the entire thing for speed
|
|
||||||
// The is_trivially_copyable check fails on MSVC due to BitField.
|
|
||||||
// TODO: Can we work around this any way?
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 && !defined(_MSC_VER)
|
|
||||||
static_assert(std::has_trivial_copy_constructor<PipelineInfo>::value,
|
|
||||||
"PipelineInfo is trivially copyable");
|
|
||||||
#elif !defined(_MSC_VER)
|
|
||||||
static_assert(std::is_trivially_copyable<PipelineInfo>::value,
|
|
||||||
"PipelineInfo is trivially copyable");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::size_t PipelineInfoHash::operator()(const PipelineInfo& key) const
|
std::size_t PipelineInfoHash::operator()(const PipelineInfo& key) const
|
||||||
{
|
{
|
||||||
return static_cast<std::size_t>(XXH64(&key, sizeof(key), 0));
|
return static_cast<std::size_t>(XXH64(&key, sizeof(key), 0));
|
||||||
|
@ -1014,26 +1002,6 @@ bool operator>(const PipelineInfo& lhs, const PipelineInfo& rhs)
|
||||||
return std::memcmp(&lhs, &rhs, sizeof(lhs)) > 0;
|
return std::memcmp(&lhs, &rhs, sizeof(lhs)) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const SamplerState& lhs, const SamplerState& rhs)
|
|
||||||
{
|
|
||||||
return lhs.bits == rhs.bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const SamplerState& lhs, const SamplerState& rhs)
|
|
||||||
{
|
|
||||||
return !operator==(lhs, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator>(const SamplerState& lhs, const SamplerState& rhs)
|
|
||||||
{
|
|
||||||
return lhs.bits > rhs.bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const SamplerState& lhs, const SamplerState& rhs)
|
|
||||||
{
|
|
||||||
return lhs.bits < rhs.bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t ComputePipelineInfoHash::operator()(const ComputePipelineInfo& key) const
|
std::size_t ComputePipelineInfoHash::operator()(const ComputePipelineInfo& key) const
|
||||||
{
|
{
|
||||||
return static_cast<std::size_t>(XXH64(&key, sizeof(key), 0));
|
return static_cast<std::size_t>(XXH64(&key, sizeof(key), 0));
|
||||||
|
@ -1214,7 +1182,8 @@ void ShaderCache::CreateDummyPipeline(const UberShader::VertexShaderUid& vuid,
|
||||||
pinfo.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex;
|
pinfo.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex;
|
||||||
pinfo.blend_state.hex = RenderState::GetNoBlendingBlendState().hex;
|
pinfo.blend_state.hex = RenderState::GetNoBlendingBlendState().hex;
|
||||||
pinfo.multisampling_state.hex = FramebufferManager::GetInstance()->GetEFBMultisamplingState().hex;
|
pinfo.multisampling_state.hex = FramebufferManager::GetInstance()->GetEFBMultisamplingState().hex;
|
||||||
pinfo.rasterization_state.primitive = guid.GetUidData()->primitive_type;
|
pinfo.rasterization_state.primitive =
|
||||||
|
static_cast<PrimitiveType>(guid.GetUidData()->primitive_type);
|
||||||
GetPipelineWithCacheResultAsync(pinfo);
|
GetPipelineWithCacheResultAsync(pinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,6 @@ bool operator==(const PipelineInfo& lhs, const PipelineInfo& rhs);
|
||||||
bool operator!=(const PipelineInfo& lhs, const PipelineInfo& rhs);
|
bool operator!=(const PipelineInfo& lhs, const PipelineInfo& rhs);
|
||||||
bool operator<(const PipelineInfo& lhs, const PipelineInfo& rhs);
|
bool operator<(const PipelineInfo& lhs, const PipelineInfo& rhs);
|
||||||
bool operator>(const PipelineInfo& lhs, const PipelineInfo& rhs);
|
bool operator>(const PipelineInfo& lhs, const PipelineInfo& rhs);
|
||||||
bool operator==(const SamplerState& lhs, const SamplerState& rhs);
|
|
||||||
bool operator!=(const SamplerState& lhs, const SamplerState& rhs);
|
|
||||||
bool operator>(const SamplerState& lhs, const SamplerState& rhs);
|
|
||||||
bool operator<(const SamplerState& lhs, const SamplerState& rhs);
|
|
||||||
|
|
||||||
struct ComputePipelineInfo
|
struct ComputePipelineInfo
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,7 @@ bool geometry_shader_uid_data::IsPassthrough() const
|
||||||
{
|
{
|
||||||
const bool stereo = g_ActiveConfig.iStereoMode > 0;
|
const bool stereo = g_ActiveConfig.iStereoMode > 0;
|
||||||
const bool wireframe = g_ActiveConfig.bWireFrame;
|
const bool wireframe = g_ActiveConfig.bWireFrame;
|
||||||
return primitive_type >= PrimitiveType::Triangles && !stereo && !wireframe;
|
return primitive_type >= static_cast<u32>(PrimitiveType::Triangles) && !stereo && !wireframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
GeometryShaderUid GetGeometryShaderUid(PrimitiveType primitive_type)
|
GeometryShaderUid GetGeometryShaderUid(PrimitiveType primitive_type)
|
||||||
|
@ -31,7 +31,7 @@ GeometryShaderUid GetGeometryShaderUid(PrimitiveType primitive_type)
|
||||||
geometry_shader_uid_data* uid_data = out.GetUidData<geometry_shader_uid_data>();
|
geometry_shader_uid_data* uid_data = out.GetUidData<geometry_shader_uid_data>();
|
||||||
memset(uid_data, 0, sizeof(geometry_shader_uid_data));
|
memset(uid_data, 0, sizeof(geometry_shader_uid_data));
|
||||||
|
|
||||||
uid_data->primitive_type = primitive_type;
|
uid_data->primitive_type = static_cast<u32>(primitive_type);
|
||||||
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
|
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
@ -56,9 +56,10 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
|
||||||
const bool msaa = host_config.msaa;
|
const bool msaa = host_config.msaa;
|
||||||
const bool ssaa = host_config.ssaa;
|
const bool ssaa = host_config.ssaa;
|
||||||
const bool stereo = host_config.stereo;
|
const bool stereo = host_config.stereo;
|
||||||
|
const PrimitiveType primitive_type = static_cast<PrimitiveType>(uid_data->primitive_type);
|
||||||
const unsigned primitive_type_index = static_cast<unsigned>(uid_data->primitive_type);
|
const unsigned primitive_type_index = static_cast<unsigned>(uid_data->primitive_type);
|
||||||
const unsigned vertex_in = std::min(static_cast<unsigned>(primitive_type_index) + 1, 3u);
|
const unsigned vertex_in = std::min(static_cast<unsigned>(primitive_type_index) + 1, 3u);
|
||||||
unsigned vertex_out = uid_data->primitive_type == PrimitiveType::TriangleStrip ? 3 : 4;
|
unsigned vertex_out = primitive_type == PrimitiveType::TriangleStrip ? 3 : 4;
|
||||||
|
|
||||||
if (wireframe)
|
if (wireframe)
|
||||||
vertex_out++;
|
vertex_out++;
|
||||||
|
@ -146,7 +147,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
|
||||||
out.Write("\tVertexData ps;\n");
|
out.Write("\tVertexData ps;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid_data->primitive_type == PrimitiveType::Lines)
|
if (primitive_type == PrimitiveType::Lines)
|
||||||
{
|
{
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
|
@ -177,7 +178,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
|
||||||
"\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n"
|
"\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n"
|
||||||
"\t}\n");
|
"\t}\n");
|
||||||
}
|
}
|
||||||
else if (uid_data->primitive_type == PrimitiveType::Points)
|
else if (primitive_type == PrimitiveType::Points)
|
||||||
{
|
{
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
|
@ -247,7 +248,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
|
||||||
out.Write("\tf.pos.x += hoffset * (f.pos.w - " I_STEREOPARAMS ".z);\n");
|
out.Write("\tf.pos.x += hoffset * (f.pos.w - " I_STEREOPARAMS ".z);\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid_data->primitive_type == PrimitiveType::Lines)
|
if (primitive_type == PrimitiveType::Lines)
|
||||||
{
|
{
|
||||||
out.Write("\tVS_OUTPUT l = f;\n"
|
out.Write("\tVS_OUTPUT l = f;\n"
|
||||||
"\tVS_OUTPUT r = f;\n");
|
"\tVS_OUTPUT r = f;\n");
|
||||||
|
@ -268,7 +269,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
|
||||||
EmitVertex(out, host_config, uid_data, "l", ApiType, wireframe, pixel_lighting, true);
|
EmitVertex(out, host_config, uid_data, "l", ApiType, wireframe, pixel_lighting, true);
|
||||||
EmitVertex(out, host_config, uid_data, "r", ApiType, wireframe, pixel_lighting);
|
EmitVertex(out, host_config, uid_data, "r", ApiType, wireframe, pixel_lighting);
|
||||||
}
|
}
|
||||||
else if (uid_data->primitive_type == PrimitiveType::Points)
|
else if (primitive_type == PrimitiveType::Points)
|
||||||
{
|
{
|
||||||
out.Write("\tVS_OUTPUT ll = f;\n"
|
out.Write("\tVS_OUTPUT ll = f;\n"
|
||||||
"\tVS_OUTPUT lr = f;\n"
|
"\tVS_OUTPUT lr = f;\n"
|
||||||
|
@ -376,7 +377,7 @@ void EnumerateGeometryShaderUids(const std::function<void(const GeometryShaderUi
|
||||||
for (PrimitiveType primitive : primitive_lut)
|
for (PrimitiveType primitive : primitive_lut)
|
||||||
{
|
{
|
||||||
auto* guid = uid.GetUidData<geometry_shader_uid_data>();
|
auto* guid = uid.GetUidData<geometry_shader_uid_data>();
|
||||||
guid->primitive_type = primitive;
|
guid->primitive_type = static_cast<u32>(primitive);
|
||||||
|
|
||||||
for (u32 texgens = 0; texgens <= 8; texgens++)
|
for (u32 texgens = 0; texgens <= 8; texgens++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,7 @@ struct geometry_shader_uid_data
|
||||||
bool IsPassthrough() const;
|
bool IsPassthrough() const;
|
||||||
|
|
||||||
u32 numTexGens : 4;
|
u32 numTexGens : 4;
|
||||||
PrimitiveType primitive_type : 2;
|
u32 primitive_type : 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
virtual void SetScissorRect(const EFBRectangle& rc) {}
|
virtual void SetScissorRect(const EFBRectangle& rc) {}
|
||||||
virtual void SetRasterizationState(const RasterizationState& state) {}
|
virtual void SetRasterizationState(const RasterizationState& state) {}
|
||||||
virtual void SetDepthState(const DepthState& state) {}
|
virtual void SetDepthState(const DepthState& state) {}
|
||||||
virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {}
|
virtual void SetSamplerState(u32 index, const SamplerState& state) {}
|
||||||
virtual void SetInterlacingMode() {}
|
virtual void SetInterlacingMode() {}
|
||||||
virtual void SetViewport() {}
|
virtual void SetViewport() {}
|
||||||
virtual void SetFullscreen(bool enable_fullscreen) {}
|
virtual void SetFullscreen(bool enable_fullscreen) {}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "VideoCommon/RenderState.h"
|
#include "VideoCommon/RenderState.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include "VideoCommon/SamplerCommon.h"
|
||||||
|
|
||||||
void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_type)
|
void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_type)
|
||||||
{
|
{
|
||||||
|
@ -14,6 +17,12 @@ void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_ty
|
||||||
cullmode = GenMode::CULL_NONE;
|
cullmode = GenMode::CULL_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RasterizationState& RasterizationState::operator=(const RasterizationState& rhs)
|
||||||
|
{
|
||||||
|
hex = rhs.hex;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void DepthState::Generate(const BPMemory& bp)
|
void DepthState::Generate(const BPMemory& bp)
|
||||||
{
|
{
|
||||||
testenable = bp.zmode.testenable.Value();
|
testenable = bp.zmode.testenable.Value();
|
||||||
|
@ -21,6 +30,12 @@ void DepthState::Generate(const BPMemory& bp)
|
||||||
func = bp.zmode.func.Value();
|
func = bp.zmode.func.Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DepthState& DepthState::operator=(const DepthState& rhs)
|
||||||
|
{
|
||||||
|
hex = rhs.hex;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
// If the framebuffer format has no alpha channel, it is assumed to
|
// If the framebuffer format has no alpha channel, it is assumed to
|
||||||
// ONE on blending. As the backends may emulate this framebuffer
|
// ONE on blending. As the backends may emulate this framebuffer
|
||||||
// configuration with an alpha channel, we just drop all references
|
// configuration with an alpha channel, we just drop all references
|
||||||
|
@ -145,6 +160,43 @@ void BlendingState::Generate(const BPMemory& bp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlendingState& BlendingState::operator=(const BlendingState& rhs)
|
||||||
|
{
|
||||||
|
hex = rhs.hex;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SamplerState::Generate(const BPMemory& bp, u32 index)
|
||||||
|
{
|
||||||
|
const FourTexUnits& tex = bpmem.tex[index / 4];
|
||||||
|
const TexMode0& tm0 = tex.texMode0[index % 4];
|
||||||
|
const TexMode1& tm1 = tex.texMode1[index % 4];
|
||||||
|
|
||||||
|
// 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 & 4) != 0 ? Filter::Linear : Filter::Point;
|
||||||
|
mipmap_filter = (tm0.min_filter & 3) == TexMode0::TEXF_LINEAR ? Filter::Linear : Filter::Point;
|
||||||
|
mag_filter = tm0.mag_filter != 0 ? Filter::Linear : Filter::Point;
|
||||||
|
|
||||||
|
// If mipmaps are disabled, clamp min/max lod
|
||||||
|
max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod : 0;
|
||||||
|
min_lod = std::min(max_lod.Value(), tm1.min_lod);
|
||||||
|
lod_bias = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm0.lod_bias : 0;
|
||||||
|
|
||||||
|
// Address modes
|
||||||
|
static constexpr std::array<AddressMode, 4> address_modes = {
|
||||||
|
{AddressMode::Clamp, AddressMode::Repeat, AddressMode::MirroredRepeat, AddressMode::Repeat}};
|
||||||
|
wrap_u = address_modes[tm0.wrap_s];
|
||||||
|
wrap_v = address_modes[tm0.wrap_t];
|
||||||
|
anisotropic_filtering = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SamplerState& SamplerState::operator=(const SamplerState& rhs)
|
||||||
|
{
|
||||||
|
hex = rhs.hex;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
namespace RenderState
|
namespace RenderState
|
||||||
{
|
{
|
||||||
RasterizationState GetNoCullRasterizationState()
|
RasterizationState GetNoCullRasterizationState()
|
||||||
|
@ -177,4 +229,34 @@ BlendingState GetNoBlendingBlendState()
|
||||||
state.alphaupdate = true;
|
state.alphaupdate = true;
|
||||||
return state;
|
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;
|
||||||
|
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;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,11 @@ union RasterizationState
|
||||||
{
|
{
|
||||||
void Generate(const BPMemory& bp, PrimitiveType primitive_type);
|
void Generate(const BPMemory& bp, PrimitiveType primitive_type);
|
||||||
|
|
||||||
|
RasterizationState& operator=(const RasterizationState& rhs);
|
||||||
|
|
||||||
|
bool operator==(const RasterizationState& rhs) const { return hex == rhs.hex; }
|
||||||
|
bool operator!=(const RasterizationState& rhs) const { return hex != rhs.hex; }
|
||||||
|
bool operator<(const RasterizationState& rhs) const { return hex < rhs.hex; }
|
||||||
BitField<0, 2, GenMode::CullMode> cullmode;
|
BitField<0, 2, GenMode::CullMode> cullmode;
|
||||||
BitField<3, 2, PrimitiveType> primitive;
|
BitField<3, 2, PrimitiveType> primitive;
|
||||||
|
|
||||||
|
@ -31,6 +36,11 @@ union DepthState
|
||||||
{
|
{
|
||||||
void Generate(const BPMemory& bp);
|
void Generate(const BPMemory& bp);
|
||||||
|
|
||||||
|
DepthState& operator=(const DepthState& rhs);
|
||||||
|
|
||||||
|
bool operator==(const DepthState& rhs) const { return hex == rhs.hex; }
|
||||||
|
bool operator!=(const DepthState& rhs) const { return hex != rhs.hex; }
|
||||||
|
bool operator<(const DepthState& rhs) const { return hex < rhs.hex; }
|
||||||
BitField<0, 1, u32> testenable;
|
BitField<0, 1, u32> testenable;
|
||||||
BitField<1, 1, u32> updateenable;
|
BitField<1, 1, u32> updateenable;
|
||||||
BitField<2, 3, ZMode::CompareMode> func;
|
BitField<2, 3, ZMode::CompareMode> func;
|
||||||
|
@ -42,6 +52,11 @@ union BlendingState
|
||||||
{
|
{
|
||||||
void Generate(const BPMemory& bp);
|
void Generate(const BPMemory& bp);
|
||||||
|
|
||||||
|
BlendingState& operator=(const BlendingState& rhs);
|
||||||
|
|
||||||
|
bool operator==(const BlendingState& rhs) const { return hex == rhs.hex; }
|
||||||
|
bool operator!=(const BlendingState& rhs) const { return hex != rhs.hex; }
|
||||||
|
bool operator<(const BlendingState& rhs) const { return hex < rhs.hex; }
|
||||||
BitField<0, 1, u32> blendenable;
|
BitField<0, 1, u32> blendenable;
|
||||||
BitField<1, 1, u32> logicopenable;
|
BitField<1, 1, u32> logicopenable;
|
||||||
BitField<2, 1, u32> dstalpha;
|
BitField<2, 1, u32> dstalpha;
|
||||||
|
@ -59,9 +74,46 @@ union BlendingState
|
||||||
u32 hex;
|
u32 hex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union SamplerState
|
||||||
|
{
|
||||||
|
enum class Filter : u32
|
||||||
|
{
|
||||||
|
Point,
|
||||||
|
Linear
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AddressMode : u32
|
||||||
|
{
|
||||||
|
Clamp,
|
||||||
|
Repeat,
|
||||||
|
MirroredRepeat
|
||||||
|
};
|
||||||
|
|
||||||
|
void Generate(const BPMemory& bp, u32 index);
|
||||||
|
|
||||||
|
SamplerState& operator=(const SamplerState& rhs);
|
||||||
|
|
||||||
|
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 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, 8, u32> min_lod; // multiplied by 16
|
||||||
|
BitField<15, 8, u32> max_lod; // multiplied by 16
|
||||||
|
BitField<23, 8, s32> lod_bias; // multiplied by 32
|
||||||
|
BitField<31, 1, u32> anisotropic_filtering;
|
||||||
|
|
||||||
|
u32 hex;
|
||||||
|
};
|
||||||
|
|
||||||
namespace RenderState
|
namespace RenderState
|
||||||
{
|
{
|
||||||
RasterizationState GetNoCullRasterizationState();
|
RasterizationState GetNoCullRasterizationState();
|
||||||
DepthState GetNoDepthTestingDepthStencilState();
|
DepthState GetNoDepthTestingDepthStencilState();
|
||||||
BlendingState GetNoBlendingBlendState();
|
BlendingState GetNoBlendingBlendState();
|
||||||
|
SamplerState GetPointSamplerState();
|
||||||
|
SamplerState GetLinearSamplerState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "VideoCommon/PerfQueryBase.h"
|
#include "VideoCommon/PerfQueryBase.h"
|
||||||
#include "VideoCommon/PixelShaderManager.h"
|
#include "VideoCommon/PixelShaderManager.h"
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
|
#include "VideoCommon/SamplerCommon.h"
|
||||||
#include "VideoCommon/TextureCacheBase.h"
|
#include "VideoCommon/TextureCacheBase.h"
|
||||||
#include "VideoCommon/VertexLoaderManager.h"
|
#include "VideoCommon/VertexLoaderManager.h"
|
||||||
#include "VideoCommon/VertexShaderManager.h"
|
#include "VideoCommon/VertexShaderManager.h"
|
||||||
|
@ -208,6 +209,52 @@ std::pair<size_t, size_t> VertexManagerBase::ResetFlushAspectRatioCount()
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SetSamplerState(u32 index, bool custom_tex)
|
||||||
|
{
|
||||||
|
const FourTexUnits& tex = bpmem.tex[index / 4];
|
||||||
|
const TexMode0& tm0 = tex.texMode0[index % 4];
|
||||||
|
|
||||||
|
SamplerState state = {};
|
||||||
|
state.Generate(bpmem, index);
|
||||||
|
|
||||||
|
// Force texture filtering config option.
|
||||||
|
if (g_ActiveConfig.bForceFiltering)
|
||||||
|
{
|
||||||
|
state.min_filter = SamplerState::Filter::Linear;
|
||||||
|
state.mag_filter = SamplerState::Filter::Linear;
|
||||||
|
state.mipmap_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ?
|
||||||
|
SamplerState::Filter::Linear :
|
||||||
|
SamplerState::Filter::Point;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom textures may have a greater number of mips
|
||||||
|
if (custom_tex)
|
||||||
|
state.max_lod = 255;
|
||||||
|
|
||||||
|
// Anisotropic filtering option.
|
||||||
|
if (g_ActiveConfig.iMaxAnisotropy != 0 && !SamplerCommon::IsBpTexMode0PointFiltering(tm0))
|
||||||
|
{
|
||||||
|
// https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
|
||||||
|
// For predictable results on all hardware/drivers, only use one of:
|
||||||
|
// GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear])
|
||||||
|
// GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear])
|
||||||
|
// 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;
|
||||||
|
if (SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0))
|
||||||
|
state.mipmap_filter = SamplerState::Filter::Linear;
|
||||||
|
state.anisotropic_filtering = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.anisotropic_filtering = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_renderer->SetSamplerState(index, state);
|
||||||
|
}
|
||||||
|
|
||||||
void VertexManagerBase::Flush()
|
void VertexManagerBase::Flush()
|
||||||
{
|
{
|
||||||
if (m_is_flushed)
|
if (m_is_flushed)
|
||||||
|
@ -276,7 +323,7 @@ void VertexManagerBase::Flush()
|
||||||
|
|
||||||
if (tentry)
|
if (tentry)
|
||||||
{
|
{
|
||||||
g_renderer->SetSamplerState(i & 3, i >> 2, tentry->is_custom_tex);
|
SetSamplerState(i, tentry->is_custom_tex);
|
||||||
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height);
|
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue