Renderer: Move cull mode to a rasterization state object

Also moves logic for primitive handling to VideoCommon.
This commit is contained in:
Stenzek 2017-04-30 18:07:57 +10:00
parent 2869c570f1
commit 836b9b9acb
38 changed files with 389 additions and 450 deletions

View File

@ -434,25 +434,27 @@ 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;
} }
@ -531,4 +533,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

View File

@ -20,13 +20,6 @@ struct ID3D11RasterizerState;
namespace DX11 namespace DX11
{ {
union RasterizerState
{
BitField<0, 2, D3D11_CULL_MODE> cull_mode;
u32 packed;
};
union SamplerState union SamplerState
{ {
BitField<0, 3, u64> min_filter; BitField<0, 3, u64> min_filter;
@ -48,12 +41,15 @@ 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(DepthState 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;

View File

@ -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)

View File

@ -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();

View File

@ -61,7 +61,7 @@ struct GXPipelineState
std::array<SamplerState, 8> samplers; std::array<SamplerState, 8> samplers;
BlendingState blend; BlendingState blend;
DepthState zmode; DepthState zmode;
RasterizerState raster; RasterizationState raster;
}; };
static u32 s_last_multisamples = 1; static u32 s_last_multisamples = 1;
@ -254,8 +254,7 @@ Renderer::Renderer() : ::Renderer(D3D::GetBackBufferWidth(), D3D::GetBackBufferH
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,6 +866,8 @@ 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 (size_t stage = 0; stage < s_gx_state.samplers.size(); stage++)
@ -891,29 +892,9 @@ 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()
{
D3D::stateman->PopRasterizerState();
}
void Renderer::SetGenerationMode()
{
constexpr std::array<D3D11_CULL_MODE, 4> d3d_cull_modes{{
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::SetDepthState(const DepthState& state) void Renderer::SetDepthState(const DepthState& state)

View File

@ -21,7 +21,7 @@ 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 SetDepthState(const DepthState& state) override; void SetDepthState(const DepthState& state) override;
void SetSamplerState(int stage, int texindex, bool custom_tex) override; void SetSamplerState(int stage, int texindex, bool custom_tex) override;
void SetInterlacingMode() override; void SetInterlacingMode() 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;

View File

@ -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()

View File

@ -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);

View File

@ -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();
} }

View File

@ -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));
@ -1295,7 +1297,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 +1305,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.

View File

@ -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;

View File

@ -1785,7 +1785,7 @@ 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();
BPFunctions::SetDepthMode(); BPFunctions::SetDepthMode();
BPFunctions::SetBlendMode(); BPFunctions::SetBlendMode();
@ -1798,14 +1798,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
{ {

View File

@ -79,7 +79,7 @@ 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 SetDepthState(const DepthState& state) override; void SetDepthState(const DepthState& state) override;
void SetSamplerState(int stage, int texindex, bool custom_tex) override; void SetSamplerState(int stage, int texindex, bool custom_tex) override;
void SetInterlacingMode() override; void SetInterlacingMode() override;

View File

@ -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()

View File

@ -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.

View File

@ -124,15 +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;
}; };
// Sampler info // Sampler info

View File

@ -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);
@ -338,8 +368,8 @@ bool FramebufferManager::CreateEFBFramebuffer()
// 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);
@ -438,16 +468,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 +484,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 +493,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 +504,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 +524,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 +542,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 +672,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 +711,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 +735,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 +791,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 +818,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 +931,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,10 +1134,18 @@ 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) // GPU will expand the point to a quad.
float cs_x = float(x) * 2.0f / EFB_WIDTH - 1.0f;
float cs_y = float(y) * 2.0f / EFB_HEIGHT - 1.0f;
float point_size = GetEFBWidth() / static_cast<float>(EFB_WIDTH);
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 x1 = float(x) * 2.0f / EFB_WIDTH - 1.0f;
float y1 = float(y) * 2.0f / EFB_HEIGHT - 1.0f; float y1 = float(y) * 2.0f / EFB_HEIGHT - 1.0f;
float x2 = float(x + 1) * 2.0f / EFB_WIDTH - 1.0f; float x2 = float(x + 1) * 2.0f / EFB_WIDTH - 1.0f;
@ -1122,15 +1156,6 @@ void FramebufferManager::CreatePokeVertices(std::vector<EFBPokeVertex>* destinat
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, y1, z, 1.0f}, color});
destination_list->push_back({{x2, y2, z, 1.0f}, color}); destination_list->push_back({{x2, y2, z, 1.0f}, color});
}
else
{
// GPU will expand the point to a quad.
float cs_x = float(x) * 2.0f / EFB_WIDTH - 1.0f;
float cs_y = float(y) * 2.0f / EFB_HEIGHT - 1.0f;
float point_size = m_efb_width / static_cast<float>(EFB_WIDTH);
destination_list->push_back({{cs_x, cs_y, z, point_size}, color});
}
} }
void FramebufferManager::FlushEFBPokes() void FramebufferManager::FlushEFBPokes()
@ -1159,16 +1184,16 @@ 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 = Util::GetNoCullRasterizationState().hex;
pipeline_info.rasterization_state.samples = m_efb_samples; pipeline_info.rasterization_state.primitive = m_poke_primitive;
pipeline_info.multisampling_state.hex = GetEFBMultisamplingState().hex;
pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex; pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex;
pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex; pipeline_info.blend_state.hex = Util::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_state.testenable = true; pipeline_info.depth_state.testenable = true;
@ -1209,7 +1234,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 +1335,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);

View File

@ -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;

View File

@ -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;

View File

@ -464,10 +464,6 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
depth_state.updateenable = z_enable; depth_state.updateenable = z_enable;
depth_state.func = ZMode::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(),
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD),
@ -475,7 +471,7 @@ 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.SetDepthState(depth_state); draw.SetDepthState(depth_state);
draw.SetBlendState(blend_state); draw.SetBlendState(blend_state);
@ -1227,13 +1223,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,31 +1267,9 @@ 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::SetDepthState(const DepthState& state) void Renderer::SetDepthState(const DepthState& state)

View File

@ -58,7 +58,7 @@ 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 SetDepthState(const DepthState& state) override; void SetDepthState(const DepthState& state) override;
void SetSamplerState(int stage, int texindex, bool custom_tex) override; void SetSamplerState(int stage, int texindex, bool custom_tex) override;
void SetInterlacingMode() override; void SetInterlacingMode() override;

View File

@ -89,14 +89,20 @@ 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
@ -107,14 +113,15 @@ GetVulkanRasterizationState(const RasterizationState& state)
} }
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
state.per_sample_shading, // VkBool32 sampleShadingEnable
1.0f, // float minSampleShading 1.0f, // float minSampleShading
nullptr, // const VkSampleMask* pSampleMask; nullptr, // const VkSampleMask* pSampleMask;
VK_FALSE, // VkBool32 alphaToCoverageEnable VK_FALSE, // VkBool32 alphaToCoverageEnable
@ -261,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,
@ -275,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;
} }
@ -315,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 =
@ -1203,23 +1210,11 @@ 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 = Util::GetNoCullRasterizationState().hex;
pinfo.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits; pinfo.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex;
pinfo.blend_state.hex = Util::GetNoBlendingBlendState().hex; pinfo.blend_state.hex = Util::GetNoBlendingBlendState().hex;
switch (guid.GetUidData()->primitive_type) pinfo.multisampling_state.hex = FramebufferManager::GetInstance()->GetEFBMultisamplingState().hex;
{ pinfo.rasterization_state.primitive = guid.GetUidData()->primitive_type;
case PRIMITIVE_POINTS:
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);
} }

View File

@ -50,7 +50,7 @@ struct PipelineInfo
BlendingState blend_state; BlendingState blend_state;
RasterizationState rasterization_state; RasterizationState rasterization_state;
DepthState depth_state; DepthState depth_state;
VkPrimitiveTopology primitive_topology; MultisamplingState multisampling_state;
}; };
struct PipelineInfoHash struct PipelineInfoHash

View File

@ -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_state.testenable = true;
m_pipeline_state.depth_state.updateenable = true;
m_pipeline_state.depth_state.func = ZMode::ALWAYS;
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_state_bits = info.depth_state.hex; 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_state.hex = uid.depth_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,30 +267,21 @@ 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;
}
void StateTracker::SetMultisamplingstate(const MultisamplingState& state)
{
if (m_pipeline_state.multisampling_state.hex == state.hex)
return;
m_pipeline_state.multisampling_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;

View File

@ -45,20 +45,15 @@ public:
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 SetMultisamplingstate(const MultisamplingState& state);
void SetDepthState(const DepthState& 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();
@ -133,7 +128,6 @@ private:
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.

View File

@ -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();
} }

View File

@ -188,10 +188,7 @@ VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor)
RasterizationState GetNoCullRasterizationState() RasterizationState GetNoCullRasterizationState()
{ {
RasterizationState state = {}; RasterizationState state = {};
state.cull_mode = VK_CULL_MODE_NONE; state.cullmode = GenMode::CULL_NONE;
state.samples = VK_SAMPLE_COUNT_1_BIT;
state.per_sample_shading = VK_FALSE;
state.depth_clamp = VK_FALSE;
return state; return state;
} }
@ -335,7 +332,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 +342,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 = Util::GetNoCullRasterizationState().hex;
m_pipeline_info.rasterization_state.primitive = primitive;
m_pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex; m_pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex;
m_pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex; m_pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex;
m_pipeline_info.primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 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 +369,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,7 +443,12 @@ 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::SetMultisamplingState(const MultisamplingState& state)
{
m_pipeline_info.multisampling_state.hex = state.hex;
} }
void UtilityShaderDraw::SetDepthState(const DepthState& state) void UtilityShaderDraw::SetDepthState(const DepthState& state)
@ -506,7 +507,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 +536,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 +563,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 +572,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())

View File

@ -131,12 +131,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,6 +152,7 @@ public:
void SetPSTexelBuffer(VkBufferView view); void SetPSTexelBuffer(VkBufferView view);
void SetRasterizationState(const RasterizationState& state); void SetRasterizationState(const RasterizationState& state);
void SetMultisamplingState(const MultisamplingState& state);
void SetDepthState(const DepthState& state); void SetDepthState(const DepthState& state);
void SetBlendState(const BlendingState& state); void SetBlendState(const BlendingState& state);
@ -177,7 +179,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();

View File

@ -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();

View File

@ -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()

View File

@ -14,18 +14,18 @@
#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 >= 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>();
@ -56,8 +56,9 @@ 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 unsigned primitive_type_index = static_cast<unsigned>(uid_data->primitive_type);
unsigned int vertex_out = uid_data->primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4; const unsigned vertex_in = std::min(static_cast<unsigned>(primitive_type_index) + 1, 3u);
unsigned vertex_out = uid_data->primitive_type == PrimitiveType::TriangleStrip ? 3 : 4;
if (wireframe) if (wireframe)
vertex_out++; vertex_out++;
@ -67,14 +68,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 +134,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 (uid_data->primitive_type == PrimitiveType::Lines)
{ {
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{ {
@ -178,7 +177,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 (uid_data->primitive_type == PrimitiveType::Points)
{ {
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{ {
@ -248,7 +247,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 (uid_data->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 +268,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 (uid_data->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,9 +369,11 @@ 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 = primitive;

View File

@ -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"
@ -19,7 +20,7 @@ struct geometry_shader_uid_data
bool IsPassthrough() const; bool IsPassthrough() const;
u32 numTexGens : 4; u32 numTexGens : 4;
u32 primitive_type : 2; PrimitiveType primitive_type : 2;
}; };
#pragma pack() #pragma pack()
@ -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);

View File

@ -66,7 +66,7 @@ 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 SetDepthState(const DepthState& state) {} virtual void SetDepthState(const DepthState& state) {}
virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {} virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {}
virtual void SetInterlacingMode() {} virtual void SetInterlacingMode() {}

View File

@ -4,6 +4,16 @@
#include "VideoCommon/RenderState.h" #include "VideoCommon/RenderState.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;
}
void DepthState::Generate(const BPMemory& bp) void DepthState::Generate(const BPMemory& bp)
{ {
testenable = bp.zmode.testenable.Value(); testenable = bp.zmode.testenable.Value();

View File

@ -9,6 +9,24 @@
#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);
BitField<0, 2, GenMode::CullMode> cullmode;
BitField<3, 2, PrimitiveType> primitive;
u32 hex;
};
union DepthState union DepthState
{ {
void Generate(const BPMemory& bp); void Generate(const BPMemory& bp);

View File

@ -4,6 +4,7 @@
#include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexManagerBase.h"
#include <array>
#include <cmath> #include <cmath>
#include <memory> #include <memory>
@ -32,15 +33,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 +94,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 &&
@ -332,8 +356,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;

View File

@ -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;

View File

@ -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;