From 365236fa4c96eaba94b715b6844bff64238b70e5 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Fri, 2 Jan 2015 20:37:25 +0100 Subject: Pica: Cleanup clipping code and change screenspace z to range from -1..0. The change in depth range seems to reflect better to what applications are expecting, and makes for cleaner code overall (hence is more likely to reflect hardware behavior). --- src/video_core/rasterizer.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 3faa10153..046c010ef 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -106,16 +106,17 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, ScreenToRasterizerCoordinates(v1.screenpos), ScreenToRasterizerCoordinates(v2.screenpos) }; - if (registers.cull_mode == Regs::CullMode::KeepClockWise) { - // Reverse vertex order and use the CCW code path. + if (registers.cull_mode == Regs::CullMode::KeepCounterClockWise) { + // Reverse vertex order and use the CW code path. std::swap(vtxpos[1], vtxpos[2]); } if (registers.cull_mode != Regs::CullMode::KeepAll) { - // Cull away triangles which are wound clockwise. - // TODO: A check for degenerate triangles ("== 0") should be considered for CullMode::KeepAll + // Cull away triangles which are wound counter-clockwise. if (SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) return; + } else { + // TODO: Consider A check for degenerate triangles ("SignedArea == 0") } // TODO: Proper scissor rect test! @@ -475,7 +476,7 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, // TODO: Does depth indeed only get written even if depth testing is enabled? if (registers.output_merger.depth_test_enable) { - u16 z = (u16)(-(v0.screenpos[2].ToFloat32() * w0 + + u16 z = (u16)((v0.screenpos[2].ToFloat32() * w0 + v1.screenpos[2].ToFloat32() * w1 + v2.screenpos[2].ToFloat32() * w2) * 65535.f / wsum); u16 ref_z = GetDepth(x >> 4, y >> 4); -- cgit v1.2.3 From 638b370fb5a9dff1296e6c60c02ac68911ae666a Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Wed, 18 Feb 2015 13:14:49 +0100 Subject: Pica/Rasterizer: Clean up and fix backface culling. --- src/video_core/rasterizer.cpp | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 046c010ef..5769bd81e 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -90,9 +90,14 @@ static int SignedArea (const Math::Vec2& vtx1, return Math::Cross(vec1, vec2).z; }; -void ProcessTriangle(const VertexShader::OutputVertex& v0, - const VertexShader::OutputVertex& v1, - const VertexShader::OutputVertex& v2) +/** + * Helper function for ProcessTriangle with the "reversed" flag to allow for implementing + * culling via recursion. + */ +static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, + const VertexShader::OutputVertex& v1, + const VertexShader::OutputVertex& v2, + bool reversed = false) { // vertex positions in rasterizer coordinates auto FloatToFix = [](float24 flt) { @@ -106,17 +111,22 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, ScreenToRasterizerCoordinates(v1.screenpos), ScreenToRasterizerCoordinates(v2.screenpos) }; - if (registers.cull_mode == Regs::CullMode::KeepCounterClockWise) { - // Reverse vertex order and use the CW code path. - std::swap(vtxpos[1], vtxpos[2]); - } + if (registers.cull_mode == Regs::CullMode::KeepAll) { + // Make sure we always end up with a triangle wound counter-clockwise + if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) { + ProcessTriangleInternal(v0, v2, v1, true); + return; + } + } else { + if (!reversed && registers.cull_mode == Regs::CullMode::KeepClockWise) { + // Reverse vertex order and use the CCW code path. + ProcessTriangleInternal(v0, v2, v1, true); + return; + } - if (registers.cull_mode != Regs::CullMode::KeepAll) { - // Cull away triangles which are wound counter-clockwise. + // Cull away triangles which are wound clockwise. if (SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) return; - } else { - // TODO: Consider A check for degenerate triangles ("SignedArea == 0") } // TODO: Proper scissor rect test! @@ -695,6 +705,12 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, } } +void ProcessTriangle(const VertexShader::OutputVertex& v0, + const VertexShader::OutputVertex& v1, + const VertexShader::OutputVertex& v2) { + ProcessTriangleInternal(v0, v1, v2); +} + } // namespace Rasterizer } // namespace Pica -- cgit v1.2.3 From 3cb22d31a71ce1f0103b075cfc2533aaebff9ace Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Fri, 2 Jan 2015 01:01:06 +0100 Subject: Pica/Rasterizer: Fix garbage pixels at triangle borders. --- src/video_core/rasterizer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 5769bd81e..74182abef 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -101,7 +101,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, { // vertex positions in rasterizer coordinates auto FloatToFix = [](float24 flt) { - return Fix12P4(static_cast(flt.ToFloat32() * 16.0f)); + // TODO: Rounding here is necessary to prevent garbage pixels at + // triangle borders. Is it that the correct solution, though? + return Fix12P4(static_cast(round(flt.ToFloat32() * 16.0f))); }; auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3 vec) { return Math::Vec3{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)}; -- cgit v1.2.3 From 3b5710bae662dbd20b54736362c6f72888b9009e Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Fri, 2 Jan 2015 01:02:18 +0100 Subject: Pica/Rasterizer: Rasterize actual pixel centers instead of pixel corners. --- src/video_core/rasterizer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 74182abef..168a2ada0 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -168,9 +168,10 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, auto textures = registers.GetTextures(); auto tev_stages = registers.GetTevStages(); + // Enter rasterization loop, starting at the center of the topleft bounding box corner. // TODO: Not sure if looping through x first might be faster - for (u16 y = min_y; y < max_y; y += 0x10) { - for (u16 x = min_x; x < max_x; x += 0x10) { + for (u16 y = min_y + 8; y < max_y; y += 0x10) { + for (u16 x = min_x + 8; x < max_x; x += 0x10) { // Calculate the barycentric coordinates w0, w1 and w2 int w0 = bias0 + SignedArea(vtxpos[1].xy(), vtxpos[2].xy(), {x, y}); -- cgit v1.2.3 From aaf30ca4ee7cb539722a2928a578a579641987a1 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Fri, 2 Jan 2015 15:26:50 +0100 Subject: Pica/OutputMerger: Implement color format checking. --- src/video_core/rasterizer.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 168a2ada0..27eeb531d 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -20,10 +20,19 @@ namespace Rasterizer { static void DrawPixel(int x, int y, const Math::Vec4& color) { const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); u32* color_buffer = reinterpret_cast(Memory::GetPointer(PAddrToVAddr(addr))); - u32 value = (color.a() << 24) | (color.r() << 16) | (color.g() << 8) | color.b(); - // Assuming RGBA8 format until actual framebuffer format handling is implemented - *(color_buffer + x + y * registers.framebuffer.GetWidth()) = value; + switch (registers.framebuffer.color_format) { + case registers.framebuffer.RGBA8: + { + u32 value = (color.a() << 24) | (color.r() << 16) | (color.g() << 8) | color.b(); + *(color_buffer + x + y * registers.framebuffer.GetWidth()) = value; + break; + } + + default: + LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format); + exit(1); + } } static const Math::Vec4 GetPixel(int x, int y) { -- cgit v1.2.3 From 8bd7a896ea82b5b2f4ff7f2ec50624ff6ec45431 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Thu, 1 Jan 2015 19:59:11 +0100 Subject: Pica: Fix a bug in the register definitions, relating to texture wrapping. --- src/video_core/rasterizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 27eeb531d..65dddb47c 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -243,7 +243,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, int s = (int)(uv[i].u() * float24::FromFloat32(static_cast(texture.config.width))).ToFloat32(); int t = (int)(uv[i].v() * float24::FromFloat32(static_cast(texture.config.height))).ToFloat32(); - auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val, unsigned size) { + static auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val, unsigned size) { switch (mode) { case Regs::TextureConfig::ClampToEdge: val = std::max(val, 0); -- cgit v1.2.3 From 6ca752ccbc7c59dab66f476ca02d3b53527c57da Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 3 Jan 2015 13:33:57 +0100 Subject: Pica/TextureUnit: Implement mirrored repeating texture wrapping. --- src/video_core/rasterizer.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 65dddb47c..f788122d8 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -251,7 +251,15 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, return val; case Regs::TextureConfig::Repeat: - return (int)(((unsigned)val) % size); + return (int)((unsigned)val % size); + + case Regs::TextureConfig::MirroredRepeat: + { + int val = (int)((unsigned)val % (2 * size)); + if (val >= size) + val = 2 * size - 1 - val; + return val; + } default: LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x\n", (int)mode); -- cgit v1.2.3 From 087edcfbec86ba730d55c4fdbbf65097a8cfb8e4 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 3 Jan 2015 13:37:05 +0100 Subject: Pica/OutputMerger: Fix flipped framebuffers. --- src/video_core/rasterizer.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index f788122d8..9cad5f9b6 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -21,6 +21,10 @@ static void DrawPixel(int x, int y, const Math::Vec4& color) { const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); u32* color_buffer = reinterpret_cast(Memory::GetPointer(PAddrToVAddr(addr))); + // Similarly to textures, the render framebuffer is laid out from bottom to top, too. + // NOTE: The framebuffer height register contains the actual FB height minus one. + y = (registers.framebuffer.height - y); + switch (registers.framebuffer.color_format) { case registers.framebuffer.RGBA8: { @@ -39,6 +43,8 @@ static const Math::Vec4 GetPixel(int x, int y) { const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); u32* color_buffer_u32 = reinterpret_cast(Memory::GetPointer(PAddrToVAddr(addr))); + y = (registers.framebuffer.height - y); + u32 value = *(color_buffer_u32 + x + y * registers.framebuffer.GetWidth()); Math::Vec4 ret; ret.a() = value >> 24; @@ -52,6 +58,8 @@ static u32 GetDepth(int x, int y) { const PAddr addr = registers.framebuffer.GetDepthBufferPhysicalAddress(); u16* depth_buffer = reinterpret_cast(Memory::GetPointer(PAddrToVAddr(addr))); + y = (registers.framebuffer.height - y); + // Assuming 16-bit depth buffer format until actual format handling is implemented return *(depth_buffer + x + y * registers.framebuffer.GetWidth()); } @@ -60,6 +68,8 @@ static void SetDepth(int x, int y, u16 value) { const PAddr addr = registers.framebuffer.GetDepthBufferPhysicalAddress(); u16* depth_buffer = reinterpret_cast(Memory::GetPointer(PAddrToVAddr(addr))); + y = (registers.framebuffer.height - y); + // Assuming 16-bit depth buffer format until actual format handling is implemented *(depth_buffer + x + y * registers.framebuffer.GetWidth()) = value; } -- cgit v1.2.3 From 04cd06d5c285848c29278083891474ee78797c8a Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 3 Jan 2015 13:45:10 +0100 Subject: Pica/TextureEnvironment: Add support for the MAD-like texture combiners and clean up texture environment logic. --- src/video_core/rasterizer.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 9cad5f9b6..eacca82e5 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -419,6 +419,25 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, return result.Cast(); } + case Operation::MultiplyThenAdd: + { + auto result = (input[0] * input[1] + 255 * input[2].Cast()) / 255; + result.r() = std::min(255, result.r()); + result.g() = std::min(255, result.g()); + result.b() = std::min(255, result.b()); + return result.Cast(); + } + + case Operation::AddThenMultiply: + { + auto result = input[0] + input[1]; + result.r() = std::min(255, result.r()); + result.g() = std::min(255, result.g()); + result.b() = std::min(255, result.b()); + result = (result * input[2].Cast()) / 255; + return result.Cast(); + } + default: LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op); UNIMPLEMENTED(); @@ -443,6 +462,12 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, case Operation::Subtract: return std::max(0, (int)input[0] - (int)input[1]); + case Operation::MultiplyThenAdd: + return std::min(255, (input[0] * input[1] + 255 * input[2]) / 255); + + case Operation::AddThenMultiply: + return (std::min(255, (input[0] + input[1])) * input[2]) / 255; + default: LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d\n", (int)op); UNIMPLEMENTED(); -- cgit v1.2.3 From e11fb96408b27e2aa76e29a380fe3a2d15d37d32 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 3 Jan 2015 13:49:53 +0100 Subject: Pica/TextureEnvironment: Treat texture combiner source 1 as the PrimaryColor. Not really sure where the difference is, but some applications seem to use this 1:1 the same way... --- src/video_core/rasterizer.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index eacca82e5..4bf7593ce 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -303,7 +303,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, auto GetSource = [&](Source source) -> Math::Vec4 { switch (source) { + // TODO: What's the difference between these two? case Source::PrimaryColor: + case Source::PrimaryFragmentColor: return primary_color; case Source::Texture0: -- cgit v1.2.3 From 81ebb4d682a1c2f452d96bd5545251a8fd856def Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 3 Jan 2015 13:51:51 +0100 Subject: Pica/TextureEnvironment: Add a note. --- src/video_core/rasterizer.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 4bf7593ce..b7a7e62ab 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -277,6 +277,10 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, return 0; } }; + + // Textures are laid out from bottom to top, hence we invert the t coordinate. + // NOTE: This may not be the right place for the inversion. + // TODO: Check if this applies to ETC textures, too. s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width); t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height); -- cgit v1.2.3 From 156120434251d0ae726442206f8b5b41338d700d Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Wed, 11 Feb 2015 21:39:43 +0100 Subject: Pica/BlendUnit: Implement separate color/alpha blend equations. --- src/video_core/rasterizer.cpp | 122 ++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 64 deletions(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index b7a7e62ab..f96015de4 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -5,6 +5,7 @@ #include #include "common/common_types.h" +#include "common/math_util.h" #include "math.h" #include "pica.h" @@ -596,6 +597,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, } auto dest = GetPixel(x >> 4, y >> 4); + Math::Vec4 blend_output = combiner_output; if (registers.output_merger.alphablend_enable) { auto params = registers.output_merger.alpha_blending; @@ -684,81 +686,73 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, } }; + using BlendEquation = decltype(params)::BlendEquation; + static auto EvaluateBlendEquation = [](const Math::Vec4& src, const Math::Vec4& srcfactor, + const Math::Vec4& dest, const Math::Vec4& destfactor, + BlendEquation equation) { + Math::Vec4 result; + + auto src_result = (src * srcfactor).Cast(); + auto dst_result = (dest * destfactor).Cast(); + + switch (equation) { + case BlendEquation::Add: + result = (src_result + dst_result) / 255; + break; + + case BlendEquation::Subtract: + result = (src_result - dst_result) / 255; + break; + + case BlendEquation::ReverseSubtract: + result = (dst_result - src_result) / 255; + break; + + // TODO: How do these two actually work? + // OpenGL doesn't include the blend factors in the min/max computations, + // but is this what the 3DS actually does? + case BlendEquation::Min: + result.r() = std::min(src.r(), dest.r()); + result.g() = std::min(src.g(), dest.g()); + result.b() = std::min(src.b(), dest.b()); + result.a() = std::min(src.a(), dest.a()); + break; + + case BlendEquation::Max: + result.r() = std::max(src.r(), dest.r()); + result.g() = std::max(src.g(), dest.g()); + result.b() = std::max(src.b(), dest.b()); + result.a() = std::max(src.a(), dest.a()); + break; + + default: + LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", equation); + exit(0); + } + + return Math::Vec4(MathUtil::Clamp(result.r(), 0, 255), + MathUtil::Clamp(result.g(), 0, 255), + MathUtil::Clamp(result.b(), 0, 255), + MathUtil::Clamp(result.a(), 0, 255)); + }; + auto srcfactor = Math::MakeVec(LookupFactorRGB(params.factor_source_rgb), LookupFactorA(params.factor_source_a)); auto dstfactor = Math::MakeVec(LookupFactorRGB(params.factor_dest_rgb), LookupFactorA(params.factor_dest_a)); - - auto src_result = (combiner_output * srcfactor).Cast(); - auto dst_result = (dest * dstfactor).Cast(); - - switch (params.blend_equation_rgb) { - case params.Add: - { - auto result = (src_result + dst_result) / 255; - result.r() = std::min(255, result.r()); - result.g() = std::min(255, result.g()); - result.b() = std::min(255, result.b()); - combiner_output = result.Cast(); - break; - } - - case params.Subtract: - { - auto result = (src_result - dst_result) / 255; - result.r() = std::max(0, result.r()); - result.g() = std::max(0, result.g()); - result.b() = std::max(0, result.b()); - combiner_output = result.Cast(); - break; - } - - case params.ReverseSubtract: - { - auto result = (dst_result - src_result) / 255; - result.r() = std::max(0, result.r()); - result.g() = std::max(0, result.g()); - result.b() = std::max(0, result.b()); - combiner_output = result.Cast(); - break; - } - - case params.Min: - { - // TODO: GL spec says to do it without the factors, but is this what the 3DS does? - Math::Vec4 result; - result.r() = std::min(combiner_output.r(),dest.r()); - result.g() = std::min(combiner_output.g(),dest.g()); - result.b() = std::min(combiner_output.b(),dest.b()); - combiner_output = result.Cast(); - break; - } - - case params.Max: - { - // TODO: GL spec says to do it without the factors, but is this what the 3DS does? - Math::Vec4 result; - result.r() = std::max(combiner_output.r(),dest.r()); - result.g() = std::max(combiner_output.g(),dest.g()); - result.b() = std::max(combiner_output.b(),dest.b()); - combiner_output = result.Cast(); - break; - } - default: - LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", params.blend_equation_rgb.Value()); - exit(0); - } + blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); + blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); } else { LOG_CRITICAL(HW_GPU, "logic op: %x", registers.output_merger.logic_op); exit(0); } const Math::Vec4 result = { - registers.output_merger.red_enable ? combiner_output.r() : dest.r(), - registers.output_merger.green_enable ? combiner_output.g() : dest.g(), - registers.output_merger.blue_enable ? combiner_output.b() : dest.b(), - registers.output_merger.alpha_enable ? combiner_output.a() : dest.a() + registers.output_merger.red_enable ? blend_output.r() : dest.r(), + registers.output_merger.green_enable ? blend_output.g() : dest.g(), + registers.output_merger.blue_enable ? blend_output.b() : dest.b(), + registers.output_merger.alpha_enable ? blend_output.a() : dest.a() }; DrawPixel(x >> 4, y >> 4, result); -- cgit v1.2.3 From 6e5a903286a50b84e417d1bfda7ef07108354ae3 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Wed, 18 Feb 2015 12:14:40 +0100 Subject: Pica/Rasterizer: Make some local lambdas static. --- src/video_core/rasterizer.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index f96015de4..a3712f116 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -120,14 +120,14 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, bool reversed = false) { // vertex positions in rasterizer coordinates - auto FloatToFix = [](float24 flt) { - // TODO: Rounding here is necessary to prevent garbage pixels at - // triangle borders. Is it that the correct solution, though? - return Fix12P4(static_cast(round(flt.ToFloat32() * 16.0f))); - }; - auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3 vec) { - return Math::Vec3{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)}; - }; + static auto FloatToFix = [](float24 flt) { + // TODO: Rounding here is necessary to prevent garbage pixels at + // triangle borders. Is it that the correct solution, though? + return Fix12P4(static_cast(round(flt.ToFloat32() * 16.0f))); + }; + static auto ScreenToRasterizerCoordinates = [](const Math::Vec3& vec) { + return Math::Vec3{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)}; + }; Math::Vec3 vtxpos[3]{ ScreenToRasterizerCoordinates(v0.screenpos), ScreenToRasterizerCoordinates(v1.screenpos), -- cgit v1.2.3 From 2eee3a87f915a8d18482cdd15e6bfd823467ea13 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Wed, 18 Feb 2015 13:50:25 +0100 Subject: Pica/Rasterizer: Replace exit() calls with UNIMPLEMENTED(). --- src/video_core/rasterizer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index a3712f116..94873f406 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -36,7 +36,7 @@ static void DrawPixel(int x, int y, const Math::Vec4& color) { default: LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format); - exit(1); + UNIMPLEMENTED(); } } @@ -648,7 +648,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, default: LOG_CRITICAL(HW_GPU, "Unknown color blend factor %x", factor); - exit(0); + UNIMPLEMENTED(); break; } }; @@ -681,7 +681,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, default: LOG_CRITICAL(HW_GPU, "Unknown alpha blend factor %x", factor); - exit(0); + UNIMPLEMENTED(); break; } }; @@ -727,7 +727,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, default: LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", equation); - exit(0); + UNIMPLEMENTED(); } return Math::Vec4(MathUtil::Clamp(result.r(), 0, 255), @@ -745,7 +745,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); } else { LOG_CRITICAL(HW_GPU, "logic op: %x", registers.output_merger.logic_op); - exit(0); + UNIMPLEMENTED(); } const Math::Vec4 result = { -- cgit v1.2.3