Merge pull request #5343 from stenzek/videocommon-states
Move depth, rasterization and sampler states to VideoCommon
This commit is contained in:
commit
002e01d0ed
|
@ -136,7 +136,7 @@ public:
|
||||||
|
|
||||||
__forceinline BitField& operator=(T val)
|
__forceinline BitField& operator=(T val)
|
||||||
{
|
{
|
||||||
storage = (storage & ~GetMask()) | ((val << position) & GetMask());
|
storage = (storage & ~GetMask()) | ((static_cast<StorageType>(val) << position) & GetMask());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,32 +399,33 @@ ID3D11BlendState* StateCache::Get(BlendingState state)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D11RasterizerState* StateCache::Get(RasterizerState state)
|
ID3D11RasterizerState* StateCache::Get(RasterizationState state)
|
||||||
{
|
{
|
||||||
auto it = m_raster.find(state.packed);
|
auto it = m_raster.find(state.hex);
|
||||||
|
|
||||||
if (it != m_raster.end())
|
if (it != m_raster.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
||||||
D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, state.cull_mode, false, 0,
|
static constexpr std::array<D3D11_CULL_MODE, 4> cull_modes = {
|
||||||
0.f, 0, false, true, false, false);
|
{D3D11_CULL_NONE, D3D11_CULL_BACK, D3D11_CULL_FRONT, D3D11_CULL_BACK}};
|
||||||
|
|
||||||
|
D3D11_RASTERIZER_DESC desc = {};
|
||||||
|
desc.FillMode = D3D11_FILL_SOLID;
|
||||||
|
desc.CullMode = cull_modes[state.cullmode];
|
||||||
|
desc.ScissorEnable = TRUE;
|
||||||
|
|
||||||
ID3D11RasterizerState* res = nullptr;
|
ID3D11RasterizerState* res = nullptr;
|
||||||
|
HRESULT hr = D3D::device->CreateRasterizerState(&desc, &res);
|
||||||
HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res);
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__);
|
PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__);
|
||||||
|
|
||||||
D3D::SetDebugObjectName(res, "rasterizer state used to emulate the GX pipeline");
|
D3D::SetDebugObjectName(res, "rasterizer state used to emulate the GX pipeline");
|
||||||
m_raster.emplace(state.packed, res);
|
m_raster.emplace(state.hex, res);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D11DepthStencilState* StateCache::Get(ZMode state)
|
ID3D11DepthStencilState* StateCache::Get(DepthState state)
|
||||||
{
|
{
|
||||||
auto it = m_depth.find(state.hex);
|
auto it = m_depth.find(state.hex);
|
||||||
|
|
||||||
if (it != m_depth.end())
|
if (it != m_depth.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
||||||
|
@ -472,6 +438,7 @@ ID3D11DepthStencilState* StateCache::Get(ZMode state)
|
||||||
depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
||||||
depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
|
depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
|
||||||
|
|
||||||
|
// Less/greater are swapped due to inverted depth.
|
||||||
const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = {
|
const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = {
|
||||||
D3D11_COMPARISON_NEVER, D3D11_COMPARISON_GREATER, D3D11_COMPARISON_EQUAL,
|
D3D11_COMPARISON_NEVER, D3D11_COMPARISON_GREATER, D3D11_COMPARISON_EQUAL,
|
||||||
D3D11_COMPARISON_GREATER_EQUAL, D3D11_COMPARISON_LESS, D3D11_COMPARISON_NOT_EQUAL,
|
D3D11_COMPARISON_GREATER_EQUAL, D3D11_COMPARISON_LESS, D3D11_COMPARISON_NOT_EQUAL,
|
||||||
|
@ -531,4 +498,12 @@ void StateCache::Clear()
|
||||||
m_sampler.clear();
|
m_sampler.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
D3D11_PRIMITIVE_TOPOLOGY StateCache::GetPrimitiveTopology(PrimitiveType primitive)
|
||||||
|
{
|
||||||
|
static constexpr std::array<D3D11_PRIMITIVE_TOPOLOGY, 4> primitives = {
|
||||||
|
{D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, D3D11_PRIMITIVE_TOPOLOGY_LINELIST,
|
||||||
|
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP}};
|
||||||
|
return primitives[static_cast<u32>(primitive)];
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace DX11
|
} // namespace DX11
|
||||||
|
|
|
@ -20,27 +20,6 @@ struct ID3D11RasterizerState;
|
||||||
|
|
||||||
namespace DX11
|
namespace DX11
|
||||||
{
|
{
|
||||||
union RasterizerState
|
|
||||||
{
|
|
||||||
BitField<0, 2, D3D11_CULL_MODE> cull_mode;
|
|
||||||
|
|
||||||
u32 packed;
|
|
||||||
};
|
|
||||||
|
|
||||||
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:
|
||||||
|
@ -48,17 +27,20 @@ public:
|
||||||
// Returned objects is owned by the cache and does not need to be released.
|
// Returned objects is owned by the cache and does not need to be released.
|
||||||
ID3D11SamplerState* Get(SamplerState state);
|
ID3D11SamplerState* Get(SamplerState state);
|
||||||
ID3D11BlendState* Get(BlendingState state);
|
ID3D11BlendState* Get(BlendingState state);
|
||||||
ID3D11RasterizerState* Get(RasterizerState state);
|
ID3D11RasterizerState* Get(RasterizationState state);
|
||||||
ID3D11DepthStencilState* Get(ZMode state);
|
ID3D11DepthStencilState* Get(DepthState state);
|
||||||
|
|
||||||
// Release all cached states and clear hash tables.
|
// Release all cached states and clear hash tables.
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
|
// Convert RasterState primitive type to D3D11 primitive topology.
|
||||||
|
static D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology(PrimitiveType primitive);
|
||||||
|
|
||||||
private:
|
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
|
||||||
|
|
|
@ -207,7 +207,7 @@ void GeometryShaderCache::Shutdown()
|
||||||
g_gs_disk_cache.Close();
|
g_gs_disk_cache.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeometryShaderCache::SetShader(u32 primitive_type)
|
bool GeometryShaderCache::SetShader(PrimitiveType primitive_type)
|
||||||
{
|
{
|
||||||
GeometryShaderUid uid = GetGeometryShaderUid(primitive_type);
|
GeometryShaderUid uid = GetGeometryShaderUid(primitive_type);
|
||||||
if (last_entry && uid == last_uid)
|
if (last_entry && uid == last_uid)
|
||||||
|
|
|
@ -18,7 +18,7 @@ public:
|
||||||
static void Reload();
|
static void Reload();
|
||||||
static void Clear();
|
static void Clear();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
static bool SetShader(u32 primitive_type);
|
static bool SetShader(PrimitiveType primitive_type);
|
||||||
static bool CompileShader(const GeometryShaderUid& uid);
|
static bool CompileShader(const GeometryShaderUid& uid);
|
||||||
static bool InsertByteCode(const GeometryShaderUid& uid, const u8* bytecode, size_t len);
|
static bool InsertByteCode(const GeometryShaderUid& uid, const u8* bytecode, size_t len);
|
||||||
static void PrecompileShaders();
|
static void PrecompileShaders();
|
||||||
|
|
|
@ -60,8 +60,8 @@ struct GXPipelineState
|
||||||
{
|
{
|
||||||
std::array<SamplerState, 8> samplers;
|
std::array<SamplerState, 8> samplers;
|
||||||
BlendingState blend;
|
BlendingState blend;
|
||||||
ZMode zmode;
|
DepthState zmode;
|
||||||
RasterizerState raster;
|
RasterizationState raster;
|
||||||
};
|
};
|
||||||
|
|
||||||
static u32 s_last_multisamples = 1;
|
static u32 s_last_multisamples = 1;
|
||||||
|
@ -249,13 +249,12 @@ 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;
|
||||||
s_gx_state.zmode.func = ZMode::NEVER;
|
s_gx_state.zmode.func = ZMode::NEVER;
|
||||||
|
s_gx_state.raster.cullmode = GenMode::CULL_NONE;
|
||||||
s_gx_state.raster.cull_mode = D3D11_CULL_NONE;
|
|
||||||
|
|
||||||
// Clear EFB textures
|
// Clear EFB textures
|
||||||
constexpr std::array<float, 4> clear_color{{0.f, 0.f, 0.f, 1.f}};
|
constexpr std::array<float, 4> clear_color{{0.f, 0.f, 0.f, 1.f}};
|
||||||
|
@ -867,14 +866,12 @@ void Renderer::ApplyState()
|
||||||
D3D::stateman->PushBlendState(s_gx_state_cache.Get(s_gx_state.blend));
|
D3D::stateman->PushBlendState(s_gx_state_cache.Get(s_gx_state.blend));
|
||||||
D3D::stateman->PushDepthState(s_gx_state_cache.Get(s_gx_state.zmode));
|
D3D::stateman->PushDepthState(s_gx_state_cache.Get(s_gx_state.zmode));
|
||||||
D3D::stateman->PushRasterizerState(s_gx_state_cache.Get(s_gx_state.raster));
|
D3D::stateman->PushRasterizerState(s_gx_state_cache.Get(s_gx_state.raster));
|
||||||
|
D3D::stateman->SetPrimitiveTopology(
|
||||||
|
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();
|
||||||
|
|
||||||
|
@ -891,68 +888,19 @@ void Renderer::RestoreState()
|
||||||
D3D::stateman->PopRasterizerState();
|
D3D::stateman->PopRasterizerState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::ApplyCullDisable()
|
void Renderer::SetRasterizationState(const RasterizationState& state)
|
||||||
{
|
{
|
||||||
RasterizerState rast = s_gx_state.raster;
|
s_gx_state.raster.hex = state.hex;
|
||||||
rast.cull_mode = D3D11_CULL_NONE;
|
|
||||||
|
|
||||||
ID3D11RasterizerState* raststate = s_gx_state_cache.Get(rast);
|
|
||||||
D3D::stateman->PushRasterizerState(raststate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::RestoreCull()
|
void Renderer::SetDepthState(const DepthState& state)
|
||||||
{
|
{
|
||||||
D3D::stateman->PopRasterizerState();
|
s_gx_state.zmode.hex = state.hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetGenerationMode()
|
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
|
||||||
{
|
{
|
||||||
constexpr std::array<D3D11_CULL_MODE, 4> d3d_cull_modes{{
|
s_gx_state.samplers[index].hex = state.hex;
|
||||||
D3D11_CULL_NONE, D3D11_CULL_BACK, D3D11_CULL_FRONT, D3D11_CULL_BACK,
|
|
||||||
}};
|
|
||||||
|
|
||||||
// rastdc.FrontCounterClockwise must be false for this to work
|
|
||||||
// TODO: GX_CULL_ALL not supported, yet!
|
|
||||||
s_gx_state.raster.cull_mode = d3d_cull_modes[bpmem.genMode.cullmode];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetDepthMode()
|
|
||||||
{
|
|
||||||
s_gx_state.zmode.hex = bpmem.zmode.hex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex)
|
|
||||||
{
|
|
||||||
const FourTexUnits& tex = bpmem.tex[texindex];
|
|
||||||
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()
|
||||||
|
|
|
@ -21,9 +21,9 @@ public:
|
||||||
|
|
||||||
void SetBlendingState(const BlendingState& state) override;
|
void SetBlendingState(const BlendingState& state) override;
|
||||||
void SetScissorRect(const EFBRectangle& rc) override;
|
void SetScissorRect(const EFBRectangle& rc) override;
|
||||||
void SetGenerationMode() override;
|
void SetRasterizationState(const RasterizationState& state) override;
|
||||||
void SetDepthMode() 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;
|
||||||
|
@ -33,9 +33,6 @@ public:
|
||||||
void ApplyState() override;
|
void ApplyState() override;
|
||||||
void RestoreState() override;
|
void RestoreState() override;
|
||||||
|
|
||||||
void ApplyCullDisable();
|
|
||||||
void RestoreCull();
|
|
||||||
|
|
||||||
void RenderText(const std::string& text, int left, int top, u32 color) override;
|
void RenderText(const std::string& text, int left, int top, u32 color) override;
|
||||||
|
|
||||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
||||||
|
|
|
@ -127,28 +127,10 @@ void VertexManager::Draw(u32 stride)
|
||||||
u32 baseVertex = m_vertexDrawOffset / stride;
|
u32 baseVertex = m_vertexDrawOffset / stride;
|
||||||
u32 startIndex = m_indexDrawOffset / sizeof(u16);
|
u32 startIndex = m_indexDrawOffset / sizeof(u16);
|
||||||
|
|
||||||
switch (m_current_primitive_type)
|
|
||||||
{
|
|
||||||
case PRIMITIVE_POINTS:
|
|
||||||
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
|
|
||||||
static_cast<Renderer*>(g_renderer.get())->ApplyCullDisable();
|
|
||||||
break;
|
|
||||||
case PRIMITIVE_LINES:
|
|
||||||
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
|
|
||||||
static_cast<Renderer*>(g_renderer.get())->ApplyCullDisable();
|
|
||||||
break;
|
|
||||||
case PRIMITIVE_TRIANGLES:
|
|
||||||
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D::stateman->Apply();
|
D3D::stateman->Apply();
|
||||||
D3D::context->DrawIndexed(indices, startIndex, baseVertex);
|
D3D::context->DrawIndexed(indices, startIndex, baseVertex);
|
||||||
|
|
||||||
INCSTAT(stats.thisFrame.numDrawCalls);
|
INCSTAT(stats.thisFrame.numDrawCalls);
|
||||||
|
|
||||||
if (m_current_primitive_type != PRIMITIVE_TRIANGLES)
|
|
||||||
static_cast<Renderer*>(g_renderer.get())->RestoreCull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VertexManager::vFlush()
|
void VertexManager::vFlush()
|
||||||
|
|
|
@ -33,7 +33,7 @@ void ShaderCache<Uid>::Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Uid>
|
template <typename Uid>
|
||||||
bool ShaderCache<Uid>::SetShader(u32 primitive_type)
|
bool ShaderCache<Uid>::SetShader(PrimitiveType primitive_type)
|
||||||
{
|
{
|
||||||
Uid uid = GetUid(primitive_type, APIType::OpenGL);
|
Uid uid = GetUid(primitive_type, APIType::OpenGL);
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,10 @@ public:
|
||||||
virtual ~ShaderCache();
|
virtual ~ShaderCache();
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
bool SetShader(u32 primitive_type);
|
bool SetShader(PrimitiveType primitive_type);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual Uid GetUid(u32 primitive_type, APIType api_type) = 0;
|
virtual Uid GetUid(PrimitiveType primitive_type, APIType api_type) = 0;
|
||||||
virtual ShaderCode GenerateCode(APIType api_type, Uid uid) = 0;
|
virtual ShaderCode GenerateCode(APIType api_type, Uid uid) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -40,7 +40,7 @@ public:
|
||||||
static std::unique_ptr<VertexShaderCache> s_instance;
|
static std::unique_ptr<VertexShaderCache> s_instance;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VertexShaderUid GetUid(u32 primitive_type, APIType api_type) override
|
VertexShaderUid GetUid(PrimitiveType primitive_type, APIType api_type) override
|
||||||
{
|
{
|
||||||
return GetVertexShaderUid();
|
return GetVertexShaderUid();
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ public:
|
||||||
static std::unique_ptr<GeometryShaderCache> s_instance;
|
static std::unique_ptr<GeometryShaderCache> s_instance;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GeometryShaderUid GetUid(u32 primitive_type, APIType api_type) override
|
GeometryShaderUid GetUid(PrimitiveType primitive_type, APIType api_type) override
|
||||||
{
|
{
|
||||||
return GetGeometryShaderUid(primitive_type);
|
return GetGeometryShaderUid(primitive_type);
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ public:
|
||||||
static std::unique_ptr<PixelShaderCache> s_instance;
|
static std::unique_ptr<PixelShaderCache> s_instance;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PixelShaderUid GetUid(u32 primitive_type, APIType api_type) override
|
PixelShaderUid GetUid(PrimitiveType primitive_type, APIType api_type) override
|
||||||
{
|
{
|
||||||
return GetPixelShaderUid();
|
return GetPixelShaderUid();
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,8 @@ void ProgramShaderCache::UploadConstants()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SHADER* ProgramShaderCache::SetShader(u32 primitive_type, const GLVertexFormat* vertex_format)
|
SHADER* ProgramShaderCache::SetShader(PrimitiveType primitive_type,
|
||||||
|
const GLVertexFormat* vertex_format)
|
||||||
{
|
{
|
||||||
if (g_ActiveConfig.bDisableSpecializedShaders)
|
if (g_ActiveConfig.bDisableSpecializedShaders)
|
||||||
return SetUberShader(primitive_type, vertex_format);
|
return SetUberShader(primitive_type, vertex_format);
|
||||||
|
@ -292,7 +293,8 @@ SHADER* ProgramShaderCache::SetShader(u32 primitive_type, const GLVertexFormat*
|
||||||
return &last_entry->shader;
|
return &last_entry->shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHADER* ProgramShaderCache::SetUberShader(u32 primitive_type, const GLVertexFormat* vertex_format)
|
SHADER* ProgramShaderCache::SetUberShader(PrimitiveType primitive_type,
|
||||||
|
const GLVertexFormat* vertex_format)
|
||||||
{
|
{
|
||||||
UBERSHADERUID uid;
|
UBERSHADERUID uid;
|
||||||
std::memset(&uid, 0, sizeof(uid));
|
std::memset(&uid, 0, sizeof(uid));
|
||||||
|
@ -1117,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1155,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1295,7 +1299,7 @@ void ProgramShaderCache::DestroyPrerenderArrays(SharedContextData* data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgramShaderCache::DrawPrerenderArray(const SHADER& shader, u32 primitive_type)
|
void ProgramShaderCache::DrawPrerenderArray(const SHADER& shader, PrimitiveType primitive_type)
|
||||||
{
|
{
|
||||||
// This is called on a worker thread, so we don't want to use the normal binding process.
|
// This is called on a worker thread, so we don't want to use the normal binding process.
|
||||||
glUseProgram(shader.glprogid);
|
glUseProgram(shader.glprogid);
|
||||||
|
@ -1303,15 +1307,18 @@ void ProgramShaderCache::DrawPrerenderArray(const SHADER& shader, u32 primitive_
|
||||||
// The number of primitives drawn depends on the type.
|
// The number of primitives drawn depends on the type.
|
||||||
switch (primitive_type)
|
switch (primitive_type)
|
||||||
{
|
{
|
||||||
case PRIMITIVE_POINTS:
|
case PrimitiveType::Points:
|
||||||
glDrawElements(GL_POINTS, 1, GL_UNSIGNED_SHORT, nullptr);
|
glDrawElements(GL_POINTS, 1, GL_UNSIGNED_SHORT, nullptr);
|
||||||
break;
|
break;
|
||||||
case PRIMITIVE_LINES:
|
case PrimitiveType::Lines:
|
||||||
glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, nullptr);
|
glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, nullptr);
|
||||||
break;
|
break;
|
||||||
case PRIMITIVE_TRIANGLES:
|
case PrimitiveType::Triangles:
|
||||||
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, nullptr);
|
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, nullptr);
|
||||||
break;
|
break;
|
||||||
|
case PrimitiveType::TriangleStrip:
|
||||||
|
glDrawElements(GL_TRIANGLE_STRIP, 3, GL_UNSIGNED_SHORT, nullptr);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Has to be finished by the time the main thread picks it up.
|
// Has to be finished by the time the main thread picks it up.
|
||||||
|
|
|
@ -94,8 +94,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
static PCacheEntry GetShaderProgram();
|
static PCacheEntry GetShaderProgram();
|
||||||
static SHADER* SetShader(u32 primitive_type, const GLVertexFormat* vertex_format);
|
static SHADER* SetShader(PrimitiveType primitive_type, const GLVertexFormat* vertex_format);
|
||||||
static SHADER* SetUberShader(u32 primitive_type, const GLVertexFormat* vertex_format);
|
static SHADER* SetUberShader(PrimitiveType primitive_type, const GLVertexFormat* vertex_format);
|
||||||
static void BindVertexFormat(const GLVertexFormat* vertex_format);
|
static void BindVertexFormat(const GLVertexFormat* vertex_format);
|
||||||
static void InvalidateVertexFormat();
|
static void InvalidateVertexFormat();
|
||||||
static void BindLastVertexFormat();
|
static void BindLastVertexFormat();
|
||||||
|
@ -198,7 +198,7 @@ private:
|
||||||
static void DestroyShaders();
|
static void DestroyShaders();
|
||||||
static void CreatePrerenderArrays(SharedContextData* data);
|
static void CreatePrerenderArrays(SharedContextData* data);
|
||||||
static void DestroyPrerenderArrays(SharedContextData* data);
|
static void DestroyPrerenderArrays(SharedContextData* data);
|
||||||
static void DrawPrerenderArray(const SHADER& shader, u32 primitive_type);
|
static void DrawPrerenderArray(const SHADER& shader, PrimitiveType primitive_type);
|
||||||
|
|
||||||
static PCache pshaders;
|
static PCache pshaders;
|
||||||
static UberPCache ubershaders;
|
static UberPCache ubershaders;
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -1785,9 +1789,9 @@ void Renderer::RestoreAPIState()
|
||||||
glEnable(GL_CLIP_DISTANCE0);
|
glEnable(GL_CLIP_DISTANCE0);
|
||||||
glEnable(GL_CLIP_DISTANCE1);
|
glEnable(GL_CLIP_DISTANCE1);
|
||||||
}
|
}
|
||||||
SetGenerationMode();
|
BPFunctions::SetGenerationMode();
|
||||||
BPFunctions::SetScissor();
|
BPFunctions::SetScissor();
|
||||||
SetDepthMode();
|
BPFunctions::SetDepthMode();
|
||||||
BPFunctions::SetBlendMode();
|
BPFunctions::SetBlendMode();
|
||||||
SetViewport();
|
SetViewport();
|
||||||
|
|
||||||
|
@ -1798,14 +1802,14 @@ void Renderer::RestoreAPIState()
|
||||||
OGLTexture::SetStage();
|
OGLTexture::SetStage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetGenerationMode()
|
void Renderer::SetRasterizationState(const RasterizationState& state)
|
||||||
{
|
{
|
||||||
// none, ccw, cw, ccw
|
// none, ccw, cw, ccw
|
||||||
if (bpmem.genMode.cullmode > 0)
|
if (state.cullmode != GenMode::CULL_NONE)
|
||||||
{
|
{
|
||||||
// TODO: GX_CULL_ALL not supported, yet!
|
// TODO: GX_CULL_ALL not supported, yet!
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW);
|
glFrontFace(state.cullmode == GenMode::CULL_FRONT ? GL_CCW : GL_CW);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1813,16 +1817,16 @@ void Renderer::SetGenerationMode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetDepthMode()
|
void Renderer::SetDepthState(const DepthState& state)
|
||||||
{
|
{
|
||||||
const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
|
const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
|
||||||
GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS};
|
GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS};
|
||||||
|
|
||||||
if (bpmem.zmode.testenable)
|
if (state.testenable)
|
||||||
{
|
{
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE);
|
glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE);
|
||||||
glDepthFunc(glCmpFuncs[bpmem.zmode.func]);
|
glDepthFunc(glCmpFuncs[state.func]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1834,13 +1838,9 @@ void Renderer::SetDepthMode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
|
|
|
@ -79,9 +79,9 @@ public:
|
||||||
|
|
||||||
void SetBlendingState(const BlendingState& state) override;
|
void SetBlendingState(const BlendingState& state) override;
|
||||||
void SetScissorRect(const EFBRectangle& rc) override;
|
void SetScissorRect(const EFBRectangle& rc) override;
|
||||||
void SetGenerationMode() override;
|
void SetRasterizationState(const RasterizationState& state) override;
|
||||||
void SetDepthMode() 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;
|
||||||
|
|
|
@ -114,17 +114,17 @@ void VertexManager::Draw(u32 stride)
|
||||||
|
|
||||||
switch (m_current_primitive_type)
|
switch (m_current_primitive_type)
|
||||||
{
|
{
|
||||||
case PRIMITIVE_POINTS:
|
case PrimitiveType::Points:
|
||||||
primitive_mode = GL_POINTS;
|
primitive_mode = GL_POINTS;
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
break;
|
break;
|
||||||
case PRIMITIVE_LINES:
|
case PrimitiveType::Lines:
|
||||||
primitive_mode = GL_LINES;
|
primitive_mode = GL_LINES;
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
break;
|
break;
|
||||||
case PRIMITIVE_TRIANGLES:
|
case PrimitiveType::Triangles:
|
||||||
primitive_mode =
|
primitive_mode = GL_TRIANGLES;
|
||||||
g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? GL_TRIANGLE_STRIP : GL_TRIANGLES;
|
break;
|
||||||
|
case PrimitiveType::TriangleStrip:
|
||||||
|
primitive_mode = GL_TRIANGLE_STRIP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,9 +140,6 @@ void VertexManager::Draw(u32 stride)
|
||||||
}
|
}
|
||||||
|
|
||||||
INCSTAT(stats.thisFrame.numDrawCalls);
|
INCSTAT(stats.thisFrame.numDrawCalls);
|
||||||
|
|
||||||
if (m_current_primitive_type != PRIMITIVE_TRIANGLES)
|
|
||||||
static_cast<Renderer*>(g_renderer.get())->SetGenerationMode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VertexManager::vFlush()
|
void VertexManager::vFlush()
|
||||||
|
|
|
@ -62,16 +62,17 @@ void SWVertexLoader::vFlush()
|
||||||
u8 primitiveType = 0;
|
u8 primitiveType = 0;
|
||||||
switch (m_current_primitive_type)
|
switch (m_current_primitive_type)
|
||||||
{
|
{
|
||||||
case PRIMITIVE_POINTS:
|
case PrimitiveType::Points:
|
||||||
primitiveType = OpcodeDecoder::GX_DRAW_POINTS;
|
primitiveType = OpcodeDecoder::GX_DRAW_POINTS;
|
||||||
break;
|
break;
|
||||||
case PRIMITIVE_LINES:
|
case PrimitiveType::Lines:
|
||||||
primitiveType = OpcodeDecoder::GX_DRAW_LINES;
|
primitiveType = OpcodeDecoder::GX_DRAW_LINES;
|
||||||
break;
|
break;
|
||||||
case PRIMITIVE_TRIANGLES:
|
case PrimitiveType::Triangles:
|
||||||
primitiveType = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ?
|
primitiveType = OpcodeDecoder::GX_DRAW_TRIANGLES;
|
||||||
OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP :
|
break;
|
||||||
OpcodeDecoder::GX_DRAW_TRIANGLES;
|
case PrimitiveType::TriangleStrip:
|
||||||
|
primitiveType = OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,13 +90,6 @@ void SWVertexLoader::vFlush()
|
||||||
for (u32 i = 0; i < IndexGenerator::GetIndexLen(); i++)
|
for (u32 i = 0; i < IndexGenerator::GetIndexLen(); i++)
|
||||||
{
|
{
|
||||||
const u16 index = m_local_index_buffer[i];
|
const u16 index = m_local_index_buffer[i];
|
||||||
|
|
||||||
if (index == 0xffff)
|
|
||||||
{
|
|
||||||
// primitive restart
|
|
||||||
m_setup_unit.Init(primitiveType);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
memset(&m_vertex, 0, sizeof(m_vertex));
|
memset(&m_vertex, 0, sizeof(m_vertex));
|
||||||
|
|
||||||
// Super Mario Sunshine requires those to be zero for those debug boxes.
|
// Super Mario Sunshine requires those to be zero for those debug boxes.
|
||||||
|
|
|
@ -124,41 +124,12 @@ constexpr u32 PUSH_CONSTANT_BUFFER_SIZE = 128;
|
||||||
// Minimum number of draw calls per command buffer when attempting to preempt a readback operation.
|
// Minimum number of draw calls per command buffer when attempting to preempt a readback operation.
|
||||||
constexpr u32 MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK = 10;
|
constexpr u32 MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK = 10;
|
||||||
|
|
||||||
// Rasterization state info
|
// Multisampling state info that we don't expose in VideoCommon.
|
||||||
union RasterizationState
|
union MultisamplingState
|
||||||
{
|
{
|
||||||
BitField<0, 2, VkCullModeFlags> cull_mode;
|
BitField<0, 5, u32> samples; // 1-16
|
||||||
BitField<2, 7, VkSampleCountFlagBits> samples;
|
BitField<0, 1, u32> per_sample_shading; // SSAA
|
||||||
BitField<9, 1, VkBool32> per_sample_shading;
|
u32 hex;
|
||||||
BitField<10, 1, VkBool32> depth_clamp;
|
|
||||||
|
|
||||||
u32 bits;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Depth state info
|
|
||||||
union DepthStencilState
|
|
||||||
{
|
|
||||||
BitField<0, 1, VkBool32> test_enable;
|
|
||||||
BitField<1, 1, VkBool32> write_enable;
|
|
||||||
BitField<2, 3, VkCompareOp> compare_op;
|
|
||||||
|
|
||||||
u32 bits;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -61,6 +61,39 @@ FramebufferManager* FramebufferManager::GetInstance()
|
||||||
return static_cast<FramebufferManager*>(g_framebuffer_manager.get());
|
return static_cast<FramebufferManager*>(g_framebuffer_manager.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 FramebufferManager::GetEFBWidth() const
|
||||||
|
{
|
||||||
|
return m_efb_color_texture->GetWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 FramebufferManager::GetEFBHeight() const
|
||||||
|
{
|
||||||
|
return m_efb_color_texture->GetHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 FramebufferManager::GetEFBLayers() const
|
||||||
|
{
|
||||||
|
return m_efb_color_texture->GetLayers();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSampleCountFlagBits FramebufferManager::GetEFBSamples() const
|
||||||
|
{
|
||||||
|
return m_efb_color_texture->GetSamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
MultisamplingState FramebufferManager::GetEFBMultisamplingState() const
|
||||||
|
{
|
||||||
|
MultisamplingState ms = {};
|
||||||
|
ms.per_sample_shading = g_ActiveConfig.MultisamplingEnabled() && g_ActiveConfig.bSSAA;
|
||||||
|
ms.samples = static_cast<u32>(GetEFBSamples());
|
||||||
|
return ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<u32, u32> FramebufferManager::GetTargetSize() const
|
||||||
|
{
|
||||||
|
return std::make_pair(GetEFBWidth(), GetEFBHeight());
|
||||||
|
}
|
||||||
|
|
||||||
bool FramebufferManager::Initialize()
|
bool FramebufferManager::Initialize()
|
||||||
{
|
{
|
||||||
if (!CreateEFBRenderPass())
|
if (!CreateEFBRenderPass())
|
||||||
|
@ -117,22 +150,17 @@ bool FramebufferManager::Initialize()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<u32, u32> FramebufferManager::GetTargetSize() const
|
|
||||||
{
|
|
||||||
return std::make_pair(m_efb_width, m_efb_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FramebufferManager::CreateEFBRenderPass()
|
bool FramebufferManager::CreateEFBRenderPass()
|
||||||
{
|
{
|
||||||
m_efb_samples = static_cast<VkSampleCountFlagBits>(g_ActiveConfig.iMultisamples);
|
VkSampleCountFlagBits samples = static_cast<VkSampleCountFlagBits>(g_ActiveConfig.iMultisamples);
|
||||||
|
|
||||||
// render pass for rendering to the efb
|
// render pass for rendering to the efb
|
||||||
VkAttachmentDescription attachments[] = {
|
VkAttachmentDescription attachments[] = {
|
||||||
{0, EFB_COLOR_TEXTURE_FORMAT, m_efb_samples, VK_ATTACHMENT_LOAD_OP_LOAD,
|
{0, EFB_COLOR_TEXTURE_FORMAT, samples, VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
|
||||||
{0, EFB_DEPTH_TEXTURE_FORMAT, m_efb_samples, VK_ATTACHMENT_LOAD_OP_LOAD,
|
{0, EFB_DEPTH_TEXTURE_FORMAT, samples, VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}};
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}};
|
||||||
|
@ -177,7 +205,7 @@ bool FramebufferManager::CreateEFBRenderPass()
|
||||||
}
|
}
|
||||||
|
|
||||||
// render pass for resolving depth, since we can't do it with vkCmdResolveImage
|
// render pass for resolving depth, since we can't do it with vkCmdResolveImage
|
||||||
if (m_efb_samples != VK_SAMPLE_COUNT_1_BIT)
|
if (g_ActiveConfig.MultisamplingEnabled())
|
||||||
{
|
{
|
||||||
VkAttachmentDescription resolve_attachment = {0,
|
VkAttachmentDescription resolve_attachment = {0,
|
||||||
EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT,
|
EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT,
|
||||||
|
@ -228,30 +256,32 @@ void FramebufferManager::DestroyEFBRenderPass()
|
||||||
|
|
||||||
bool FramebufferManager::CreateEFBFramebuffer()
|
bool FramebufferManager::CreateEFBFramebuffer()
|
||||||
{
|
{
|
||||||
m_efb_width = static_cast<u32>(std::max(g_renderer->GetTargetWidth(), 1));
|
u32 efb_width = static_cast<u32>(std::max(g_renderer->GetTargetWidth(), 1));
|
||||||
m_efb_height = static_cast<u32>(std::max(g_renderer->GetTargetHeight(), 1));
|
u32 efb_height = static_cast<u32>(std::max(g_renderer->GetTargetHeight(), 1));
|
||||||
m_efb_layers = (g_ActiveConfig.iStereoMode != STEREO_OFF) ? 2 : 1;
|
u32 efb_layers = (g_ActiveConfig.iStereoMode != STEREO_OFF) ? 2 : 1;
|
||||||
INFO_LOG(VIDEO, "EFB size: %ux%ux%u", m_efb_width, m_efb_height, m_efb_layers);
|
VkSampleCountFlagBits efb_samples =
|
||||||
|
static_cast<VkSampleCountFlagBits>(g_ActiveConfig.iMultisamples);
|
||||||
|
INFO_LOG(VIDEO, "EFB size: %ux%ux%u", efb_width, efb_height, efb_layers);
|
||||||
|
|
||||||
// Update the static variable in the base class. Why does this even exist?
|
// Update the static variable in the base class. Why does this even exist?
|
||||||
FramebufferManagerBase::m_EFBLayers = m_efb_layers;
|
FramebufferManagerBase::m_EFBLayers = g_ActiveConfig.iMultisamples;
|
||||||
|
|
||||||
// Allocate EFB render targets
|
// Allocate EFB render targets
|
||||||
m_efb_color_texture =
|
m_efb_color_texture =
|
||||||
Texture2D::Create(m_efb_width, m_efb_height, 1, m_efb_layers, EFB_COLOR_TEXTURE_FORMAT,
|
Texture2D::Create(efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, efb_samples,
|
||||||
m_efb_samples, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||||
|
|
||||||
// We need a second texture to swap with for changing pixel formats
|
// We need a second texture to swap with for changing pixel formats
|
||||||
m_efb_convert_color_texture =
|
m_efb_convert_color_texture =
|
||||||
Texture2D::Create(m_efb_width, m_efb_height, 1, m_efb_layers, EFB_COLOR_TEXTURE_FORMAT,
|
Texture2D::Create(efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, efb_samples,
|
||||||
m_efb_samples, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||||
|
|
||||||
m_efb_depth_texture = Texture2D::Create(
|
m_efb_depth_texture = Texture2D::Create(
|
||||||
m_efb_width, m_efb_height, 1, m_efb_layers, EFB_DEPTH_TEXTURE_FORMAT, m_efb_samples,
|
efb_width, efb_height, 1, efb_layers, EFB_DEPTH_TEXTURE_FORMAT, efb_samples,
|
||||||
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||||
|
@ -260,16 +290,16 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create resolved textures if MSAA is on
|
// Create resolved textures if MSAA is on
|
||||||
if (m_efb_samples != VK_SAMPLE_COUNT_1_BIT)
|
if (g_ActiveConfig.MultisamplingEnabled())
|
||||||
{
|
{
|
||||||
m_efb_resolve_color_texture = Texture2D::Create(
|
m_efb_resolve_color_texture = Texture2D::Create(
|
||||||
m_efb_width, m_efb_height, 1, m_efb_layers, EFB_COLOR_TEXTURE_FORMAT, VK_SAMPLE_COUNT_1_BIT,
|
efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, VK_SAMPLE_COUNT_1_BIT,
|
||||||
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||||
VK_IMAGE_USAGE_SAMPLED_BIT);
|
VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||||
|
|
||||||
m_efb_resolve_depth_texture = Texture2D::Create(
|
m_efb_resolve_depth_texture = Texture2D::Create(
|
||||||
m_efb_width, m_efb_height, 1, m_efb_layers, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT,
|
efb_width, efb_height, 1, efb_layers, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT,
|
||||||
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL,
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
||||||
VK_IMAGE_USAGE_SAMPLED_BIT);
|
VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||||
|
@ -284,9 +314,9 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
||||||
m_depth_resolve_render_pass,
|
m_depth_resolve_render_pass,
|
||||||
1,
|
1,
|
||||||
&attachment,
|
&attachment,
|
||||||
m_efb_width,
|
efb_width,
|
||||||
m_efb_height,
|
efb_height,
|
||||||
m_efb_layers};
|
efb_layers};
|
||||||
|
|
||||||
VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
|
VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
|
||||||
&m_depth_resolve_framebuffer);
|
&m_depth_resolve_framebuffer);
|
||||||
|
@ -307,9 +337,9 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
||||||
m_efb_load_render_pass,
|
m_efb_load_render_pass,
|
||||||
static_cast<u32>(ArraySize(framebuffer_attachments)),
|
static_cast<u32>(ArraySize(framebuffer_attachments)),
|
||||||
framebuffer_attachments,
|
framebuffer_attachments,
|
||||||
m_efb_width,
|
efb_width,
|
||||||
m_efb_height,
|
efb_height,
|
||||||
m_efb_layers};
|
efb_layers};
|
||||||
|
|
||||||
VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
|
VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
|
||||||
&m_efb_framebuffer);
|
&m_efb_framebuffer);
|
||||||
|
@ -332,17 +362,22 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
||||||
// Transition to state that can be used to clear
|
// Transition to state that can be used to clear
|
||||||
m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
m_efb_convert_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
m_efb_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
m_efb_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
|
||||||
// Clear the contents of the buffers.
|
// Clear the contents of the buffers.
|
||||||
static const VkClearColorValue clear_color = {{0.0f, 0.0f, 0.0f, 0.0f}};
|
static const VkClearColorValue clear_color = {{0.0f, 0.0f, 0.0f, 0.0f}};
|
||||||
static const VkClearDepthStencilValue clear_depth = {0.0f, 0};
|
static const VkClearDepthStencilValue clear_depth = {0.0f, 0};
|
||||||
VkImageSubresourceRange clear_color_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, m_efb_layers};
|
VkImageSubresourceRange clear_color_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, efb_layers};
|
||||||
VkImageSubresourceRange clear_depth_range = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, m_efb_layers};
|
VkImageSubresourceRange clear_depth_range = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, efb_layers};
|
||||||
vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
&clear_color, 1, &clear_color_range);
|
&clear_color, 1, &clear_color_range);
|
||||||
|
vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
|
m_efb_convert_color_texture->GetImage(),
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &clear_color_range);
|
||||||
vkCmdClearDepthStencilImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
vkCmdClearDepthStencilImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
m_efb_depth_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
m_efb_depth_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
&clear_depth, 1, &clear_depth_range);
|
&clear_depth, 1, &clear_depth_range);
|
||||||
|
@ -438,16 +473,12 @@ void FramebufferManager::ReinterpretPixelData(int convtype)
|
||||||
m_efb_load_render_pass, g_shader_cache->GetScreenQuadVertexShader(),
|
m_efb_load_render_pass, g_shader_cache->GetScreenQuadVertexShader(),
|
||||||
g_shader_cache->GetScreenQuadGeometryShader(), pixel_shader);
|
g_shader_cache->GetScreenQuadGeometryShader(), pixel_shader);
|
||||||
|
|
||||||
RasterizationState rs_state = Util::GetNoCullRasterizationState();
|
VkRect2D region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}};
|
||||||
rs_state.samples = m_efb_samples;
|
draw.SetMultisamplingState(GetEFBMultisamplingState());
|
||||||
rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE;
|
|
||||||
draw.SetRasterizationState(rs_state);
|
|
||||||
|
|
||||||
VkRect2D region = {{0, 0}, {m_efb_width, m_efb_height}};
|
|
||||||
draw.BeginRenderPass(m_efb_convert_framebuffer, region);
|
draw.BeginRenderPass(m_efb_convert_framebuffer, region);
|
||||||
draw.SetPSSampler(0, m_efb_color_texture->GetView(), g_object_cache->GetPointSampler());
|
draw.SetPSSampler(0, m_efb_color_texture->GetView(), g_object_cache->GetPointSampler());
|
||||||
draw.SetViewportAndScissor(0, 0, m_efb_width, m_efb_height);
|
draw.SetViewportAndScissor(0, 0, GetEFBWidth(), GetEFBHeight());
|
||||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
draw.DrawWithoutVertexBuffer(4);
|
||||||
draw.EndRenderPass();
|
draw.EndRenderPass();
|
||||||
|
|
||||||
// Swap EFB texture pointers
|
// Swap EFB texture pointers
|
||||||
|
@ -458,7 +489,7 @@ void FramebufferManager::ReinterpretPixelData(int convtype)
|
||||||
Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region)
|
Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region)
|
||||||
{
|
{
|
||||||
// Return the normal EFB texture if multisampling is off.
|
// Return the normal EFB texture if multisampling is off.
|
||||||
if (m_efb_samples == VK_SAMPLE_COUNT_1_BIT)
|
if (GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT)
|
||||||
return m_efb_color_texture.get();
|
return m_efb_color_texture.get();
|
||||||
|
|
||||||
// Can't resolve within a render pass.
|
// Can't resolve within a render pass.
|
||||||
|
@ -467,8 +498,8 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region)
|
||||||
// It's not valid to resolve out-of-bounds coordinates.
|
// It's not valid to resolve out-of-bounds coordinates.
|
||||||
// Ensuring the region is within the image is the caller's responsibility.
|
// Ensuring the region is within the image is the caller's responsibility.
|
||||||
_assert_(region.offset.x >= 0 && region.offset.y >= 0 &&
|
_assert_(region.offset.x >= 0 && region.offset.y >= 0 &&
|
||||||
(static_cast<u32>(region.offset.x) + region.extent.width) <= m_efb_width &&
|
(static_cast<u32>(region.offset.x) + region.extent.width) <= GetEFBWidth() &&
|
||||||
(static_cast<u32>(region.offset.y) + region.extent.height) <= m_efb_height);
|
(static_cast<u32>(region.offset.y) + region.extent.height) <= GetEFBHeight());
|
||||||
|
|
||||||
// Resolving is considered to be a transfer operation.
|
// Resolving is considered to be a transfer operation.
|
||||||
m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
|
@ -478,11 +509,11 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region)
|
||||||
|
|
||||||
// Resolve to our already-created texture.
|
// Resolve to our already-created texture.
|
||||||
VkImageResolve resolve = {
|
VkImageResolve resolve = {
|
||||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, m_efb_layers}, // VkImageSubresourceLayers srcSubresource
|
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, GetEFBLayers()}, // VkImageSubresourceLayers srcSubresource
|
||||||
{region.offset.x, region.offset.y, 0}, // VkOffset3D srcOffset
|
{region.offset.x, region.offset.y, 0}, // VkOffset3D srcOffset
|
||||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, m_efb_layers}, // VkImageSubresourceLayers dstSubresource
|
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, GetEFBLayers()}, // VkImageSubresourceLayers dstSubresource
|
||||||
{region.offset.x, region.offset.y, 0}, // VkOffset3D dstOffset
|
{region.offset.x, region.offset.y, 0}, // VkOffset3D dstOffset
|
||||||
{region.extent.width, region.extent.height, m_efb_layers} // VkExtent3D extent
|
{region.extent.width, region.extent.height, GetEFBLayers()} // VkExtent3D extent
|
||||||
};
|
};
|
||||||
vkCmdResolveImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
vkCmdResolveImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
@ -498,7 +529,7 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region)
|
||||||
Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region)
|
Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region)
|
||||||
{
|
{
|
||||||
// Return the normal EFB texture if multisampling is off.
|
// Return the normal EFB texture if multisampling is off.
|
||||||
if (m_efb_samples == VK_SAMPLE_COUNT_1_BIT)
|
if (GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT)
|
||||||
return m_efb_depth_texture.get();
|
return m_efb_depth_texture.get();
|
||||||
|
|
||||||
// Can't resolve within a render pass.
|
// Can't resolve within a render pass.
|
||||||
|
@ -516,7 +547,7 @@ Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region)
|
||||||
draw.SetPSSampler(0, m_efb_depth_texture->GetView(), g_object_cache->GetPointSampler());
|
draw.SetPSSampler(0, m_efb_depth_texture->GetView(), g_object_cache->GetPointSampler());
|
||||||
draw.SetViewportAndScissor(region.offset.x, region.offset.y, region.extent.width,
|
draw.SetViewportAndScissor(region.offset.x, region.offset.y, region.extent.width,
|
||||||
region.extent.height);
|
region.extent.height);
|
||||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
draw.DrawWithoutVertexBuffer(4);
|
||||||
draw.EndRenderPass();
|
draw.EndRenderPass();
|
||||||
|
|
||||||
// Restore MSAA texture ready for rendering again
|
// Restore MSAA texture ready for rendering again
|
||||||
|
@ -646,11 +677,11 @@ bool FramebufferManager::CompileConversionShaders()
|
||||||
|
|
||||||
m_ps_rgb8_to_rgba6 = Util::CompileAndCreateFragmentShader(header + RGB8_TO_RGBA6_SHADER_SOURCE);
|
m_ps_rgb8_to_rgba6 = Util::CompileAndCreateFragmentShader(header + RGB8_TO_RGBA6_SHADER_SOURCE);
|
||||||
m_ps_rgba6_to_rgb8 = Util::CompileAndCreateFragmentShader(header + RGBA6_TO_RGB8_SHADER_SOURCE);
|
m_ps_rgba6_to_rgb8 = Util::CompileAndCreateFragmentShader(header + RGBA6_TO_RGB8_SHADER_SOURCE);
|
||||||
if (m_efb_samples != VK_SAMPLE_COUNT_1_BIT)
|
if (GetEFBSamples() != VK_SAMPLE_COUNT_1_BIT)
|
||||||
m_ps_depth_resolve = Util::CompileAndCreateFragmentShader(header + DEPTH_RESOLVE_SHADER_SOURCE);
|
m_ps_depth_resolve = Util::CompileAndCreateFragmentShader(header + DEPTH_RESOLVE_SHADER_SOURCE);
|
||||||
|
|
||||||
return (m_ps_rgba6_to_rgb8 != VK_NULL_HANDLE && m_ps_rgb8_to_rgba6 != VK_NULL_HANDLE &&
|
return (m_ps_rgba6_to_rgb8 != VK_NULL_HANDLE && m_ps_rgb8_to_rgba6 != VK_NULL_HANDLE &&
|
||||||
(m_efb_samples == VK_SAMPLE_COUNT_1_BIT || m_ps_depth_resolve != VK_NULL_HANDLE));
|
(GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT || m_ps_depth_resolve != VK_NULL_HANDLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramebufferManager::DestroyConversionShaders()
|
void FramebufferManager::DestroyConversionShaders()
|
||||||
|
@ -685,13 +716,13 @@ bool FramebufferManager::PopulateColorReadbackTexture()
|
||||||
StateTracker::GetInstance()->OnReadback();
|
StateTracker::GetInstance()->OnReadback();
|
||||||
|
|
||||||
// Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on.
|
// Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on.
|
||||||
VkRect2D src_region = {{0, 0}, {m_efb_width, m_efb_height}};
|
VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}};
|
||||||
Texture2D* src_texture = m_efb_color_texture.get();
|
Texture2D* src_texture = m_efb_color_texture.get();
|
||||||
VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
if (m_efb_samples > 1)
|
if (GetEFBSamples() > 1)
|
||||||
src_texture = ResolveEFBColorTexture(src_region);
|
src_texture = ResolveEFBColorTexture(src_region);
|
||||||
|
|
||||||
if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT)
|
if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT)
|
||||||
{
|
{
|
||||||
m_color_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
m_color_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||||
|
@ -709,7 +740,7 @@ bool FramebufferManager::PopulateColorReadbackTexture()
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler());
|
draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler());
|
||||||
draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT);
|
draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT);
|
||||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
draw.DrawWithoutVertexBuffer(4);
|
||||||
draw.EndRenderPass();
|
draw.EndRenderPass();
|
||||||
|
|
||||||
// Restore EFB to color attachment, since we're done with it.
|
// Restore EFB to color attachment, since we're done with it.
|
||||||
|
@ -765,16 +796,16 @@ bool FramebufferManager::PopulateDepthReadbackTexture()
|
||||||
StateTracker::GetInstance()->OnReadback();
|
StateTracker::GetInstance()->OnReadback();
|
||||||
|
|
||||||
// Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on.
|
// Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on.
|
||||||
VkRect2D src_region = {{0, 0}, {m_efb_width, m_efb_height}};
|
VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}};
|
||||||
Texture2D* src_texture = m_efb_depth_texture.get();
|
Texture2D* src_texture = m_efb_depth_texture.get();
|
||||||
VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
if (m_efb_samples > 1)
|
if (GetEFBSamples() > 1)
|
||||||
{
|
{
|
||||||
// EFB depth resolves are written out as color textures
|
// EFB depth resolves are written out as color textures
|
||||||
src_texture = ResolveEFBDepthTexture(src_region);
|
src_texture = ResolveEFBDepthTexture(src_region);
|
||||||
src_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
src_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
}
|
}
|
||||||
if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT)
|
if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT)
|
||||||
{
|
{
|
||||||
m_depth_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
m_depth_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||||
|
@ -792,7 +823,7 @@ bool FramebufferManager::PopulateDepthReadbackTexture()
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler());
|
draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler());
|
||||||
draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT);
|
draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT);
|
||||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
draw.DrawWithoutVertexBuffer(4);
|
||||||
draw.EndRenderPass();
|
draw.EndRenderPass();
|
||||||
|
|
||||||
// Restore EFB to depth attachment, since we're done with it.
|
// Restore EFB to depth attachment, since we're done with it.
|
||||||
|
@ -905,12 +936,12 @@ bool FramebufferManager::CreateReadbackRenderPasses()
|
||||||
g_vulkan_context->GetDeviceLimits().pointSizeRange[0] > 1 ||
|
g_vulkan_context->GetDeviceLimits().pointSizeRange[0] > 1 ||
|
||||||
g_vulkan_context->GetDeviceLimits().pointSizeRange[1] < 16)
|
g_vulkan_context->GetDeviceLimits().pointSizeRange[1] < 16)
|
||||||
{
|
{
|
||||||
m_poke_primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
|
m_poke_primitive = PrimitiveType::TriangleStrip;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Points should be okay.
|
// Points should be okay.
|
||||||
m_poke_primitive_topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
m_poke_primitive = PrimitiveType::Points;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1108,29 +1139,28 @@ void FramebufferManager::PokeEFBDepth(u32 x, u32 y, float depth)
|
||||||
void FramebufferManager::CreatePokeVertices(std::vector<EFBPokeVertex>* destination_list, u32 x,
|
void FramebufferManager::CreatePokeVertices(std::vector<EFBPokeVertex>* destination_list, u32 x,
|
||||||
u32 y, float z, u32 color)
|
u32 y, float z, u32 color)
|
||||||
{
|
{
|
||||||
// Some devices don't support point sizes >1 (e.g. Adreno).
|
if (m_poke_primitive == PrimitiveType::Points)
|
||||||
if (m_poke_primitive_topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
|
|
||||||
{
|
|
||||||
// generate quad from the single point (clip-space coordinates)
|
|
||||||
float x1 = float(x) * 2.0f / EFB_WIDTH - 1.0f;
|
|
||||||
float y1 = float(y) * 2.0f / EFB_HEIGHT - 1.0f;
|
|
||||||
float x2 = float(x + 1) * 2.0f / EFB_WIDTH - 1.0f;
|
|
||||||
float y2 = float(y + 1) * 2.0f / EFB_HEIGHT - 1.0f;
|
|
||||||
destination_list->push_back({{x1, y1, z, 1.0f}, color});
|
|
||||||
destination_list->push_back({{x2, y1, z, 1.0f}, color});
|
|
||||||
destination_list->push_back({{x1, y2, z, 1.0f}, color});
|
|
||||||
destination_list->push_back({{x1, y2, z, 1.0f}, color});
|
|
||||||
destination_list->push_back({{x2, y1, z, 1.0f}, color});
|
|
||||||
destination_list->push_back({{x2, y2, z, 1.0f}, color});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// GPU will expand the point to a quad.
|
// GPU will expand the point to a quad.
|
||||||
float cs_x = float(x) * 2.0f / EFB_WIDTH - 1.0f;
|
float cs_x = float(x) * 2.0f / EFB_WIDTH - 1.0f;
|
||||||
float cs_y = float(y) * 2.0f / EFB_HEIGHT - 1.0f;
|
float cs_y = float(y) * 2.0f / EFB_HEIGHT - 1.0f;
|
||||||
float point_size = m_efb_width / static_cast<float>(EFB_WIDTH);
|
float point_size = GetEFBWidth() / static_cast<float>(EFB_WIDTH);
|
||||||
destination_list->push_back({{cs_x, cs_y, z, point_size}, color});
|
destination_list->push_back({{cs_x, cs_y, z, point_size}, color});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some devices don't support point sizes >1 (e.g. Adreno).
|
||||||
|
// Generate quad from the single point (clip-space coordinates).
|
||||||
|
float x1 = float(x) * 2.0f / EFB_WIDTH - 1.0f;
|
||||||
|
float y1 = float(y) * 2.0f / EFB_HEIGHT - 1.0f;
|
||||||
|
float x2 = float(x + 1) * 2.0f / EFB_WIDTH - 1.0f;
|
||||||
|
float y2 = float(y + 1) * 2.0f / EFB_HEIGHT - 1.0f;
|
||||||
|
destination_list->push_back({{x1, y1, z, 1.0f}, color});
|
||||||
|
destination_list->push_back({{x2, y1, z, 1.0f}, color});
|
||||||
|
destination_list->push_back({{x1, y2, z, 1.0f}, color});
|
||||||
|
destination_list->push_back({{x1, y2, z, 1.0f}, color});
|
||||||
|
destination_list->push_back({{x2, y1, z, 1.0f}, color});
|
||||||
|
destination_list->push_back({{x2, y2, z, 1.0f}, color});
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramebufferManager::FlushEFBPokes()
|
void FramebufferManager::FlushEFBPokes()
|
||||||
|
@ -1159,21 +1189,21 @@ void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, size_t
|
||||||
pipeline_info.vertex_format = m_poke_vertex_format.get();
|
pipeline_info.vertex_format = m_poke_vertex_format.get();
|
||||||
pipeline_info.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD);
|
pipeline_info.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD);
|
||||||
pipeline_info.vs = m_poke_vertex_shader;
|
pipeline_info.vs = m_poke_vertex_shader;
|
||||||
pipeline_info.gs = (m_efb_layers > 1) ? m_poke_geometry_shader : VK_NULL_HANDLE;
|
pipeline_info.gs = (GetEFBLayers() > 1) ? m_poke_geometry_shader : VK_NULL_HANDLE;
|
||||||
pipeline_info.ps = m_poke_fragment_shader;
|
pipeline_info.ps = m_poke_fragment_shader;
|
||||||
pipeline_info.render_pass = m_efb_load_render_pass;
|
pipeline_info.render_pass = m_efb_load_render_pass;
|
||||||
pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits;
|
pipeline_info.rasterization_state.hex = RenderState::GetNoCullRasterizationState().hex;
|
||||||
pipeline_info.rasterization_state.samples = m_efb_samples;
|
pipeline_info.rasterization_state.primitive = m_poke_primitive;
|
||||||
pipeline_info.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits;
|
pipeline_info.multisampling_state.hex = GetEFBMultisamplingState().hex;
|
||||||
pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex;
|
pipeline_info.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex;
|
||||||
|
pipeline_info.blend_state.hex = RenderState::GetNoBlendingBlendState().hex;
|
||||||
pipeline_info.blend_state.colorupdate = write_color;
|
pipeline_info.blend_state.colorupdate = write_color;
|
||||||
pipeline_info.blend_state.alphaupdate = write_color;
|
pipeline_info.blend_state.alphaupdate = write_color;
|
||||||
pipeline_info.primitive_topology = m_poke_primitive_topology;
|
|
||||||
if (write_depth)
|
if (write_depth)
|
||||||
{
|
{
|
||||||
pipeline_info.depth_stencil_state.test_enable = VK_TRUE;
|
pipeline_info.depth_state.testenable = true;
|
||||||
pipeline_info.depth_stencil_state.write_enable = VK_TRUE;
|
pipeline_info.depth_state.updateenable = true;
|
||||||
pipeline_info.depth_stencil_state.compare_op = VK_COMPARE_OP_ALWAYS;
|
pipeline_info.depth_state.func = ZMode::ALWAYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline pipeline = g_shader_cache->GetPipeline(pipeline_info);
|
VkPipeline pipeline = g_shader_cache->GetPipeline(pipeline_info);
|
||||||
|
@ -1209,7 +1239,7 @@ void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, size_t
|
||||||
StateTracker::GetInstance()->EndClearRenderPass();
|
StateTracker::GetInstance()->EndClearRenderPass();
|
||||||
StateTracker::GetInstance()->BeginRenderPass();
|
StateTracker::GetInstance()->BeginRenderPass();
|
||||||
StateTracker::GetInstance()->SetPendingRebind();
|
StateTracker::GetInstance()->SetPendingRebind();
|
||||||
Util::SetViewportAndScissor(command_buffer, 0, 0, m_efb_width, m_efb_height);
|
Util::SetViewportAndScissor(command_buffer, 0, 0, GetEFBWidth(), GetEFBHeight());
|
||||||
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
vkCmdBindVertexBuffers(command_buffer, 0, 1, &vb_buffer, &vb_offset);
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, &vb_buffer, &vb_offset);
|
||||||
vkCmdDraw(command_buffer, static_cast<u32>(vertex_count), 1, 0, 0);
|
vkCmdDraw(command_buffer, static_cast<u32>(vertex_count), 1, 0, 0);
|
||||||
|
@ -1310,7 +1340,7 @@ bool FramebufferManager::CompilePokeShaders()
|
||||||
)";
|
)";
|
||||||
|
|
||||||
std::string source = g_shader_cache->GetUtilityShaderHeader();
|
std::string source = g_shader_cache->GetUtilityShaderHeader();
|
||||||
if (m_poke_primitive_topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
|
if (m_poke_primitive == PrimitiveType::Points)
|
||||||
source += "#define USE_POINT_SIZE 1\n";
|
source += "#define USE_POINT_SIZE 1\n";
|
||||||
source += POKE_VERTEX_SHADER_SOURCE;
|
source += POKE_VERTEX_SHADER_SOURCE;
|
||||||
m_poke_vertex_shader = Util::CompileAndCreateVertexShader(source);
|
m_poke_vertex_shader = Util::CompileAndCreateVertexShader(source);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "VideoBackends/Vulkan/Constants.h"
|
#include "VideoBackends/Vulkan/Constants.h"
|
||||||
#include "VideoBackends/Vulkan/TextureCache.h"
|
#include "VideoBackends/Vulkan/TextureCache.h"
|
||||||
#include "VideoCommon/FramebufferManagerBase.h"
|
#include "VideoCommon/FramebufferManagerBase.h"
|
||||||
|
#include "VideoCommon/RenderState.h"
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
|
@ -34,13 +35,14 @@ public:
|
||||||
|
|
||||||
VkRenderPass GetEFBLoadRenderPass() const { return m_efb_load_render_pass; }
|
VkRenderPass GetEFBLoadRenderPass() const { return m_efb_load_render_pass; }
|
||||||
VkRenderPass GetEFBClearRenderPass() const { return m_efb_clear_render_pass; }
|
VkRenderPass GetEFBClearRenderPass() const { return m_efb_clear_render_pass; }
|
||||||
u32 GetEFBWidth() const { return m_efb_width; }
|
|
||||||
u32 GetEFBHeight() const { return m_efb_height; }
|
|
||||||
u32 GetEFBLayers() const { return m_efb_layers; }
|
|
||||||
VkSampleCountFlagBits GetEFBSamples() const { return m_efb_samples; }
|
|
||||||
Texture2D* GetEFBColorTexture() const { return m_efb_color_texture.get(); }
|
Texture2D* GetEFBColorTexture() const { return m_efb_color_texture.get(); }
|
||||||
Texture2D* GetEFBDepthTexture() const { return m_efb_depth_texture.get(); }
|
Texture2D* GetEFBDepthTexture() const { return m_efb_depth_texture.get(); }
|
||||||
VkFramebuffer GetEFBFramebuffer() const { return m_efb_framebuffer; }
|
VkFramebuffer GetEFBFramebuffer() const { return m_efb_framebuffer; }
|
||||||
|
u32 GetEFBWidth() const;
|
||||||
|
u32 GetEFBHeight() const;
|
||||||
|
u32 GetEFBLayers() const;
|
||||||
|
VkSampleCountFlagBits GetEFBSamples() const;
|
||||||
|
MultisamplingState GetEFBMultisamplingState() const;
|
||||||
std::pair<u32, u32> GetTargetSize() const override;
|
std::pair<u32, u32> GetTargetSize() const override;
|
||||||
|
|
||||||
std::unique_ptr<XFBSourceBase> CreateXFBSource(unsigned int target_width,
|
std::unique_ptr<XFBSourceBase> CreateXFBSource(unsigned int target_width,
|
||||||
|
@ -124,11 +126,6 @@ private:
|
||||||
VkRenderPass m_efb_clear_render_pass = VK_NULL_HANDLE;
|
VkRenderPass m_efb_clear_render_pass = VK_NULL_HANDLE;
|
||||||
VkRenderPass m_depth_resolve_render_pass = VK_NULL_HANDLE;
|
VkRenderPass m_depth_resolve_render_pass = VK_NULL_HANDLE;
|
||||||
|
|
||||||
u32 m_efb_width = 0;
|
|
||||||
u32 m_efb_height = 0;
|
|
||||||
u32 m_efb_layers = 1;
|
|
||||||
VkSampleCountFlagBits m_efb_samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
|
|
||||||
std::unique_ptr<Texture2D> m_efb_color_texture;
|
std::unique_ptr<Texture2D> m_efb_color_texture;
|
||||||
std::unique_ptr<Texture2D> m_efb_convert_color_texture;
|
std::unique_ptr<Texture2D> m_efb_convert_color_texture;
|
||||||
std::unique_ptr<Texture2D> m_efb_depth_texture;
|
std::unique_ptr<Texture2D> m_efb_depth_texture;
|
||||||
|
@ -160,7 +157,7 @@ private:
|
||||||
std::unique_ptr<StreamBuffer> m_poke_vertex_stream_buffer;
|
std::unique_ptr<StreamBuffer> m_poke_vertex_stream_buffer;
|
||||||
std::vector<EFBPokeVertex> m_color_poke_vertices;
|
std::vector<EFBPokeVertex> m_color_poke_vertices;
|
||||||
std::vector<EFBPokeVertex> m_depth_poke_vertices;
|
std::vector<EFBPokeVertex> m_depth_poke_vertices;
|
||||||
VkPrimitiveTopology m_poke_primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
PrimitiveType m_poke_primitive = PrimitiveType::TriangleStrip;
|
||||||
|
|
||||||
VkRenderPass m_copy_color_render_pass = VK_NULL_HANDLE;
|
VkRenderPass m_copy_color_render_pass = VK_NULL_HANDLE;
|
||||||
VkRenderPass m_copy_depth_render_pass = VK_NULL_HANDLE;
|
VkRenderPass m_copy_depth_render_pass = VK_NULL_HANDLE;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -310,10 +310,10 @@ void RasterFont::PrintMultiLineText(VkRenderPass render_pass, const std::string&
|
||||||
|
|
||||||
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
|
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
|
||||||
render_pass, m_vertex_shader, VK_NULL_HANDLE, m_fragment_shader);
|
render_pass, m_vertex_shader, VK_NULL_HANDLE, m_fragment_shader,
|
||||||
|
PrimitiveType::Triangles);
|
||||||
|
|
||||||
UtilityShaderVertex* vertices =
|
UtilityShaderVertex* vertices = draw.ReserveVertices(text.length() * 6);
|
||||||
draw.ReserveVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, text.length() * 6);
|
|
||||||
size_t num_vertices = 0;
|
size_t num_vertices = 0;
|
||||||
if (!vertices)
|
if (!vertices)
|
||||||
return;
|
return;
|
||||||
|
@ -400,7 +400,7 @@ void RasterFont::PrintMultiLineText(VkRenderPass render_pass, const std::string&
|
||||||
draw.SetPSSampler(0, m_texture->GetView(), g_object_cache->GetLinearSampler());
|
draw.SetPSSampler(0, m_texture->GetView(), g_object_cache->GetLinearSampler());
|
||||||
|
|
||||||
// Setup alpha blending
|
// Setup alpha blending
|
||||||
BlendingState blend_state = Util::GetNoBlendingBlendState();
|
BlendingState blend_state = RenderState::GetNoBlendingBlendState();
|
||||||
blend_state.blendenable = true;
|
blend_state.blendenable = true;
|
||||||
blend_state.srcfactor = BlendMode::SRCALPHA;
|
blend_state.srcfactor = BlendMode::SRCALPHA;
|
||||||
blend_state.dstfactor = BlendMode::INVSRCALPHA;
|
blend_state.dstfactor = BlendMode::INVSRCALPHA;
|
||||||
|
|
|
@ -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()
|
||||||
|
@ -455,18 +453,14 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
|
||||||
StateTracker::GetInstance()->SetPendingRebind();
|
StateTracker::GetInstance()->SetPendingRebind();
|
||||||
|
|
||||||
// Mask away the appropriate colors and use a shader
|
// Mask away the appropriate colors and use a shader
|
||||||
BlendingState blend_state = Util::GetNoBlendingBlendState();
|
BlendingState blend_state = RenderState::GetNoBlendingBlendState();
|
||||||
blend_state.colorupdate = color_enable;
|
blend_state.colorupdate = color_enable;
|
||||||
blend_state.alphaupdate = alpha_enable;
|
blend_state.alphaupdate = alpha_enable;
|
||||||
|
|
||||||
DepthStencilState depth_state = Util::GetNoDepthTestingDepthStencilState();
|
DepthState depth_state = RenderState::GetNoDepthTestingDepthStencilState();
|
||||||
depth_state.test_enable = z_enable ? VK_TRUE : VK_FALSE;
|
depth_state.testenable = z_enable;
|
||||||
depth_state.write_enable = z_enable ? VK_TRUE : VK_FALSE;
|
depth_state.updateenable = z_enable;
|
||||||
depth_state.compare_op = VK_COMPARE_OP_ALWAYS;
|
depth_state.func = ZMode::ALWAYS;
|
||||||
|
|
||||||
RasterizationState rs_state = Util::GetNoCullRasterizationState();
|
|
||||||
rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE;
|
|
||||||
rs_state.samples = FramebufferManager::GetInstance()->GetEFBSamples();
|
|
||||||
|
|
||||||
// No need to start a new render pass, but we do need to restore viewport state
|
// No need to start a new render pass, but we do need to restore viewport state
|
||||||
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
|
@ -475,8 +469,8 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
|
||||||
g_shader_cache->GetPassthroughVertexShader(),
|
g_shader_cache->GetPassthroughVertexShader(),
|
||||||
g_shader_cache->GetPassthroughGeometryShader(), m_clear_fragment_shader);
|
g_shader_cache->GetPassthroughGeometryShader(), m_clear_fragment_shader);
|
||||||
|
|
||||||
draw.SetRasterizationState(rs_state);
|
draw.SetMultisamplingState(FramebufferManager::GetInstance()->GetEFBMultisamplingState());
|
||||||
draw.SetDepthStencilState(depth_state);
|
draw.SetDepthState(depth_state);
|
||||||
draw.SetBlendState(blend_state);
|
draw.SetBlendState(blend_state);
|
||||||
|
|
||||||
draw.DrawColoredQuad(target_rc.left, target_rc.top, target_rc.GetWidth(), target_rc.GetHeight(),
|
draw.DrawColoredQuad(target_rc.left, target_rc.top, target_rc.GetWidth(), target_rc.GetHeight(),
|
||||||
|
@ -1227,13 +1221,8 @@ void Renderer::BindEFBToStateTracker()
|
||||||
FramebufferManager::GetInstance()->GetEFBClearRenderPass());
|
FramebufferManager::GetInstance()->GetEFBClearRenderPass());
|
||||||
StateTracker::GetInstance()->SetFramebuffer(
|
StateTracker::GetInstance()->SetFramebuffer(
|
||||||
FramebufferManager::GetInstance()->GetEFBFramebuffer(), framebuffer_size);
|
FramebufferManager::GetInstance()->GetEFBFramebuffer(), framebuffer_size);
|
||||||
|
StateTracker::GetInstance()->SetMultisamplingstate(
|
||||||
// Update rasterization state with MSAA info
|
FramebufferManager::GetInstance()->GetEFBMultisamplingState());
|
||||||
RasterizationState rs_state = {};
|
|
||||||
rs_state.bits = StateTracker::GetInstance()->GetRasterizationState().bits;
|
|
||||||
rs_state.samples = FramebufferManager::GetInstance()->GetEFBSamples();
|
|
||||||
rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE;
|
|
||||||
StateTracker::GetInstance()->SetRasterizationState(rs_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::ResizeEFBTextures()
|
void Renderer::ResizeEFBTextures()
|
||||||
|
@ -1276,72 +1265,14 @@ void Renderer::RestoreAPIState()
|
||||||
StateTracker::GetInstance()->SetPendingRebind();
|
StateTracker::GetInstance()->SetPendingRebind();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetGenerationMode()
|
void Renderer::SetRasterizationState(const RasterizationState& state)
|
||||||
{
|
{
|
||||||
RasterizationState new_rs_state = {};
|
StateTracker::GetInstance()->SetRasterizationState(state);
|
||||||
new_rs_state.bits = StateTracker::GetInstance()->GetRasterizationState().bits;
|
|
||||||
|
|
||||||
switch (bpmem.genMode.cullmode)
|
|
||||||
{
|
|
||||||
case GenMode::CULL_NONE:
|
|
||||||
new_rs_state.cull_mode = VK_CULL_MODE_NONE;
|
|
||||||
break;
|
|
||||||
case GenMode::CULL_BACK:
|
|
||||||
new_rs_state.cull_mode = VK_CULL_MODE_BACK_BIT;
|
|
||||||
break;
|
|
||||||
case GenMode::CULL_FRONT:
|
|
||||||
new_rs_state.cull_mode = VK_CULL_MODE_FRONT_BIT;
|
|
||||||
break;
|
|
||||||
case GenMode::CULL_ALL:
|
|
||||||
new_rs_state.cull_mode = VK_CULL_MODE_FRONT_AND_BACK;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
new_rs_state.cull_mode = VK_CULL_MODE_NONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
StateTracker::GetInstance()->SetRasterizationState(new_rs_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetDepthMode()
|
void Renderer::SetDepthState(const DepthState& state)
|
||||||
{
|
{
|
||||||
DepthStencilState new_ds_state = {};
|
StateTracker::GetInstance()->SetDepthState(state);
|
||||||
new_ds_state.test_enable = bpmem.zmode.testenable ? VK_TRUE : VK_FALSE;
|
|
||||||
new_ds_state.write_enable = bpmem.zmode.updateenable ? VK_TRUE : VK_FALSE;
|
|
||||||
|
|
||||||
// Inverted depth, hence these are swapped
|
|
||||||
switch (bpmem.zmode.func)
|
|
||||||
{
|
|
||||||
case ZMode::NEVER:
|
|
||||||
new_ds_state.compare_op = VK_COMPARE_OP_NEVER;
|
|
||||||
break;
|
|
||||||
case ZMode::LESS:
|
|
||||||
new_ds_state.compare_op = VK_COMPARE_OP_GREATER;
|
|
||||||
break;
|
|
||||||
case ZMode::EQUAL:
|
|
||||||
new_ds_state.compare_op = VK_COMPARE_OP_EQUAL;
|
|
||||||
break;
|
|
||||||
case ZMode::LEQUAL:
|
|
||||||
new_ds_state.compare_op = VK_COMPARE_OP_GREATER_OR_EQUAL;
|
|
||||||
break;
|
|
||||||
case ZMode::GREATER:
|
|
||||||
new_ds_state.compare_op = VK_COMPARE_OP_LESS;
|
|
||||||
break;
|
|
||||||
case ZMode::NEQUAL:
|
|
||||||
new_ds_state.compare_op = VK_COMPARE_OP_NOT_EQUAL;
|
|
||||||
break;
|
|
||||||
case ZMode::GEQUAL:
|
|
||||||
new_ds_state.compare_op = VK_COMPARE_OP_LESS_OR_EQUAL;
|
|
||||||
break;
|
|
||||||
case ZMode::ALWAYS:
|
|
||||||
new_ds_state.compare_op = VK_COMPARE_OP_ALWAYS;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
new_ds_state.compare_op = VK_COMPARE_OP_ALWAYS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
StateTracker::GetInstance()->SetDepthStencilState(new_ds_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetBlendingState(const BlendingState& state)
|
void Renderer::SetBlendingState(const BlendingState& state)
|
||||||
|
@ -1349,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()
|
||||||
|
@ -1419,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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,9 +58,9 @@ public:
|
||||||
|
|
||||||
void SetBlendingState(const BlendingState& state) override;
|
void SetBlendingState(const BlendingState& state) override;
|
||||||
void SetScissorRect(const EFBRectangle& rc) override;
|
void SetScissorRect(const EFBRectangle& rc) override;
|
||||||
void SetGenerationMode() override;
|
void SetRasterizationState(const RasterizationState& state) override;
|
||||||
void SetDepthMode() 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;
|
||||||
|
|
||||||
|
|
|
@ -89,49 +89,61 @@ static bool IsStripPrimitiveTopology(VkPrimitiveTopology topology)
|
||||||
static VkPipelineRasterizationStateCreateInfo
|
static VkPipelineRasterizationStateCreateInfo
|
||||||
GetVulkanRasterizationState(const RasterizationState& state)
|
GetVulkanRasterizationState(const RasterizationState& state)
|
||||||
{
|
{
|
||||||
|
static constexpr std::array<VkCullModeFlags, 4> cull_modes = {
|
||||||
|
{VK_CULL_MODE_NONE, VK_CULL_MODE_BACK_BIT, VK_CULL_MODE_FRONT_BIT,
|
||||||
|
VK_CULL_MODE_FRONT_AND_BACK}};
|
||||||
|
|
||||||
|
bool depth_clamp = g_ActiveConfig.backend_info.bSupportsDepthClamp;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType
|
||||||
nullptr, // const void* pNext
|
nullptr, // const void* pNext
|
||||||
0, // VkPipelineRasterizationStateCreateFlags flags
|
0, // VkPipelineRasterizationStateCreateFlags flags
|
||||||
state.depth_clamp, // VkBool32 depthClampEnable
|
depth_clamp, // VkBool32 depthClampEnable
|
||||||
VK_FALSE, // VkBool32 rasterizerDiscardEnable
|
VK_FALSE, // VkBool32 rasterizerDiscardEnable
|
||||||
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode
|
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode
|
||||||
state.cull_mode, // VkCullModeFlags cullMode
|
cull_modes[state.cullmode], // VkCullModeFlags cullMode
|
||||||
VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace
|
VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace
|
||||||
VK_FALSE, // VkBool32 depthBiasEnable
|
VK_FALSE, // VkBool32 depthBiasEnable
|
||||||
0.0f, // float depthBiasConstantFactor
|
0.0f, // float depthBiasConstantFactor
|
||||||
0.0f, // float depthBiasClamp
|
0.0f, // float depthBiasClamp
|
||||||
0.0f, // float depthBiasSlopeFactor
|
0.0f, // float depthBiasSlopeFactor
|
||||||
1.0f // float lineWidth
|
1.0f // float lineWidth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkPipelineMultisampleStateCreateInfo
|
static VkPipelineMultisampleStateCreateInfo
|
||||||
GetVulkanMultisampleState(const RasterizationState& rs_state)
|
GetVulkanMultisampleState(const MultisamplingState& state)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType
|
||||||
nullptr, // const void* pNext
|
nullptr, // const void* pNext
|
||||||
0, // VkPipelineMultisampleStateCreateFlags flags
|
0, // VkPipelineMultisampleStateCreateFlags flags
|
||||||
rs_state.samples, // VkSampleCountFlagBits rasterizationSamples
|
static_cast<VkSampleCountFlagBits>(
|
||||||
rs_state.per_sample_shading, // VkBool32 sampleShadingEnable
|
state.samples.Value()), // VkSampleCountFlagBits rasterizationSamples
|
||||||
1.0f, // float minSampleShading
|
state.per_sample_shading, // VkBool32 sampleShadingEnable
|
||||||
nullptr, // const VkSampleMask* pSampleMask;
|
1.0f, // float minSampleShading
|
||||||
VK_FALSE, // VkBool32 alphaToCoverageEnable
|
nullptr, // const VkSampleMask* pSampleMask;
|
||||||
VK_FALSE // VkBool32 alphaToOneEnable
|
VK_FALSE, // VkBool32 alphaToCoverageEnable
|
||||||
|
VK_FALSE // VkBool32 alphaToOneEnable
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkPipelineDepthStencilStateCreateInfo
|
static VkPipelineDepthStencilStateCreateInfo GetVulkanDepthStencilState(const DepthState& state)
|
||||||
GetVulkanDepthStencilState(const DepthStencilState& state)
|
|
||||||
{
|
{
|
||||||
|
// Less/greater are swapped due to inverted depth.
|
||||||
|
static constexpr std::array<VkCompareOp, 8> funcs = {
|
||||||
|
{VK_COMPARE_OP_NEVER, VK_COMPARE_OP_GREATER, VK_COMPARE_OP_EQUAL,
|
||||||
|
VK_COMPARE_OP_GREATER_OR_EQUAL, VK_COMPARE_OP_LESS, VK_COMPARE_OP_NOT_EQUAL,
|
||||||
|
VK_COMPARE_OP_LESS_OR_EQUAL, VK_COMPARE_OP_ALWAYS}};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType
|
||||||
nullptr, // const void* pNext
|
nullptr, // const void* pNext
|
||||||
0, // VkPipelineDepthStencilStateCreateFlags flags
|
0, // VkPipelineDepthStencilStateCreateFlags flags
|
||||||
state.test_enable, // VkBool32 depthTestEnable
|
state.testenable, // VkBool32 depthTestEnable
|
||||||
state.write_enable, // VkBool32 depthWriteEnable
|
state.updateenable, // VkBool32 depthWriteEnable
|
||||||
state.compare_op, // VkCompareOp depthCompareOp
|
funcs[state.func], // VkCompareOp depthCompareOp
|
||||||
VK_FALSE, // VkBool32 depthBoundsTestEnable
|
VK_FALSE, // VkBool32 depthBoundsTestEnable
|
||||||
VK_FALSE, // VkBool32 stencilTestEnable
|
VK_FALSE, // VkBool32 stencilTestEnable
|
||||||
{}, // VkStencilOpState front
|
{}, // VkStencilOpState front
|
||||||
|
@ -256,13 +268,13 @@ VkPipeline ShaderCache::CreatePipeline(const PipelineInfo& info)
|
||||||
info.vertex_format ? info.vertex_format->GetVertexInputStateInfo() : empty_vertex_input_state;
|
info.vertex_format ? info.vertex_format->GetVertexInputStateInfo() : empty_vertex_input_state;
|
||||||
|
|
||||||
// Input assembly
|
// Input assembly
|
||||||
|
static constexpr std::array<VkPrimitiveTopology, 4> vk_primitive_topologies = {
|
||||||
|
{VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
|
||||||
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP}};
|
||||||
VkPipelineInputAssemblyStateCreateInfo input_assembly_state = {
|
VkPipelineInputAssemblyStateCreateInfo input_assembly_state = {
|
||||||
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0,
|
||||||
nullptr, // const void* pNext
|
vk_primitive_topologies[static_cast<u32>(info.rasterization_state.primitive.Value())],
|
||||||
0, // VkPipelineInputAssemblyStateCreateFlags flags
|
VK_FALSE};
|
||||||
info.primitive_topology, // VkPrimitiveTopology topology
|
|
||||||
VK_FALSE // VkBool32 primitiveRestartEnable
|
|
||||||
};
|
|
||||||
|
|
||||||
// See Vulkan spec, section 19:
|
// See Vulkan spec, section 19:
|
||||||
// If topology is VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
|
// If topology is VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
|
||||||
|
@ -270,7 +282,7 @@ VkPipeline ShaderCache::CreatePipeline(const PipelineInfo& info)
|
||||||
// VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY or VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
|
// VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY or VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
|
||||||
// primitiveRestartEnable must be VK_FALSE
|
// primitiveRestartEnable must be VK_FALSE
|
||||||
if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart &&
|
if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart &&
|
||||||
IsStripPrimitiveTopology(info.primitive_topology))
|
IsStripPrimitiveTopology(input_assembly_state.topology))
|
||||||
{
|
{
|
||||||
input_assembly_state.primitiveRestartEnable = VK_TRUE;
|
input_assembly_state.primitiveRestartEnable = VK_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -310,9 +322,9 @@ VkPipeline ShaderCache::CreatePipeline(const PipelineInfo& info)
|
||||||
VkPipelineRasterizationStateCreateInfo rasterization_state =
|
VkPipelineRasterizationStateCreateInfo rasterization_state =
|
||||||
GetVulkanRasterizationState(info.rasterization_state);
|
GetVulkanRasterizationState(info.rasterization_state);
|
||||||
VkPipelineMultisampleStateCreateInfo multisample_state =
|
VkPipelineMultisampleStateCreateInfo multisample_state =
|
||||||
GetVulkanMultisampleState(info.rasterization_state);
|
GetVulkanMultisampleState(info.multisampling_state);
|
||||||
VkPipelineDepthStencilStateCreateInfo depth_stencil_state =
|
VkPipelineDepthStencilStateCreateInfo depth_stencil_state =
|
||||||
GetVulkanDepthStencilState(info.depth_stencil_state);
|
GetVulkanDepthStencilState(info.depth_state);
|
||||||
VkPipelineColorBlendAttachmentState blend_attachment_state =
|
VkPipelineColorBlendAttachmentState blend_attachment_state =
|
||||||
GetVulkanAttachmentBlendState(info.blend_state);
|
GetVulkanAttachmentBlendState(info.blend_state);
|
||||||
VkPipelineColorBlendStateCreateInfo blend_state =
|
VkPipelineColorBlendStateCreateInfo blend_state =
|
||||||
|
@ -965,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));
|
||||||
|
@ -1002,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));
|
||||||
|
@ -1198,23 +1178,12 @@ void ShaderCache::CreateDummyPipeline(const UberShader::VertexShaderUid& vuid,
|
||||||
VK_NULL_HANDLE;
|
VK_NULL_HANDLE;
|
||||||
pinfo.ps = GetPixelUberShaderForUid(puid);
|
pinfo.ps = GetPixelUberShaderForUid(puid);
|
||||||
pinfo.render_pass = FramebufferManager::GetInstance()->GetEFBLoadRenderPass();
|
pinfo.render_pass = FramebufferManager::GetInstance()->GetEFBLoadRenderPass();
|
||||||
pinfo.rasterization_state.bits = Util::GetNoCullRasterizationState().bits;
|
pinfo.rasterization_state.hex = RenderState::GetNoCullRasterizationState().hex;
|
||||||
pinfo.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits;
|
pinfo.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex;
|
||||||
pinfo.blend_state.hex = Util::GetNoBlendingBlendState().hex;
|
pinfo.blend_state.hex = RenderState::GetNoBlendingBlendState().hex;
|
||||||
switch (guid.GetUidData()->primitive_type)
|
pinfo.multisampling_state.hex = FramebufferManager::GetInstance()->GetEFBMultisamplingState().hex;
|
||||||
{
|
pinfo.rasterization_state.primitive =
|
||||||
case PRIMITIVE_POINTS:
|
static_cast<PrimitiveType>(guid.GetUidData()->primitive_type);
|
||||||
pinfo.primitive_topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
|
||||||
break;
|
|
||||||
case PRIMITIVE_LINES:
|
|
||||||
pinfo.primitive_topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
|
|
||||||
break;
|
|
||||||
case PRIMITIVE_TRIANGLES:
|
|
||||||
pinfo.primitive_topology = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ?
|
|
||||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP :
|
|
||||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
GetPipelineWithCacheResultAsync(pinfo);
|
GetPipelineWithCacheResultAsync(pinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,8 @@ struct PipelineInfo
|
||||||
VkRenderPass render_pass;
|
VkRenderPass render_pass;
|
||||||
BlendingState blend_state;
|
BlendingState blend_state;
|
||||||
RasterizationState rasterization_state;
|
RasterizationState rasterization_state;
|
||||||
DepthStencilState depth_stencil_state;
|
DepthState depth_state;
|
||||||
VkPrimitiveTopology primitive_topology;
|
MultisamplingState multisampling_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PipelineInfoHash
|
struct PipelineInfoHash
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
#include "VideoBackends/Vulkan/CommandBufferManager.h"
|
#include "VideoBackends/Vulkan/CommandBufferManager.h"
|
||||||
#include "VideoBackends/Vulkan/Constants.h"
|
#include "VideoBackends/Vulkan/Constants.h"
|
||||||
#include "VideoBackends/Vulkan/FramebufferManager.h"
|
|
||||||
#include "VideoBackends/Vulkan/ObjectCache.h"
|
#include "VideoBackends/Vulkan/ObjectCache.h"
|
||||||
#include "VideoBackends/Vulkan/ShaderCache.h"
|
#include "VideoBackends/Vulkan/ShaderCache.h"
|
||||||
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
||||||
|
@ -54,26 +53,6 @@ void StateTracker::DestroyInstance()
|
||||||
|
|
||||||
bool StateTracker::Initialize()
|
bool StateTracker::Initialize()
|
||||||
{
|
{
|
||||||
// Set some sensible defaults
|
|
||||||
m_pipeline_state.rasterization_state.cull_mode = VK_CULL_MODE_NONE;
|
|
||||||
m_pipeline_state.rasterization_state.per_sample_shading = VK_FALSE;
|
|
||||||
m_pipeline_state.rasterization_state.depth_clamp = VK_FALSE;
|
|
||||||
m_pipeline_state.depth_stencil_state.test_enable = VK_TRUE;
|
|
||||||
m_pipeline_state.depth_stencil_state.write_enable = VK_TRUE;
|
|
||||||
m_pipeline_state.depth_stencil_state.compare_op = VK_COMPARE_OP_LESS;
|
|
||||||
m_pipeline_state.blend_state.hex = 0;
|
|
||||||
m_pipeline_state.blend_state.blendenable = false;
|
|
||||||
m_pipeline_state.blend_state.srcfactor = BlendMode::ONE;
|
|
||||||
m_pipeline_state.blend_state.srcfactoralpha = BlendMode::ONE;
|
|
||||||
m_pipeline_state.blend_state.dstfactor = BlendMode::ZERO;
|
|
||||||
m_pipeline_state.blend_state.dstfactoralpha = BlendMode::ZERO;
|
|
||||||
m_pipeline_state.blend_state.colorupdate = true;
|
|
||||||
m_pipeline_state.blend_state.alphaupdate = true;
|
|
||||||
|
|
||||||
// Enable depth clamping if supported by driver.
|
|
||||||
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
|
|
||||||
m_pipeline_state.rasterization_state.depth_clamp = VK_TRUE;
|
|
||||||
|
|
||||||
// BBox is disabled by default.
|
// BBox is disabled by default.
|
||||||
m_pipeline_state.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD);
|
m_pipeline_state.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD);
|
||||||
m_num_active_descriptor_sets = NUM_GX_DRAW_DESCRIPTOR_SETS;
|
m_num_active_descriptor_sets = NUM_GX_DRAW_DESCRIPTOR_SETS;
|
||||||
|
@ -166,13 +145,12 @@ void StateTracker::AppendToPipelineUIDCache(const PipelineInfo& info)
|
||||||
{
|
{
|
||||||
SerializedPipelineUID sinfo;
|
SerializedPipelineUID sinfo;
|
||||||
sinfo.blend_state_bits = info.blend_state.hex;
|
sinfo.blend_state_bits = info.blend_state.hex;
|
||||||
sinfo.rasterizer_state_bits = info.rasterization_state.bits;
|
sinfo.rasterizer_state_bits = info.rasterization_state.hex;
|
||||||
sinfo.depth_stencil_state_bits = info.depth_stencil_state.bits;
|
sinfo.depth_state_bits = info.depth_state.hex;
|
||||||
sinfo.vertex_decl = m_pipeline_state.vertex_format->GetVertexDeclaration();
|
sinfo.vertex_decl = m_pipeline_state.vertex_format->GetVertexDeclaration();
|
||||||
sinfo.vs_uid = m_vs_uid;
|
sinfo.vs_uid = m_vs_uid;
|
||||||
sinfo.gs_uid = m_gs_uid;
|
sinfo.gs_uid = m_gs_uid;
|
||||||
sinfo.ps_uid = m_ps_uid;
|
sinfo.ps_uid = m_ps_uid;
|
||||||
sinfo.primitive_topology = info.primitive_topology;
|
|
||||||
|
|
||||||
u32 dummy_value = 0;
|
u32 dummy_value = 0;
|
||||||
m_uid_cache.Append(sinfo, &dummy_value, 1);
|
m_uid_cache.Append(sinfo, &dummy_value, 1);
|
||||||
|
@ -211,10 +189,10 @@ bool StateTracker::PrecachePipelineUID(const SerializedPipelineUID& uid)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
pinfo.render_pass = m_load_render_pass;
|
pinfo.render_pass = m_load_render_pass;
|
||||||
pinfo.rasterization_state.bits = uid.rasterizer_state_bits;
|
pinfo.rasterization_state.hex = uid.rasterizer_state_bits;
|
||||||
pinfo.depth_stencil_state.bits = uid.depth_stencil_state_bits;
|
pinfo.depth_state.hex = uid.depth_state_bits;
|
||||||
pinfo.blend_state.hex = uid.blend_state_bits;
|
pinfo.blend_state.hex = uid.blend_state_bits;
|
||||||
pinfo.primitive_topology = uid.primitive_topology;
|
pinfo.multisampling_state.hex = m_pipeline_state.multisampling_state.hex;
|
||||||
|
|
||||||
if (g_ActiveConfig.bBackgroundShaderCompiling)
|
if (g_ActiveConfig.bBackgroundShaderCompiling)
|
||||||
{
|
{
|
||||||
|
@ -289,39 +267,30 @@ void StateTracker::SetVertexFormat(const VertexFormat* vertex_format)
|
||||||
UpdatePipelineVertexFormat();
|
UpdatePipelineVertexFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateTracker::SetPrimitiveTopology(VkPrimitiveTopology primitive_topology)
|
|
||||||
{
|
|
||||||
if (m_pipeline_state.primitive_topology == primitive_topology)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_pipeline_state.primitive_topology = primitive_topology;
|
|
||||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateTracker::DisableBackFaceCulling()
|
|
||||||
{
|
|
||||||
if (m_pipeline_state.rasterization_state.cull_mode == VK_CULL_MODE_NONE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_pipeline_state.rasterization_state.cull_mode = VK_CULL_MODE_NONE;
|
|
||||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateTracker::SetRasterizationState(const RasterizationState& state)
|
void StateTracker::SetRasterizationState(const RasterizationState& state)
|
||||||
{
|
{
|
||||||
if (m_pipeline_state.rasterization_state.bits == state.bits)
|
if (m_pipeline_state.rasterization_state.hex == state.hex)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_pipeline_state.rasterization_state.bits = state.bits;
|
m_pipeline_state.rasterization_state.hex = state.hex;
|
||||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateTracker::SetDepthStencilState(const DepthStencilState& state)
|
void StateTracker::SetMultisamplingstate(const MultisamplingState& state)
|
||||||
{
|
{
|
||||||
if (m_pipeline_state.depth_stencil_state.bits == state.bits)
|
if (m_pipeline_state.multisampling_state.hex == state.hex)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_pipeline_state.depth_stencil_state.bits = state.bits;
|
m_pipeline_state.multisampling_state.hex = state.hex;
|
||||||
|
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateTracker::SetDepthState(const DepthState& state)
|
||||||
|
{
|
||||||
|
if (m_pipeline_state.depth_state.hex == state.hex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_pipeline_state.depth_state.hex = state.hex;
|
||||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +303,7 @@ void StateTracker::SetBlendState(const BlendingState& state)
|
||||||
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
m_dirty_flags |= DIRTY_FLAG_PIPELINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StateTracker::CheckForShaderChanges(u32 gx_primitive_type)
|
bool StateTracker::CheckForShaderChanges()
|
||||||
{
|
{
|
||||||
VertexShaderUid vs_uid = GetVertexShaderUid();
|
VertexShaderUid vs_uid = GetVertexShaderUid();
|
||||||
PixelShaderUid ps_uid = GetPixelShaderUid();
|
PixelShaderUid ps_uid = GetPixelShaderUid();
|
||||||
|
@ -418,7 +387,7 @@ bool StateTracker::CheckForShaderChanges(u32 gx_primitive_type)
|
||||||
|
|
||||||
if (g_vulkan_context->SupportsGeometryShaders())
|
if (g_vulkan_context->SupportsGeometryShaders())
|
||||||
{
|
{
|
||||||
GeometryShaderUid gs_uid = GetGeometryShaderUid(gx_primitive_type);
|
GeometryShaderUid gs_uid = GetGeometryShaderUid(m_pipeline_state.rasterization_state.primitive);
|
||||||
if (gs_uid != m_gs_uid)
|
if (gs_uid != m_gs_uid)
|
||||||
{
|
{
|
||||||
m_gs_uid = gs_uid;
|
m_gs_uid = gs_uid;
|
||||||
|
|
|
@ -39,29 +39,21 @@ public:
|
||||||
{
|
{
|
||||||
return m_pipeline_state.rasterization_state;
|
return m_pipeline_state.rasterization_state;
|
||||||
}
|
}
|
||||||
const DepthStencilState& GetDepthStencilState() const
|
const DepthState& GetDepthStencilState() const { return m_pipeline_state.depth_state; }
|
||||||
{
|
|
||||||
return m_pipeline_state.depth_stencil_state;
|
|
||||||
}
|
|
||||||
const BlendingState& GetBlendState() const { return m_pipeline_state.blend_state; }
|
const BlendingState& GetBlendState() const { return m_pipeline_state.blend_state; }
|
||||||
void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset);
|
void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset);
|
||||||
void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
|
void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
|
||||||
|
|
||||||
void SetRenderPass(VkRenderPass load_render_pass, VkRenderPass clear_render_pass);
|
void SetRenderPass(VkRenderPass load_render_pass, VkRenderPass clear_render_pass);
|
||||||
|
|
||||||
void SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area);
|
void SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area);
|
||||||
|
|
||||||
void SetVertexFormat(const VertexFormat* vertex_format);
|
void SetVertexFormat(const VertexFormat* vertex_format);
|
||||||
|
|
||||||
void SetPrimitiveTopology(VkPrimitiveTopology primitive_topology);
|
|
||||||
|
|
||||||
void DisableBackFaceCulling();
|
|
||||||
|
|
||||||
void SetRasterizationState(const RasterizationState& state);
|
void SetRasterizationState(const RasterizationState& state);
|
||||||
void SetDepthStencilState(const DepthStencilState& state);
|
void SetMultisamplingstate(const MultisamplingState& state);
|
||||||
|
void SetDepthState(const DepthState& state);
|
||||||
void SetBlendState(const BlendingState& state);
|
void SetBlendState(const BlendingState& state);
|
||||||
|
|
||||||
bool CheckForShaderChanges(u32 gx_primitive_type);
|
bool CheckForShaderChanges();
|
||||||
void ClearShaders();
|
void ClearShaders();
|
||||||
|
|
||||||
void UpdateVertexShaderConstants();
|
void UpdateVertexShaderConstants();
|
||||||
|
@ -130,13 +122,12 @@ private:
|
||||||
struct SerializedPipelineUID
|
struct SerializedPipelineUID
|
||||||
{
|
{
|
||||||
u32 rasterizer_state_bits;
|
u32 rasterizer_state_bits;
|
||||||
u32 depth_stencil_state_bits;
|
u32 depth_state_bits;
|
||||||
u32 blend_state_bits;
|
u32 blend_state_bits;
|
||||||
PortableVertexDeclaration vertex_decl;
|
PortableVertexDeclaration vertex_decl;
|
||||||
VertexShaderUid vs_uid;
|
VertexShaderUid vs_uid;
|
||||||
GeometryShaderUid gs_uid;
|
GeometryShaderUid gs_uid;
|
||||||
PixelShaderUid ps_uid;
|
PixelShaderUid ps_uid;
|
||||||
VkPrimitiveTopology primitive_topology;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Number of descriptor sets for game draws.
|
// Number of descriptor sets for game draws.
|
||||||
|
|
|
@ -214,7 +214,7 @@ void TextureConverter::ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry,
|
||||||
g_object_cache->GetPointSampler());
|
g_object_cache->GetPointSampler());
|
||||||
draw.SetPSTexelBuffer(m_texel_buffer_view_r16_uint);
|
draw.SetPSTexelBuffer(m_texel_buffer_view_r16_uint);
|
||||||
draw.SetViewportAndScissor(0, 0, dst_entry->GetWidth(), dst_entry->GetHeight());
|
draw.SetViewportAndScissor(0, 0, dst_entry->GetWidth(), dst_entry->GetHeight());
|
||||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
draw.DrawWithoutVertexBuffer(4);
|
||||||
draw.EndRenderPass();
|
draw.EndRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
|
||||||
|
|
||||||
VkRect2D render_region = {{0, 0}, {render_width, render_height}};
|
VkRect2D render_region = {{0, 0}, {render_width, render_height}};
|
||||||
draw.BeginRenderPass(m_encoding_render_framebuffer, render_region);
|
draw.BeginRenderPass(m_encoding_render_framebuffer, render_region);
|
||||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
draw.DrawWithoutVertexBuffer(4);
|
||||||
draw.EndRenderPass();
|
draw.EndRenderPass();
|
||||||
|
|
||||||
// Transition the image before copying
|
// Transition the image before copying
|
||||||
|
@ -382,7 +382,7 @@ void TextureConverter::DecodeYUYVTextureFromMemory(VKTexture* dst_texture, const
|
||||||
draw.SetViewportAndScissor(0, 0, static_cast<int>(src_width), static_cast<int>(src_height));
|
draw.SetViewportAndScissor(0, 0, static_cast<int>(src_width), static_cast<int>(src_height));
|
||||||
draw.SetPSTexelBuffer(m_texel_buffer_view_rgba8_unorm);
|
draw.SetPSTexelBuffer(m_texel_buffer_view_rgba8_unorm);
|
||||||
draw.SetPushConstants(&push_constants, sizeof(push_constants));
|
draw.SetPushConstants(&push_constants, sizeof(push_constants));
|
||||||
draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4);
|
draw.DrawWithoutVertexBuffer(4);
|
||||||
draw.EndRenderPass();
|
draw.EndRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,6 +801,7 @@ bool TextureConverter::CompileYUYVConversionShaders()
|
||||||
static const char RGB_TO_YUYV_SHADER_SOURCE[] = R"(
|
static const char RGB_TO_YUYV_SHADER_SOURCE[] = R"(
|
||||||
SAMPLER_BINDING(0) uniform sampler2DArray source;
|
SAMPLER_BINDING(0) uniform sampler2DArray source;
|
||||||
layout(location = 0) in vec3 uv0;
|
layout(location = 0) in vec3 uv0;
|
||||||
|
layout(location = 1) in vec4 col0;
|
||||||
layout(location = 0) out vec4 ocol0;
|
layout(location = 0) out vec4 ocol0;
|
||||||
|
|
||||||
const vec3 y_const = vec3(0.257,0.504,0.098);
|
const vec3 y_const = vec3(0.257,0.504,0.098);
|
||||||
|
|
|
@ -185,39 +185,6 @@ VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RasterizationState GetNoCullRasterizationState()
|
|
||||||
{
|
|
||||||
RasterizationState state = {};
|
|
||||||
state.cull_mode = VK_CULL_MODE_NONE;
|
|
||||||
state.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
state.per_sample_shading = VK_FALSE;
|
|
||||||
state.depth_clamp = VK_FALSE;
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
DepthStencilState GetNoDepthTestingDepthStencilState()
|
|
||||||
{
|
|
||||||
DepthStencilState state = {};
|
|
||||||
state.test_enable = VK_FALSE;
|
|
||||||
state.write_enable = VK_FALSE;
|
|
||||||
state.compare_op = VK_COMPARE_OP_ALWAYS;
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlendingState GetNoBlendingBlendState()
|
|
||||||
{
|
|
||||||
BlendingState state = {};
|
|
||||||
state.blendenable = false;
|
|
||||||
state.srcfactor = BlendMode::ONE;
|
|
||||||
state.srcfactoralpha = BlendMode::ZERO;
|
|
||||||
state.dstfactor = BlendMode::ONE;
|
|
||||||
state.dstfactoralpha = BlendMode::ZERO;
|
|
||||||
state.logicopenable = false;
|
|
||||||
state.colorupdate = true;
|
|
||||||
state.alphaupdate = true;
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetViewportAndScissor(VkCommandBuffer command_buffer, int x, int y, int width, int height,
|
void SetViewportAndScissor(VkCommandBuffer command_buffer, int x, int y, int width, int height,
|
||||||
float min_depth /*= 0.0f*/, float max_depth /*= 1.0f*/)
|
float min_depth /*= 0.0f*/, float max_depth /*= 1.0f*/)
|
||||||
{
|
{
|
||||||
|
@ -335,7 +302,7 @@ VkShaderModule CompileAndCreateComputeShader(const std::string& source_code, boo
|
||||||
UtilityShaderDraw::UtilityShaderDraw(VkCommandBuffer command_buffer,
|
UtilityShaderDraw::UtilityShaderDraw(VkCommandBuffer command_buffer,
|
||||||
VkPipelineLayout pipeline_layout, VkRenderPass render_pass,
|
VkPipelineLayout pipeline_layout, VkRenderPass render_pass,
|
||||||
VkShaderModule vertex_shader, VkShaderModule geometry_shader,
|
VkShaderModule vertex_shader, VkShaderModule geometry_shader,
|
||||||
VkShaderModule pixel_shader)
|
VkShaderModule pixel_shader, PrimitiveType primitive)
|
||||||
: m_command_buffer(command_buffer)
|
: m_command_buffer(command_buffer)
|
||||||
{
|
{
|
||||||
// Populate minimal pipeline state
|
// Populate minimal pipeline state
|
||||||
|
@ -345,16 +312,16 @@ UtilityShaderDraw::UtilityShaderDraw(VkCommandBuffer command_buffer,
|
||||||
m_pipeline_info.vs = vertex_shader;
|
m_pipeline_info.vs = vertex_shader;
|
||||||
m_pipeline_info.gs = geometry_shader;
|
m_pipeline_info.gs = geometry_shader;
|
||||||
m_pipeline_info.ps = pixel_shader;
|
m_pipeline_info.ps = pixel_shader;
|
||||||
m_pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits;
|
m_pipeline_info.rasterization_state.hex = RenderState::GetNoCullRasterizationState().hex;
|
||||||
m_pipeline_info.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits;
|
m_pipeline_info.rasterization_state.primitive = primitive;
|
||||||
m_pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex;
|
m_pipeline_info.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex;
|
||||||
m_pipeline_info.primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
m_pipeline_info.blend_state.hex = RenderState::GetNoBlendingBlendState().hex;
|
||||||
|
m_pipeline_info.multisampling_state.per_sample_shading = false;
|
||||||
|
m_pipeline_info.multisampling_state.samples = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
UtilityShaderVertex* UtilityShaderDraw::ReserveVertices(VkPrimitiveTopology topology, size_t count)
|
UtilityShaderVertex* UtilityShaderDraw::ReserveVertices(size_t count)
|
||||||
{
|
{
|
||||||
m_pipeline_info.primitive_topology = topology;
|
|
||||||
|
|
||||||
if (!g_object_cache->GetUtilityShaderVertexBuffer()->ReserveMemory(
|
if (!g_object_cache->GetUtilityShaderVertexBuffer()->ReserveMemory(
|
||||||
sizeof(UtilityShaderVertex) * count, sizeof(UtilityShaderVertex), true, true, true))
|
sizeof(UtilityShaderVertex) * count, sizeof(UtilityShaderVertex), true, true, true))
|
||||||
PanicAlert("Failed to allocate space for vertices in backend shader");
|
PanicAlert("Failed to allocate space for vertices in backend shader");
|
||||||
|
@ -372,10 +339,9 @@ void UtilityShaderDraw::CommitVertices(size_t count)
|
||||||
m_vertex_count = static_cast<uint32_t>(count);
|
m_vertex_count = static_cast<uint32_t>(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UtilityShaderDraw::UploadVertices(VkPrimitiveTopology topology, UtilityShaderVertex* vertices,
|
void UtilityShaderDraw::UploadVertices(UtilityShaderVertex* vertices, size_t count)
|
||||||
size_t count)
|
|
||||||
{
|
{
|
||||||
UtilityShaderVertex* upload_vertices = ReserveVertices(topology, count);
|
UtilityShaderVertex* upload_vertices = ReserveVertices(count);
|
||||||
memcpy(upload_vertices, vertices, sizeof(UtilityShaderVertex) * count);
|
memcpy(upload_vertices, vertices, sizeof(UtilityShaderVertex) * count);
|
||||||
CommitVertices(count);
|
CommitVertices(count);
|
||||||
}
|
}
|
||||||
|
@ -447,12 +413,17 @@ void UtilityShaderDraw::SetPSTexelBuffer(VkBufferView view)
|
||||||
|
|
||||||
void UtilityShaderDraw::SetRasterizationState(const RasterizationState& state)
|
void UtilityShaderDraw::SetRasterizationState(const RasterizationState& state)
|
||||||
{
|
{
|
||||||
m_pipeline_info.rasterization_state.bits = state.bits;
|
m_pipeline_info.rasterization_state.hex = state.hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UtilityShaderDraw::SetDepthStencilState(const DepthStencilState& state)
|
void UtilityShaderDraw::SetMultisamplingState(const MultisamplingState& state)
|
||||||
{
|
{
|
||||||
m_pipeline_info.depth_stencil_state.bits = state.bits;
|
m_pipeline_info.multisampling_state.hex = state.hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UtilityShaderDraw::SetDepthState(const DepthState& state)
|
||||||
|
{
|
||||||
|
m_pipeline_info.depth_state.hex = state.hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UtilityShaderDraw::SetBlendState(const BlendingState& state)
|
void UtilityShaderDraw::SetBlendState(const BlendingState& state)
|
||||||
|
@ -506,7 +477,7 @@ void UtilityShaderDraw::DrawQuad(int x, int y, int width, int height, float z)
|
||||||
vertices[3].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
vertices[3].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
Util::SetViewportAndScissor(m_command_buffer, x, y, width, height);
|
Util::SetViewportAndScissor(m_command_buffer, x, y, width, height);
|
||||||
UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices));
|
UploadVertices(vertices, ArraySize(vertices));
|
||||||
Draw();
|
Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,7 +506,7 @@ void UtilityShaderDraw::DrawQuad(int dst_x, int dst_y, int dst_width, int dst_he
|
||||||
vertices[3].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
vertices[3].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
Util::SetViewportAndScissor(m_command_buffer, dst_x, dst_y, dst_width, dst_height);
|
Util::SetViewportAndScissor(m_command_buffer, dst_x, dst_y, dst_width, dst_height);
|
||||||
UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices));
|
UploadVertices(vertices, ArraySize(vertices));
|
||||||
Draw();
|
Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,7 +533,7 @@ void UtilityShaderDraw::DrawColoredQuad(int x, int y, int width, int height, u32
|
||||||
vertices[3].SetColor(color);
|
vertices[3].SetColor(color);
|
||||||
|
|
||||||
Util::SetViewportAndScissor(m_command_buffer, x, y, width, height);
|
Util::SetViewportAndScissor(m_command_buffer, x, y, width, height);
|
||||||
UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices));
|
UploadVertices(vertices, ArraySize(vertices));
|
||||||
Draw();
|
Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,11 +542,9 @@ void UtilityShaderDraw::SetViewportAndScissor(int x, int y, int width, int heigh
|
||||||
Util::SetViewportAndScissor(m_command_buffer, x, y, width, height, 0.0f, 1.0f);
|
Util::SetViewportAndScissor(m_command_buffer, x, y, width, height, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UtilityShaderDraw::DrawWithoutVertexBuffer(VkPrimitiveTopology primitive_topology,
|
void UtilityShaderDraw::DrawWithoutVertexBuffer(u32 vertex_count)
|
||||||
u32 vertex_count)
|
|
||||||
{
|
{
|
||||||
m_pipeline_info.vertex_format = nullptr;
|
m_pipeline_info.vertex_format = nullptr;
|
||||||
m_pipeline_info.primitive_topology = primitive_topology;
|
|
||||||
|
|
||||||
BindDescriptors();
|
BindDescriptors();
|
||||||
if (!BindPipeline())
|
if (!BindPipeline())
|
||||||
|
|
|
@ -38,10 +38,6 @@ VkRect2D ClampRect2D(const VkRect2D& rect, u32 width, u32 height);
|
||||||
// Map {SRC,DST}_COLOR to {SRC,DST}_ALPHA
|
// Map {SRC,DST}_COLOR to {SRC,DST}_ALPHA
|
||||||
VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor);
|
VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor);
|
||||||
|
|
||||||
RasterizationState GetNoCullRasterizationState();
|
|
||||||
DepthStencilState GetNoDepthTestingDepthStencilState();
|
|
||||||
BlendingState GetNoBlendingBlendState();
|
|
||||||
|
|
||||||
// Combines viewport and scissor updates
|
// Combines viewport and scissor updates
|
||||||
void SetViewportAndScissor(VkCommandBuffer command_buffer, int x, int y, int width, int height,
|
void SetViewportAndScissor(VkCommandBuffer command_buffer, int x, int y, int width, int height,
|
||||||
float min_depth = 0.0f, float max_depth = 1.0f);
|
float min_depth = 0.0f, float max_depth = 1.0f);
|
||||||
|
@ -131,12 +127,13 @@ class UtilityShaderDraw
|
||||||
public:
|
public:
|
||||||
UtilityShaderDraw(VkCommandBuffer command_buffer, VkPipelineLayout pipeline_layout,
|
UtilityShaderDraw(VkCommandBuffer command_buffer, VkPipelineLayout pipeline_layout,
|
||||||
VkRenderPass render_pass, VkShaderModule vertex_shader,
|
VkRenderPass render_pass, VkShaderModule vertex_shader,
|
||||||
VkShaderModule geometry_shader, VkShaderModule pixel_shader);
|
VkShaderModule geometry_shader, VkShaderModule pixel_shader,
|
||||||
|
PrimitiveType primitive = PrimitiveType::TriangleStrip);
|
||||||
|
|
||||||
UtilityShaderVertex* ReserveVertices(VkPrimitiveTopology topology, size_t count);
|
UtilityShaderVertex* ReserveVertices(size_t count);
|
||||||
void CommitVertices(size_t count);
|
void CommitVertices(size_t count);
|
||||||
|
|
||||||
void UploadVertices(VkPrimitiveTopology topology, UtilityShaderVertex* vertices, size_t count);
|
void UploadVertices(UtilityShaderVertex* vertices, size_t count);
|
||||||
|
|
||||||
u8* AllocateVSUniforms(size_t size);
|
u8* AllocateVSUniforms(size_t size);
|
||||||
void CommitVSUniforms(size_t size);
|
void CommitVSUniforms(size_t size);
|
||||||
|
@ -151,7 +148,8 @@ public:
|
||||||
void SetPSTexelBuffer(VkBufferView view);
|
void SetPSTexelBuffer(VkBufferView view);
|
||||||
|
|
||||||
void SetRasterizationState(const RasterizationState& state);
|
void SetRasterizationState(const RasterizationState& state);
|
||||||
void SetDepthStencilState(const DepthStencilState& state);
|
void SetMultisamplingState(const MultisamplingState& state);
|
||||||
|
void SetDepthState(const DepthState& state);
|
||||||
void SetBlendState(const BlendingState& state);
|
void SetBlendState(const BlendingState& state);
|
||||||
|
|
||||||
void BeginRenderPass(VkFramebuffer framebuffer, const VkRect2D& region,
|
void BeginRenderPass(VkFramebuffer framebuffer, const VkRect2D& region,
|
||||||
|
@ -177,7 +175,7 @@ public:
|
||||||
|
|
||||||
// Draw without a vertex buffer. Assumes viewport has been initialized separately.
|
// Draw without a vertex buffer. Assumes viewport has been initialized separately.
|
||||||
void SetViewportAndScissor(int x, int y, int width, int height);
|
void SetViewportAndScissor(int x, int y, int width, int height);
|
||||||
void DrawWithoutVertexBuffer(VkPrimitiveTopology primitive_topology, u32 vertex_count);
|
void DrawWithoutVertexBuffer(u32 vertex_count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void BindVertexBuffer();
|
void BindVertexBuffer();
|
||||||
|
|
|
@ -138,33 +138,9 @@ void VertexManager::vFlush()
|
||||||
// Figure out the number of indices to draw
|
// Figure out the number of indices to draw
|
||||||
u32 index_count = IndexGenerator::GetIndexLen();
|
u32 index_count = IndexGenerator::GetIndexLen();
|
||||||
|
|
||||||
// Update assembly state
|
// Update tracked state
|
||||||
StateTracker::GetInstance()->SetVertexFormat(vertex_format);
|
StateTracker::GetInstance()->SetVertexFormat(vertex_format);
|
||||||
switch (m_current_primitive_type)
|
StateTracker::GetInstance()->CheckForShaderChanges();
|
||||||
{
|
|
||||||
case PRIMITIVE_POINTS:
|
|
||||||
StateTracker::GetInstance()->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
|
|
||||||
StateTracker::GetInstance()->DisableBackFaceCulling();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PRIMITIVE_LINES:
|
|
||||||
StateTracker::GetInstance()->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
|
|
||||||
StateTracker::GetInstance()->DisableBackFaceCulling();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PRIMITIVE_TRIANGLES:
|
|
||||||
StateTracker::GetInstance()->SetPrimitiveTopology(
|
|
||||||
g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ?
|
|
||||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP :
|
|
||||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
|
|
||||||
g_renderer->SetGenerationMode();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for any shader stage changes
|
|
||||||
StateTracker::GetInstance()->CheckForShaderChanges(m_current_primitive_type);
|
|
||||||
|
|
||||||
// Update any changed constants
|
|
||||||
StateTracker::GetInstance()->UpdateVertexShaderConstants();
|
StateTracker::GetInstance()->UpdateVertexShaderConstants();
|
||||||
StateTracker::GetInstance()->UpdateGeometryShaderConstants();
|
StateTracker::GetInstance()->UpdateGeometryShaderConstants();
|
||||||
StateTracker::GetInstance()->UpdatePixelShaderConstants();
|
StateTracker::GetInstance()->UpdatePixelShaderConstants();
|
||||||
|
|
|
@ -27,7 +27,9 @@ void FlushPipeline()
|
||||||
|
|
||||||
void SetGenerationMode()
|
void SetGenerationMode()
|
||||||
{
|
{
|
||||||
g_renderer->SetGenerationMode();
|
RasterizationState state = {};
|
||||||
|
state.Generate(bpmem, g_vertex_manager->GetCurrentPrimitiveType());
|
||||||
|
g_renderer->SetRasterizationState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetScissor()
|
void SetScissor()
|
||||||
|
@ -68,12 +70,14 @@ void SetScissor()
|
||||||
|
|
||||||
void SetDepthMode()
|
void SetDepthMode()
|
||||||
{
|
{
|
||||||
g_renderer->SetDepthMode();
|
DepthState state = {};
|
||||||
|
state.Generate(bpmem);
|
||||||
|
g_renderer->SetDepthState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetBlendMode()
|
void SetBlendMode()
|
||||||
{
|
{
|
||||||
BlendingState state;
|
BlendingState state = {};
|
||||||
state.Generate(bpmem);
|
state.Generate(bpmem);
|
||||||
g_renderer->SetBlendingState(state);
|
g_renderer->SetBlendingState(state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,24 +14,24 @@
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
#include "VideoCommon/XFMemory.h"
|
#include "VideoCommon/XFMemory.h"
|
||||||
|
|
||||||
static const char* primitives_ogl[] = {"points", "lines", "triangles"};
|
constexpr std::array<const char*, 4> primitives_ogl = {
|
||||||
|
{"points", "lines", "triangles", "triangles"}};
|
||||||
static const char* primitives_d3d[] = {"point", "line", "triangle"};
|
constexpr std::array<const char*, 4> primitives_d3d = {{"point", "line", "triangle", "triangle"}};
|
||||||
|
|
||||||
bool geometry_shader_uid_data::IsPassthrough() const
|
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 == PRIMITIVE_TRIANGLES && !stereo && !wireframe;
|
return primitive_type >= static_cast<u32>(PrimitiveType::Triangles) && !stereo && !wireframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type)
|
GeometryShaderUid GetGeometryShaderUid(PrimitiveType primitive_type)
|
||||||
{
|
{
|
||||||
ShaderUid<geometry_shader_uid_data> out;
|
ShaderUid<geometry_shader_uid_data> out;
|
||||||
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,8 +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 unsigned int vertex_in = uid_data->primitive_type + 1;
|
const PrimitiveType primitive_type = static_cast<PrimitiveType>(uid_data->primitive_type);
|
||||||
unsigned int vertex_out = uid_data->primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4;
|
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);
|
||||||
|
unsigned vertex_out = primitive_type == PrimitiveType::TriangleStrip ? 3 : 4;
|
||||||
|
|
||||||
if (wireframe)
|
if (wireframe)
|
||||||
vertex_out++;
|
vertex_out++;
|
||||||
|
@ -67,14 +69,14 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
|
||||||
// Insert layout parameters
|
// Insert layout parameters
|
||||||
if (host_config.backend_gs_instancing)
|
if (host_config.backend_gs_instancing)
|
||||||
{
|
{
|
||||||
out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[uid_data->primitive_type],
|
out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[primitive_type_index],
|
||||||
stereo ? 2 : 1);
|
stereo ? 2 : 1);
|
||||||
out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle",
|
out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle",
|
||||||
vertex_out);
|
vertex_out);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out.Write("layout(%s) in;\n", primitives_ogl[uid_data->primitive_type]);
|
out.Write("layout(%s) in;\n", primitives_ogl[primitive_type_index]);
|
||||||
out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle",
|
out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle",
|
||||||
stereo ? vertex_out * 2 : vertex_out);
|
stereo ? vertex_out * 2 : vertex_out);
|
||||||
}
|
}
|
||||||
|
@ -133,21 +135,19 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
|
||||||
out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, stereo ? 2 : 1);
|
out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, stereo ? 2 : 1);
|
||||||
out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream<VertexData> output, in uint "
|
out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream<VertexData> output, in uint "
|
||||||
"InstanceID : SV_GSInstanceID)\n{\n",
|
"InstanceID : SV_GSInstanceID)\n{\n",
|
||||||
primitives_d3d[uid_data->primitive_type], vertex_in,
|
primitives_d3d[primitive_type_index], vertex_in, wireframe ? "Line" : "Triangle");
|
||||||
wireframe ? "Line" : "Triangle");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out.Write("[maxvertexcount(%d)]\n", stereo ? vertex_out * 2 : vertex_out);
|
out.Write("[maxvertexcount(%d)]\n", stereo ? vertex_out * 2 : vertex_out);
|
||||||
out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream<VertexData> output)\n{\n",
|
out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream<VertexData> output)\n{\n",
|
||||||
primitives_d3d[uid_data->primitive_type], vertex_in,
|
primitives_d3d[primitive_type_index], vertex_in, wireframe ? "Line" : "Triangle");
|
||||||
wireframe ? "Line" : "Triangle");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Write("\tVertexData ps;\n");
|
out.Write("\tVertexData ps;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid_data->primitive_type == PRIMITIVE_LINES)
|
if (primitive_type == PrimitiveType::Lines)
|
||||||
{
|
{
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
|
@ -178,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 == PRIMITIVE_POINTS)
|
else if (primitive_type == PrimitiveType::Points)
|
||||||
{
|
{
|
||||||
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
|
||||||
{
|
{
|
||||||
|
@ -248,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 == PRIMITIVE_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");
|
||||||
|
@ -269,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 == PRIMITIVE_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"
|
||||||
|
@ -370,12 +370,14 @@ void EnumerateGeometryShaderUids(const std::function<void(const GeometryShaderUi
|
||||||
GeometryShaderUid uid;
|
GeometryShaderUid uid;
|
||||||
std::memset(&uid, 0, sizeof(uid));
|
std::memset(&uid, 0, sizeof(uid));
|
||||||
|
|
||||||
static constexpr std::array<u32, 3> primitive_lut = {
|
const std::array<PrimitiveType, 3> primitive_lut = {
|
||||||
{PRIMITIVE_TRIANGLES, PRIMITIVE_LINES, PRIMITIVE_POINTS}};
|
{g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? PrimitiveType::TriangleStrip :
|
||||||
for (u32 primitive : primitive_lut)
|
PrimitiveType::Triangles,
|
||||||
|
PrimitiveType::Lines, PrimitiveType::Points}};
|
||||||
|
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++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "VideoCommon/RenderState.h"
|
||||||
#include "VideoCommon/ShaderGenCommon.h"
|
#include "VideoCommon/ShaderGenCommon.h"
|
||||||
#include "VideoCommon/VertexManagerBase.h"
|
#include "VideoCommon/VertexManagerBase.h"
|
||||||
|
|
||||||
|
@ -28,5 +29,5 @@ typedef ShaderUid<geometry_shader_uid_data> GeometryShaderUid;
|
||||||
|
|
||||||
ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& host_config,
|
ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& host_config,
|
||||||
const geometry_shader_uid_data* uid_data);
|
const geometry_shader_uid_data* uid_data);
|
||||||
GeometryShaderUid GetGeometryShaderUid(u32 primitive_type);
|
GeometryShaderUid GetGeometryShaderUid(PrimitiveType primitive_type);
|
||||||
void EnumerateGeometryShaderUids(const std::function<void(const GeometryShaderUid&)>& callback);
|
void EnumerateGeometryShaderUids(const std::function<void(const GeometryShaderUid&)>& callback);
|
||||||
|
|
|
@ -66,9 +66,9 @@ public:
|
||||||
|
|
||||||
virtual void SetBlendingState(const BlendingState& state) {}
|
virtual void SetBlendingState(const BlendingState& state) {}
|
||||||
virtual void SetScissorRect(const EFBRectangle& rc) {}
|
virtual void SetScissorRect(const EFBRectangle& rc) {}
|
||||||
virtual void SetGenerationMode() {}
|
virtual void SetRasterizationState(const RasterizationState& state) {}
|
||||||
virtual void SetDepthMode() {}
|
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,38 @@
|
||||||
// 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)
|
||||||
|
{
|
||||||
|
cullmode = bp.genMode.cullmode;
|
||||||
|
primitive = primitive_type;
|
||||||
|
|
||||||
|
// Back-face culling should be disabled for points/lines.
|
||||||
|
if (primitive_type != PrimitiveType::Triangles && primitive_type != PrimitiveType::TriangleStrip)
|
||||||
|
cullmode = GenMode::CULL_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
RasterizationState& RasterizationState::operator=(const RasterizationState& rhs)
|
||||||
|
{
|
||||||
|
hex = rhs.hex;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepthState::Generate(const BPMemory& bp)
|
||||||
|
{
|
||||||
|
testenable = bp.zmode.testenable.Value();
|
||||||
|
updateenable = bp.zmode.updateenable.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
|
||||||
|
@ -127,3 +159,104 @@ 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
|
||||||
|
{
|
||||||
|
RasterizationState GetNoCullRasterizationState()
|
||||||
|
{
|
||||||
|
RasterizationState state = {};
|
||||||
|
state.cullmode = GenMode::CULL_NONE;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
DepthState GetNoDepthTestingDepthStencilState()
|
||||||
|
{
|
||||||
|
DepthState state = {};
|
||||||
|
state.testenable = false;
|
||||||
|
state.updateenable = false;
|
||||||
|
state.func = ZMode::ALWAYS;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlendingState GetNoBlendingBlendState()
|
||||||
|
{
|
||||||
|
BlendingState state = {};
|
||||||
|
state.usedualsrc = false;
|
||||||
|
state.blendenable = false;
|
||||||
|
state.srcfactor = BlendMode::ONE;
|
||||||
|
state.srcfactoralpha = BlendMode::ONE;
|
||||||
|
state.dstfactor = BlendMode::ZERO;
|
||||||
|
state.dstfactoralpha = BlendMode::ZERO;
|
||||||
|
state.logicopenable = false;
|
||||||
|
state.colorupdate = true;
|
||||||
|
state.alphaupdate = true;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,10 +9,54 @@
|
||||||
#include "VideoCommon/BPMemory.h"
|
#include "VideoCommon/BPMemory.h"
|
||||||
#include "VideoCommon/BPStructs.h"
|
#include "VideoCommon/BPStructs.h"
|
||||||
|
|
||||||
|
enum class PrimitiveType : u32
|
||||||
|
{
|
||||||
|
Points,
|
||||||
|
Lines,
|
||||||
|
Triangles,
|
||||||
|
TriangleStrip,
|
||||||
|
};
|
||||||
|
|
||||||
|
union RasterizationState
|
||||||
|
{
|
||||||
|
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<3, 2, PrimitiveType> primitive;
|
||||||
|
|
||||||
|
u32 hex;
|
||||||
|
};
|
||||||
|
|
||||||
|
union DepthState
|
||||||
|
{
|
||||||
|
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<1, 1, u32> updateenable;
|
||||||
|
BitField<2, 3, ZMode::CompareMode> func;
|
||||||
|
|
||||||
|
u32 hex;
|
||||||
|
};
|
||||||
|
|
||||||
union BlendingState
|
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;
|
||||||
|
@ -29,3 +73,47 @@ 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
|
||||||
|
{
|
||||||
|
RasterizationState GetNoCullRasterizationState();
|
||||||
|
DepthState GetNoDepthTestingDepthStencilState();
|
||||||
|
BlendingState GetNoBlendingBlendState();
|
||||||
|
SamplerState GetPointSamplerState();
|
||||||
|
SamplerState GetLinearSamplerState();
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "VideoCommon/VertexManagerBase.h"
|
#include "VideoCommon/VertexManagerBase.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -23,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"
|
||||||
|
@ -32,15 +34,28 @@
|
||||||
|
|
||||||
std::unique_ptr<VertexManagerBase> g_vertex_manager;
|
std::unique_ptr<VertexManagerBase> g_vertex_manager;
|
||||||
|
|
||||||
static const PrimitiveType primitive_from_gx[8] = {
|
// GX primitive -> RenderState primitive, no primitive restart
|
||||||
PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS
|
constexpr std::array<PrimitiveType, 8> primitive_from_gx = {
|
||||||
PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS_2
|
PrimitiveType::Triangles, // GX_DRAW_QUADS
|
||||||
PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLES
|
PrimitiveType::Triangles, // GX_DRAW_QUADS_2
|
||||||
PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLE_STRIP
|
PrimitiveType::Triangles, // GX_DRAW_TRIANGLES
|
||||||
PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLE_FAN
|
PrimitiveType::Triangles, // GX_DRAW_TRIANGLE_STRIP
|
||||||
PRIMITIVE_LINES, // GX_DRAW_LINES
|
PrimitiveType::Triangles, // GX_DRAW_TRIANGLE_FAN
|
||||||
PRIMITIVE_LINES, // GX_DRAW_LINE_STRIP
|
PrimitiveType::Lines, // GX_DRAW_LINES
|
||||||
PRIMITIVE_POINTS, // GX_DRAW_POINTS
|
PrimitiveType::Lines, // GX_DRAW_LINE_STRIP
|
||||||
|
PrimitiveType::Points, // GX_DRAW_POINTS
|
||||||
|
};
|
||||||
|
|
||||||
|
// GX primitive -> RenderState primitive, using primitive restart
|
||||||
|
constexpr std::array<PrimitiveType, 8> primitive_from_gx_pr = {
|
||||||
|
PrimitiveType::TriangleStrip, // GX_DRAW_QUADS
|
||||||
|
PrimitiveType::TriangleStrip, // GX_DRAW_QUADS_2
|
||||||
|
PrimitiveType::TriangleStrip, // GX_DRAW_TRIANGLES
|
||||||
|
PrimitiveType::TriangleStrip, // GX_DRAW_TRIANGLE_STRIP
|
||||||
|
PrimitiveType::TriangleStrip, // GX_DRAW_TRIANGLE_FAN
|
||||||
|
PrimitiveType::Lines, // GX_DRAW_LINES
|
||||||
|
PrimitiveType::Lines, // GX_DRAW_LINE_STRIP
|
||||||
|
PrimitiveType::Points, // GX_DRAW_POINTS
|
||||||
};
|
};
|
||||||
|
|
||||||
// Due to the BT.601 standard which the GameCube is based on being a compromise
|
// Due to the BT.601 standard which the GameCube is based on being a compromise
|
||||||
|
@ -80,9 +95,19 @@ DataReader VertexManagerBase::PrepareForAdditionalData(int primitive, u32 count,
|
||||||
u32 const needed_vertex_bytes = count * stride + 4;
|
u32 const needed_vertex_bytes = count * stride + 4;
|
||||||
|
|
||||||
// We can't merge different kinds of primitives, so we have to flush here
|
// We can't merge different kinds of primitives, so we have to flush here
|
||||||
if (m_current_primitive_type != primitive_from_gx[primitive])
|
PrimitiveType new_primitive_type = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ?
|
||||||
|
primitive_from_gx_pr[primitive] :
|
||||||
|
primitive_from_gx[primitive];
|
||||||
|
if (m_current_primitive_type != new_primitive_type)
|
||||||
|
{
|
||||||
Flush();
|
Flush();
|
||||||
m_current_primitive_type = primitive_from_gx[primitive];
|
|
||||||
|
// Have to update the rasterization state for point/line cull modes.
|
||||||
|
RasterizationState raster_state = {};
|
||||||
|
raster_state.Generate(bpmem, new_primitive_type);
|
||||||
|
g_renderer->SetRasterizationState(raster_state);
|
||||||
|
m_current_primitive_type = new_primitive_type;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for size in buffer, if the buffer gets full, call Flush()
|
// Check for size in buffer, if the buffer gets full, call Flush()
|
||||||
if (!m_is_flushed &&
|
if (!m_is_flushed &&
|
||||||
|
@ -184,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)
|
||||||
|
@ -252,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
|
||||||
|
@ -332,8 +403,11 @@ void VertexManagerBase::CalculateZSlope(NativeVertexFormat* format)
|
||||||
float viewOffset[2] = {xfmem.viewport.xOrig - bpmem.scissorOffset.x * 2,
|
float viewOffset[2] = {xfmem.viewport.xOrig - bpmem.scissorOffset.x * 2,
|
||||||
xfmem.viewport.yOrig - bpmem.scissorOffset.y * 2};
|
xfmem.viewport.yOrig - bpmem.scissorOffset.y * 2};
|
||||||
|
|
||||||
if (m_current_primitive_type != PRIMITIVE_TRIANGLES)
|
if (m_current_primitive_type != PrimitiveType::Triangles &&
|
||||||
|
m_current_primitive_type != PrimitiveType::TriangleStrip)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Global matrix ID.
|
// Global matrix ID.
|
||||||
u32 mtxIdx = g_main_cp_state.matrix_index_a.PosNormalMtxIdx;
|
u32 mtxIdx = g_main_cp_state.matrix_index_a.PosNormalMtxIdx;
|
||||||
|
|
|
@ -9,19 +9,13 @@
|
||||||
|
|
||||||
#include "Common/CommonFuncs.h"
|
#include "Common/CommonFuncs.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "VideoCommon/RenderState.h"
|
||||||
|
|
||||||
class DataReader;
|
class DataReader;
|
||||||
class NativeVertexFormat;
|
class NativeVertexFormat;
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
struct PortableVertexDeclaration;
|
struct PortableVertexDeclaration;
|
||||||
|
|
||||||
enum PrimitiveType
|
|
||||||
{
|
|
||||||
PRIMITIVE_POINTS,
|
|
||||||
PRIMITIVE_LINES,
|
|
||||||
PRIMITIVE_TRIANGLES,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Slope
|
struct Slope
|
||||||
{
|
{
|
||||||
float dfdx;
|
float dfdx;
|
||||||
|
@ -51,6 +45,7 @@ public:
|
||||||
// needs to be virtual for DX11's dtor
|
// needs to be virtual for DX11's dtor
|
||||||
virtual ~VertexManagerBase();
|
virtual ~VertexManagerBase();
|
||||||
|
|
||||||
|
PrimitiveType GetCurrentPrimitiveType() const { return m_current_primitive_type; }
|
||||||
DataReader PrepareForAdditionalData(int primitive, u32 count, u32 stride, bool cullall);
|
DataReader PrepareForAdditionalData(int primitive, u32 count, u32 stride, bool cullall);
|
||||||
void FlushData(u32 count, u32 stride);
|
void FlushData(u32 count, u32 stride);
|
||||||
|
|
||||||
|
@ -65,8 +60,6 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void vDoState(PointerWrap& p) {}
|
virtual void vDoState(PointerWrap& p) {}
|
||||||
PrimitiveType m_current_primitive_type = PrimitiveType::PRIMITIVE_POINTS;
|
|
||||||
|
|
||||||
virtual void ResetBuffer(u32 stride) = 0;
|
virtual void ResetBuffer(u32 stride) = 0;
|
||||||
|
|
||||||
u8* m_cur_buffer_pointer = nullptr;
|
u8* m_cur_buffer_pointer = nullptr;
|
||||||
|
@ -80,6 +73,7 @@ protected:
|
||||||
void CalculateZSlope(NativeVertexFormat* format);
|
void CalculateZSlope(NativeVertexFormat* format);
|
||||||
|
|
||||||
bool m_cull_all = false;
|
bool m_cull_all = false;
|
||||||
|
PrimitiveType m_current_primitive_type = PrimitiveType::Points;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_is_flushed = true;
|
bool m_is_flushed = true;
|
||||||
|
|
|
@ -229,6 +229,7 @@ struct VideoConfig final
|
||||||
// Utility
|
// Utility
|
||||||
bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; }
|
bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; }
|
||||||
bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; }
|
bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; }
|
||||||
|
bool MultisamplingEnabled() const { return iMultisamples > 1; }
|
||||||
bool ExclusiveFullscreenEnabled() const
|
bool ExclusiveFullscreenEnabled() const
|
||||||
{
|
{
|
||||||
return backend_info.bSupportsExclusiveFullscreen && !bBorderlessFullscreen;
|
return backend_info.bSupportsExclusiveFullscreen && !bBorderlessFullscreen;
|
||||||
|
|
Loading…
Reference in New Issue