diff options
| author | Markus Wick <degasus@users.noreply.github.com> | 2017-09-11 13:28:09 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-09-11 13:28:09 +0200 |
| commit | 002e01d0ede3bd0eeebebc09f8f6a813ebc8d444 (patch) | |
| tree | 5fb17c3d07988499767c51908b49dac2d8d9c881 /Source/Core/VideoCommon | |
| parent | 9d169449a7898cefab29a5e033f82560cfcdef5e (diff) | |
| parent | 24ddea04ce3c843dd1de3d34d775e9a49d195225 (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.cpp | 10 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/GeometryShaderGen.cpp | 46 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/GeometryShaderGen.h | 3 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/RenderBase.h | 6 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/RenderState.cpp | 133 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/RenderState.h | 88 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/VertexManagerBase.cpp | 100 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/VertexManagerBase.h | 12 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/VideoConfig.h | 1 |
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; |
