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

@ -27,7 +27,9 @@ void FlushPipeline()
void SetGenerationMode()
{
g_renderer->SetGenerationMode();
RasterizationState state = {};
state.Generate(bpmem, g_vertex_manager->GetCurrentPrimitiveType());
g_renderer->SetRasterizationState(state);
}
void SetScissor()

View File

@ -14,18 +14,18 @@
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
static const char* primitives_ogl[] = {"points", "lines", "triangles"};
static const char* primitives_d3d[] = {"point", "line", "triangle"};
constexpr std::array<const char*, 4> primitives_ogl = {
{"points", "lines", "triangles", "triangles"}};
constexpr std::array<const char*, 4> primitives_d3d = {{"point", "line", "triangle", "triangle"}};
bool geometry_shader_uid_data::IsPassthrough() const
{
const bool stereo = g_ActiveConfig.iStereoMode > 0;
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;
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 ssaa = host_config.ssaa;
const bool stereo = host_config.stereo;
const unsigned int vertex_in = uid_data->primitive_type + 1;
unsigned int vertex_out = uid_data->primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4;
const unsigned primitive_type_index = static_cast<unsigned>(uid_data->primitive_type);
const unsigned vertex_in = std::min(static_cast<unsigned>(primitive_type_index) + 1, 3u);
unsigned vertex_out = uid_data->primitive_type == PrimitiveType::TriangleStrip ? 3 : 4;
if (wireframe)
vertex_out++;
@ -67,14 +68,14 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
// Insert layout parameters
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);
out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle",
vertex_out);
}
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",
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("void main(%s VS_OUTPUT o[%d], inout %sStream<VertexData> output, in uint "
"InstanceID : SV_GSInstanceID)\n{\n",
primitives_d3d[uid_data->primitive_type], vertex_in,
wireframe ? "Line" : "Triangle");
primitives_d3d[primitive_type_index], vertex_in, wireframe ? "Line" : "Triangle");
}
else
{
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",
primitives_d3d[uid_data->primitive_type], vertex_in,
wireframe ? "Line" : "Triangle");
primitives_d3d[primitive_type_index], vertex_in, wireframe ? "Line" : "Triangle");
}
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)
{
@ -178,7 +177,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
"\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\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)
{
@ -248,7 +247,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
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"
"\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, "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"
"\tVS_OUTPUT lr = f;\n"
@ -370,9 +369,11 @@ void EnumerateGeometryShaderUids(const std::function<void(const GeometryShaderUi
GeometryShaderUid uid;
std::memset(&uid, 0, sizeof(uid));
static constexpr std::array<u32, 3> primitive_lut = {
{PRIMITIVE_TRIANGLES, PRIMITIVE_LINES, PRIMITIVE_POINTS}};
for (u32 primitive : primitive_lut)
const std::array<PrimitiveType, 3> primitive_lut = {
{g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? PrimitiveType::TriangleStrip :
PrimitiveType::Triangles,
PrimitiveType::Lines, PrimitiveType::Points}};
for (PrimitiveType primitive : primitive_lut)
{
auto* guid = uid.GetUidData<geometry_shader_uid_data>();
guid->primitive_type = primitive;

View File

@ -6,6 +6,7 @@
#include <functional>
#include "Common/CommonTypes.h"
#include "VideoCommon/RenderState.h"
#include "VideoCommon/ShaderGenCommon.h"
#include "VideoCommon/VertexManagerBase.h"
@ -19,7 +20,7 @@ struct geometry_shader_uid_data
bool IsPassthrough() const;
u32 numTexGens : 4;
u32 primitive_type : 2;
PrimitiveType primitive_type : 2;
};
#pragma pack()
@ -28,5 +29,5 @@ typedef ShaderUid<geometry_shader_uid_data> GeometryShaderUid;
ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& host_config,
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);

View File

@ -66,7 +66,7 @@ public:
virtual void SetBlendingState(const BlendingState& state) {}
virtual void SetScissorRect(const EFBRectangle& rc) {}
virtual void SetGenerationMode() {}
virtual void SetRasterizationState(const RasterizationState& state) {}
virtual void SetDepthState(const DepthState& state) {}
virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {}
virtual void SetInterlacingMode() {}

View File

@ -4,6 +4,16 @@
#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)
{
testenable = bp.zmode.testenable.Value();

View File

@ -9,6 +9,24 @@
#include "VideoCommon/BPMemory.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
{
void Generate(const BPMemory& bp);

View File

@ -4,6 +4,7 @@
#include "VideoCommon/VertexManagerBase.h"
#include <array>
#include <cmath>
#include <memory>
@ -32,15 +33,28 @@
std::unique_ptr<VertexManagerBase> g_vertex_manager;
static const PrimitiveType primitive_from_gx[8] = {
PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS
PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS_2
PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLES
PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLE_STRIP
PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLE_FAN
PRIMITIVE_LINES, // GX_DRAW_LINES
PRIMITIVE_LINES, // GX_DRAW_LINE_STRIP
PRIMITIVE_POINTS, // GX_DRAW_POINTS
// GX primitive -> RenderState primitive, no primitive restart
constexpr std::array<PrimitiveType, 8> primitive_from_gx = {
PrimitiveType::Triangles, // GX_DRAW_QUADS
PrimitiveType::Triangles, // GX_DRAW_QUADS_2
PrimitiveType::Triangles, // GX_DRAW_TRIANGLES
PrimitiveType::Triangles, // GX_DRAW_TRIANGLE_STRIP
PrimitiveType::Triangles, // GX_DRAW_TRIANGLE_FAN
PrimitiveType::Lines, // GX_DRAW_LINES
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
@ -80,9 +94,19 @@ DataReader VertexManagerBase::PrepareForAdditionalData(int primitive, u32 count,
u32 const needed_vertex_bytes = count * stride + 4;
// 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();
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()
if (!m_is_flushed &&
@ -332,8 +356,11 @@ void VertexManagerBase::CalculateZSlope(NativeVertexFormat* format)
float viewOffset[2] = {xfmem.viewport.xOrig - bpmem.scissorOffset.x * 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;
}
// Global matrix ID.
u32 mtxIdx = g_main_cp_state.matrix_index_a.PosNormalMtxIdx;

View File

@ -9,19 +9,13 @@
#include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h"
#include "VideoCommon/RenderState.h"
class DataReader;
class NativeVertexFormat;
class PointerWrap;
struct PortableVertexDeclaration;
enum PrimitiveType
{
PRIMITIVE_POINTS,
PRIMITIVE_LINES,
PRIMITIVE_TRIANGLES,
};
struct Slope
{
float dfdx;
@ -51,6 +45,7 @@ public:
// needs to be virtual for DX11's dtor
virtual ~VertexManagerBase();
PrimitiveType GetCurrentPrimitiveType() const { return m_current_primitive_type; }
DataReader PrepareForAdditionalData(int primitive, u32 count, u32 stride, bool cullall);
void FlushData(u32 count, u32 stride);
@ -65,8 +60,6 @@ public:
protected:
virtual void vDoState(PointerWrap& p) {}
PrimitiveType m_current_primitive_type = PrimitiveType::PRIMITIVE_POINTS;
virtual void ResetBuffer(u32 stride) = 0;
u8* m_cur_buffer_pointer = nullptr;
@ -80,6 +73,7 @@ protected:
void CalculateZSlope(NativeVertexFormat* format);
bool m_cull_all = false;
PrimitiveType m_current_primitive_type = PrimitiveType::Points;
private:
bool m_is_flushed = true;

View File

@ -229,6 +229,7 @@ struct VideoConfig final
// Utility
bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; }
bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; }
bool MultisamplingEnabled() const { return iMultisamples > 1; }
bool ExclusiveFullscreenEnabled() const
{
return backend_info.bSupportsExclusiveFullscreen && !bBorderlessFullscreen;