summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon
diff options
context:
space:
mode:
authorMarkus Wick <degasus@users.noreply.github.com>2017-09-11 13:28:09 +0200
committerGitHub <noreply@github.com>2017-09-11 13:28:09 +0200
commit002e01d0ede3bd0eeebebc09f8f6a813ebc8d444 (patch)
tree5fb17c3d07988499767c51908b49dac2d8d9c881 /Source/Core/VideoCommon
parent9d169449a7898cefab29a5e033f82560cfcdef5e (diff)
parent24ddea04ce3c843dd1de3d34d775e9a49d195225 (diff)
Merge pull request #5343 from stenzek/videocommon-states
Move depth, rasterization and sampler states to VideoCommon
Diffstat (limited to 'Source/Core/VideoCommon')
-rw-r--r--Source/Core/VideoCommon/BPFunctions.cpp10
-rw-r--r--Source/Core/VideoCommon/GeometryShaderGen.cpp46
-rw-r--r--Source/Core/VideoCommon/GeometryShaderGen.h3
-rw-r--r--Source/Core/VideoCommon/RenderBase.h6
-rw-r--r--Source/Core/VideoCommon/RenderState.cpp133
-rw-r--r--Source/Core/VideoCommon/RenderState.h88
-rw-r--r--Source/Core/VideoCommon/VertexManagerBase.cpp100
-rw-r--r--Source/Core/VideoCommon/VertexManagerBase.h12
-rw-r--r--Source/Core/VideoCommon/VideoConfig.h1
9 files changed, 348 insertions, 51 deletions
diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp
index b74b6f84d4..a937a9037e 100644
--- a/Source/Core/VideoCommon/BPFunctions.cpp
+++ b/Source/Core/VideoCommon/BPFunctions.cpp
@@ -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()
@@ -68,12 +70,14 @@ void SetScissor()
void SetDepthMode()
{
- g_renderer->SetDepthMode();
+ DepthState state = {};
+ state.Generate(bpmem);
+ g_renderer->SetDepthState(state);
}
void SetBlendMode()
{
- BlendingState state;
+ BlendingState state = {};
state.Generate(bpmem);
g_renderer->SetBlendingState(state);
}
diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp
index 4b06c0f7f3..98335386fa 100644
--- a/Source/Core/VideoCommon/GeometryShaderGen.cpp
+++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp
@@ -14,24 +14,24 @@
#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 >= static_cast<u32>(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>();
memset(uid_data, 0, sizeof(geometry_shader_uid_data));
- uid_data->primitive_type = primitive_type;
+ uid_data->primitive_type = static_cast<u32>(primitive_type);
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
return out;
@@ -56,8 +56,10 @@ 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 PrimitiveType primitive_type = static_cast<PrimitiveType>(uid_data->primitive_type);
+ const unsigned primitive_type_index = static_cast<unsigned>(uid_data->primitive_type);
+ const unsigned vertex_in = std::min(static_cast<unsigned>(primitive_type_index) + 1, 3u);
+ unsigned vertex_out = primitive_type == PrimitiveType::TriangleStrip ? 3 : 4;
if (wireframe)
vertex_out++;
@@ -67,14 +69,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 +135,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 (primitive_type == PrimitiveType::Lines)
{
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{
@@ -178,7 +178,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
"\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n"
"\t}\n");
}
- else if (uid_data->primitive_type == PRIMITIVE_POINTS)
+ else if (primitive_type == PrimitiveType::Points)
{
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{
@@ -248,7 +248,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
out.Write("\tf.pos.x += hoffset * (f.pos.w - " I_STEREOPARAMS ".z);\n");
}
- if (uid_data->primitive_type == PRIMITIVE_LINES)
+ if (primitive_type == PrimitiveType::Lines)
{
out.Write("\tVS_OUTPUT l = f;\n"
"\tVS_OUTPUT r = f;\n");
@@ -269,7 +269,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
EmitVertex(out, host_config, uid_data, "l", ApiType, wireframe, pixel_lighting, true);
EmitVertex(out, host_config, uid_data, "r", ApiType, wireframe, pixel_lighting);
}
- else if (uid_data->primitive_type == PRIMITIVE_POINTS)
+ else if (primitive_type == PrimitiveType::Points)
{
out.Write("\tVS_OUTPUT ll = f;\n"
"\tVS_OUTPUT lr = f;\n"
@@ -370,12 +370,14 @@ 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;
+ guid->primitive_type = static_cast<u32>(primitive);
for (u32 texgens = 0; texgens <= 8; texgens++)
{
diff --git a/Source/Core/VideoCommon/GeometryShaderGen.h b/Source/Core/VideoCommon/GeometryShaderGen.h
index f138207e14..ace05baca7 100644
--- a/Source/Core/VideoCommon/GeometryShaderGen.h
+++ b/Source/Core/VideoCommon/GeometryShaderGen.h
@@ -6,6 +6,7 @@
#include <functional>
#include "Common/CommonTypes.h"
+#include "VideoCommon/RenderState.h"
#include "VideoCommon/ShaderGenCommon.h"
#include "VideoCommon/VertexManagerBase.h"
@@ -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);
diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h
index 7b7f43b7f6..1c6bc44171 100644
--- a/Source/Core/VideoCommon/RenderBase.h
+++ b/Source/Core/VideoCommon/RenderBase.h
@@ -66,9 +66,9 @@ public:
virtual void SetBlendingState(const BlendingState& state) {}
virtual void SetScissorRect(const EFBRectangle& rc) {}
- virtual void SetGenerationMode() {}
- virtual void SetDepthMode() {}
- virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {}
+ virtual void SetRasterizationState(const RasterizationState& state) {}
+ virtual void SetDepthState(const DepthState& state) {}
+ virtual void SetSamplerState(u32 index, const SamplerState& state) {}
virtual void SetInterlacingMode() {}
virtual void SetViewport() {}
virtual void SetFullscreen(bool enable_fullscreen) {}
diff --git a/Source/Core/VideoCommon/RenderState.cpp b/Source/Core/VideoCommon/RenderState.cpp
index 7e6d845ccb..8f8d421730 100644
--- a/Source/Core/VideoCommon/RenderState.cpp
+++ b/Source/Core/VideoCommon/RenderState.cpp
@@ -3,6 +3,38 @@
// Refer to the license.txt file included.
#include "VideoCommon/RenderState.h"
+#include <algorithm>
+#include <array>
+#include "VideoCommon/SamplerCommon.h"
+
+void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_type)
+{
+ cullmode = bp.genMode.cullmode;
+ primitive = primitive_type;
+
+ // Back-face culling should be disabled for points/lines.
+ if (primitive_type != PrimitiveType::Triangles && primitive_type != PrimitiveType::TriangleStrip)
+ cullmode = GenMode::CULL_NONE;
+}
+
+RasterizationState& RasterizationState::operator=(const RasterizationState& rhs)
+{
+ hex = rhs.hex;
+ return *this;
+}
+
+void DepthState::Generate(const BPMemory& bp)
+{
+ testenable = bp.zmode.testenable.Value();
+ updateenable = bp.zmode.updateenable.Value();
+ func = bp.zmode.func.Value();
+}
+
+DepthState& DepthState::operator=(const DepthState& rhs)
+{
+ hex = rhs.hex;
+ return *this;
+}
// If the framebuffer format has no alpha channel, it is assumed to
// ONE on blending. As the backends may emulate this framebuffer
@@ -127,3 +159,104 @@ void BlendingState::Generate(const BPMemory& bp)
}
}
}
+
+BlendingState& BlendingState::operator=(const BlendingState& rhs)
+{
+ hex = rhs.hex;
+ return *this;
+}
+
+void SamplerState::Generate(const BPMemory& bp, u32 index)
+{
+ const FourTexUnits& tex = bpmem.tex[index / 4];
+ const TexMode0& tm0 = tex.texMode0[index % 4];
+ const TexMode1& tm1 = tex.texMode1[index % 4];
+
+ // GX can configure the mip filter to none. However, D3D and Vulkan can't express this in their
+ // sampler states. Therefore, we set the min/max LOD to zero if this option is used.
+ min_filter = (tm0.min_filter & 4) != 0 ? Filter::Linear : Filter::Point;
+ mipmap_filter = (tm0.min_filter & 3) == TexMode0::TEXF_LINEAR ? Filter::Linear : Filter::Point;
+ mag_filter = tm0.mag_filter != 0 ? Filter::Linear : Filter::Point;
+
+ // If mipmaps are disabled, clamp min/max lod
+ max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod : 0;
+ min_lod = std::min(max_lod.Value(), tm1.min_lod);
+ lod_bias = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm0.lod_bias : 0;
+
+ // Address modes
+ static constexpr std::array<AddressMode, 4> address_modes = {
+ {AddressMode::Clamp, AddressMode::Repeat, AddressMode::MirroredRepeat, AddressMode::Repeat}};
+ wrap_u = address_modes[tm0.wrap_s];
+ wrap_v = address_modes[tm0.wrap_t];
+ anisotropic_filtering = 0;
+}
+
+SamplerState& SamplerState::operator=(const SamplerState& rhs)
+{
+ hex = rhs.hex;
+ return *this;
+}
+
+namespace RenderState
+{
+RasterizationState GetNoCullRasterizationState()
+{
+ RasterizationState state = {};
+ state.cullmode = GenMode::CULL_NONE;
+ return state;
+}
+
+DepthState GetNoDepthTestingDepthStencilState()
+{
+ DepthState state = {};
+ state.testenable = false;
+ state.updateenable = false;
+ state.func = ZMode::ALWAYS;
+ return state;
+}
+
+BlendingState GetNoBlendingBlendState()
+{
+ BlendingState state = {};
+ state.usedualsrc = false;
+ state.blendenable = false;
+ state.srcfactor = BlendMode::ONE;
+ state.srcfactoralpha = BlendMode::ONE;
+ state.dstfactor = BlendMode::ZERO;
+ state.dstfactoralpha = BlendMode::ZERO;
+ state.logicopenable = false;
+ state.colorupdate = true;
+ state.alphaupdate = true;
+ return state;
+}
+
+SamplerState GetPointSamplerState()
+{
+ SamplerState state = {};
+ state.min_filter = SamplerState::Filter::Point;
+ state.mag_filter = SamplerState::Filter::Point;
+ state.mipmap_filter = SamplerState::Filter::Point;
+ state.wrap_u = SamplerState::AddressMode::Clamp;
+ state.wrap_v = SamplerState::AddressMode::Clamp;
+ state.min_lod = 0;
+ state.max_lod = 255;
+ state.lod_bias = 0;
+ state.anisotropic_filtering = false;
+ return state;
+}
+
+SamplerState GetLinearSamplerState()
+{
+ SamplerState state = {};
+ state.min_filter = SamplerState::Filter::Linear;
+ state.mag_filter = SamplerState::Filter::Linear;
+ state.mipmap_filter = SamplerState::Filter::Linear;
+ state.wrap_u = SamplerState::AddressMode::Clamp;
+ state.wrap_v = SamplerState::AddressMode::Clamp;
+ state.min_lod = 0;
+ state.max_lod = 255;
+ state.lod_bias = 0;
+ state.anisotropic_filtering = false;
+ return state;
+}
+}
diff --git a/Source/Core/VideoCommon/RenderState.h b/Source/Core/VideoCommon/RenderState.h
index 25a55ba17a..76482b6bb9 100644
--- a/Source/Core/VideoCommon/RenderState.h
+++ b/Source/Core/VideoCommon/RenderState.h
@@ -9,10 +9,54 @@
#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);
+
+ RasterizationState& operator=(const RasterizationState& rhs);
+
+ bool operator==(const RasterizationState& rhs) const { return hex == rhs.hex; }
+ bool operator!=(const RasterizationState& rhs) const { return hex != rhs.hex; }
+ bool operator<(const RasterizationState& rhs) const { return hex < rhs.hex; }
+ BitField<0, 2, GenMode::CullMode> cullmode;
+ BitField<3, 2, PrimitiveType> primitive;
+
+ u32 hex;
+};
+
+union DepthState
+{
+ void Generate(const BPMemory& bp);
+
+ DepthState& operator=(const DepthState& rhs);
+
+ bool operator==(const DepthState& rhs) const { return hex == rhs.hex; }
+ bool operator!=(const DepthState& rhs) const { return hex != rhs.hex; }
+ bool operator<(const DepthState& rhs) const { return hex < rhs.hex; }
+ BitField<0, 1, u32> testenable;
+ BitField<1, 1, u32> updateenable;
+ BitField<2, 3, ZMode::CompareMode> func;
+
+ u32 hex;
+};
+
union BlendingState
{
void Generate(const BPMemory& bp);
+ BlendingState& operator=(const BlendingState& rhs);
+
+ bool operator==(const BlendingState& rhs) const { return hex == rhs.hex; }
+ bool operator!=(const BlendingState& rhs) const { return hex != rhs.hex; }
+ bool operator<(const BlendingState& rhs) const { return hex < rhs.hex; }
BitField<0, 1, u32> blendenable;
BitField<1, 1, u32> logicopenable;
BitField<2, 1, u32> dstalpha;
@@ -29,3 +73,47 @@ union BlendingState
u32 hex;
};
+
+union SamplerState
+{
+ enum class Filter : u32
+ {
+ Point,
+ Linear
+ };
+
+ enum class AddressMode : u32
+ {
+ Clamp,
+ Repeat,
+ MirroredRepeat
+ };
+
+ void Generate(const BPMemory& bp, u32 index);
+
+ SamplerState& operator=(const SamplerState& rhs);
+
+ bool operator==(const SamplerState& rhs) const { return hex == rhs.hex; }
+ bool operator!=(const SamplerState& rhs) const { return hex != rhs.hex; }
+ bool operator<(const SamplerState& rhs) const { return hex < rhs.hex; }
+ BitField<0, 1, Filter> min_filter;
+ BitField<1, 1, Filter> mag_filter;
+ BitField<2, 1, Filter> mipmap_filter;
+ BitField<3, 2, AddressMode> wrap_u;
+ BitField<5, 2, AddressMode> wrap_v;
+ BitField<7, 8, u32> min_lod; // multiplied by 16
+ BitField<15, 8, u32> max_lod; // multiplied by 16
+ BitField<23, 8, s32> lod_bias; // multiplied by 32
+ BitField<31, 1, u32> anisotropic_filtering;
+
+ u32 hex;
+};
+
+namespace RenderState
+{
+RasterizationState GetNoCullRasterizationState();
+DepthState GetNoDepthTestingDepthStencilState();
+BlendingState GetNoBlendingBlendState();
+SamplerState GetPointSamplerState();
+SamplerState GetLinearSamplerState();
+}
diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp
index 7807cdb98c..9138b0db09 100644
--- a/Source/Core/VideoCommon/VertexManagerBase.cpp
+++ b/Source/Core/VideoCommon/VertexManagerBase.cpp
@@ -4,6 +4,7 @@
#include "VideoCommon/VertexManagerBase.h"
+#include <array>
#include <cmath>
#include <memory>
@@ -23,6 +24,7 @@
#include "VideoCommon/PerfQueryBase.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/RenderBase.h"
+#include "VideoCommon/SamplerCommon.h"
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexShaderManager.h"
@@ -32,15 +34,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 +95,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 &&
@@ -184,6 +209,52 @@ std::pair<size_t, size_t> VertexManagerBase::ResetFlushAspectRatioCount()
return val;
}
+static void SetSamplerState(u32 index, bool custom_tex)
+{
+ const FourTexUnits& tex = bpmem.tex[index / 4];
+ const TexMode0& tm0 = tex.texMode0[index % 4];
+
+ SamplerState state = {};
+ state.Generate(bpmem, index);
+
+ // Force texture filtering config option.
+ if (g_ActiveConfig.bForceFiltering)
+ {
+ state.min_filter = SamplerState::Filter::Linear;
+ state.mag_filter = SamplerState::Filter::Linear;
+ state.mipmap_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ?
+ SamplerState::Filter::Linear :
+ SamplerState::Filter::Point;
+ }
+
+ // Custom textures may have a greater number of mips
+ if (custom_tex)
+ state.max_lod = 255;
+
+ // Anisotropic filtering option.
+ if (g_ActiveConfig.iMaxAnisotropy != 0 && !SamplerCommon::IsBpTexMode0PointFiltering(tm0))
+ {
+ // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
+ // For predictable results on all hardware/drivers, only use one of:
+ // GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear])
+ // GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear])
+ // Letting the game set other combinations will have varying arbitrary results;
+ // possibly being interpreted as equal to bilinear/trilinear, implicitly
+ // disabling anisotropy, or changing the anisotropic algorithm employed.
+ state.min_filter = SamplerState::Filter::Linear;
+ state.mag_filter = SamplerState::Filter::Linear;
+ if (SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0))
+ state.mipmap_filter = SamplerState::Filter::Linear;
+ state.anisotropic_filtering = 1;
+ }
+ else
+ {
+ state.anisotropic_filtering = 0;
+ }
+
+ g_renderer->SetSamplerState(index, state);
+}
+
void VertexManagerBase::Flush()
{
if (m_is_flushed)
@@ -252,7 +323,7 @@ void VertexManagerBase::Flush()
if (tentry)
{
- g_renderer->SetSamplerState(i & 3, i >> 2, tentry->is_custom_tex);
+ SetSamplerState(i, tentry->is_custom_tex);
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height);
}
else
@@ -332,8 +403,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;
diff --git a/Source/Core/VideoCommon/VertexManagerBase.h b/Source/Core/VideoCommon/VertexManagerBase.h
index dae639a47d..22c9b0d2a6 100644
--- a/Source/Core/VideoCommon/VertexManagerBase.h
+++ b/Source/Core/VideoCommon/VertexManagerBase.h
@@ -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;
diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h
index e9fcece3e8..9fbe78d5c5 100644
--- a/Source/Core/VideoCommon/VideoConfig.h
+++ b/Source/Core/VideoCommon/VideoConfig.h
@@ -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;