diff options
| author | 2015-02-11 21:39:43 +0100 | |
|---|---|---|
| committer | 2015-02-18 14:50:28 +0100 | |
| commit | 156120434251d0ae726442206f8b5b41338d700d (patch) | |
| tree | b61426e3aa93a56c80283037172fbf61dc45f7a0 /src/video_core/rasterizer.cpp | |
| parent | Pica/TextureEnvironment: Add a note. (diff) | |
| download | yuzu-156120434251d0ae726442206f8b5b41338d700d.tar.gz yuzu-156120434251d0ae726442206f8b5b41338d700d.tar.xz yuzu-156120434251d0ae726442206f8b5b41338d700d.zip | |
Pica/BlendUnit: Implement separate color/alpha blend equations.
Diffstat (limited to 'src/video_core/rasterizer.cpp')
| -rw-r--r-- | src/video_core/rasterizer.cpp | 122 |
1 files changed, 58 insertions, 64 deletions
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 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/math_util.h" | ||
| 8 | 9 | ||
| 9 | #include "math.h" | 10 | #include "math.h" |
| 10 | #include "pica.h" | 11 | #include "pica.h" |
| @@ -596,6 +597,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
| 596 | } | 597 | } |
| 597 | 598 | ||
| 598 | auto dest = GetPixel(x >> 4, y >> 4); | 599 | auto dest = GetPixel(x >> 4, y >> 4); |
| 600 | Math::Vec4<u8> blend_output = combiner_output; | ||
| 599 | 601 | ||
| 600 | if (registers.output_merger.alphablend_enable) { | 602 | if (registers.output_merger.alphablend_enable) { |
| 601 | auto params = registers.output_merger.alpha_blending; | 603 | auto params = registers.output_merger.alpha_blending; |
| @@ -684,81 +686,73 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
| 684 | } | 686 | } |
| 685 | }; | 687 | }; |
| 686 | 688 | ||
| 689 | using BlendEquation = decltype(params)::BlendEquation; | ||
| 690 | static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, | ||
| 691 | const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, | ||
| 692 | BlendEquation equation) { | ||
| 693 | Math::Vec4<int> result; | ||
| 694 | |||
| 695 | auto src_result = (src * srcfactor).Cast<int>(); | ||
| 696 | auto dst_result = (dest * destfactor).Cast<int>(); | ||
| 697 | |||
| 698 | switch (equation) { | ||
| 699 | case BlendEquation::Add: | ||
| 700 | result = (src_result + dst_result) / 255; | ||
| 701 | break; | ||
| 702 | |||
| 703 | case BlendEquation::Subtract: | ||
| 704 | result = (src_result - dst_result) / 255; | ||
| 705 | break; | ||
| 706 | |||
| 707 | case BlendEquation::ReverseSubtract: | ||
| 708 | result = (dst_result - src_result) / 255; | ||
| 709 | break; | ||
| 710 | |||
| 711 | // TODO: How do these two actually work? | ||
| 712 | // OpenGL doesn't include the blend factors in the min/max computations, | ||
| 713 | // but is this what the 3DS actually does? | ||
| 714 | case BlendEquation::Min: | ||
| 715 | result.r() = std::min(src.r(), dest.r()); | ||
| 716 | result.g() = std::min(src.g(), dest.g()); | ||
| 717 | result.b() = std::min(src.b(), dest.b()); | ||
| 718 | result.a() = std::min(src.a(), dest.a()); | ||
| 719 | break; | ||
| 720 | |||
| 721 | case BlendEquation::Max: | ||
| 722 | result.r() = std::max(src.r(), dest.r()); | ||
| 723 | result.g() = std::max(src.g(), dest.g()); | ||
| 724 | result.b() = std::max(src.b(), dest.b()); | ||
| 725 | result.a() = std::max(src.a(), dest.a()); | ||
| 726 | break; | ||
| 727 | |||
| 728 | default: | ||
| 729 | LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", equation); | ||
| 730 | exit(0); | ||
| 731 | } | ||
| 732 | |||
| 733 | return Math::Vec4<u8>(MathUtil::Clamp(result.r(), 0, 255), | ||
| 734 | MathUtil::Clamp(result.g(), 0, 255), | ||
| 735 | MathUtil::Clamp(result.b(), 0, 255), | ||
| 736 | MathUtil::Clamp(result.a(), 0, 255)); | ||
| 737 | }; | ||
| 738 | |||
| 687 | auto srcfactor = Math::MakeVec(LookupFactorRGB(params.factor_source_rgb), | 739 | auto srcfactor = Math::MakeVec(LookupFactorRGB(params.factor_source_rgb), |
| 688 | LookupFactorA(params.factor_source_a)); | 740 | LookupFactorA(params.factor_source_a)); |
| 689 | auto dstfactor = Math::MakeVec(LookupFactorRGB(params.factor_dest_rgb), | 741 | auto dstfactor = Math::MakeVec(LookupFactorRGB(params.factor_dest_rgb), |
| 690 | LookupFactorA(params.factor_dest_a)); | 742 | LookupFactorA(params.factor_dest_a)); |
| 691 | |||
| 692 | auto src_result = (combiner_output * srcfactor).Cast<int>(); | ||
| 693 | auto dst_result = (dest * dstfactor).Cast<int>(); | ||
| 694 | |||
| 695 | switch (params.blend_equation_rgb) { | ||
| 696 | case params.Add: | ||
| 697 | { | ||
| 698 | auto result = (src_result + dst_result) / 255; | ||
| 699 | result.r() = std::min(255, result.r()); | ||
| 700 | result.g() = std::min(255, result.g()); | ||
| 701 | result.b() = std::min(255, result.b()); | ||
| 702 | combiner_output = result.Cast<u8>(); | ||
| 703 | break; | ||
| 704 | } | ||
| 705 | |||
| 706 | case params.Subtract: | ||
| 707 | { | ||
| 708 | auto result = (src_result - dst_result) / 255; | ||
| 709 | result.r() = std::max(0, result.r()); | ||
| 710 | result.g() = std::max(0, result.g()); | ||
| 711 | result.b() = std::max(0, result.b()); | ||
| 712 | combiner_output = result.Cast<u8>(); | ||
| 713 | break; | ||
| 714 | } | ||
| 715 | |||
| 716 | case params.ReverseSubtract: | ||
| 717 | { | ||
| 718 | auto result = (dst_result - src_result) / 255; | ||
| 719 | result.r() = std::max(0, result.r()); | ||
| 720 | result.g() = std::max(0, result.g()); | ||
| 721 | result.b() = std::max(0, result.b()); | ||
| 722 | combiner_output = result.Cast<u8>(); | ||
| 723 | break; | ||
| 724 | } | ||
| 725 | |||
| 726 | case params.Min: | ||
| 727 | { | ||
| 728 | // TODO: GL spec says to do it without the factors, but is this what the 3DS does? | ||
| 729 | Math::Vec4<int> result; | ||
| 730 | result.r() = std::min(combiner_output.r(),dest.r()); | ||
| 731 | result.g() = std::min(combiner_output.g(),dest.g()); | ||
| 732 | result.b() = std::min(combiner_output.b(),dest.b()); | ||
| 733 | combiner_output = result.Cast<u8>(); | ||
| 734 | break; | ||
| 735 | } | ||
| 736 | |||
| 737 | case params.Max: | ||
| 738 | { | ||
| 739 | // TODO: GL spec says to do it without the factors, but is this what the 3DS does? | ||
| 740 | Math::Vec4<int> result; | ||
| 741 | result.r() = std::max(combiner_output.r(),dest.r()); | ||
| 742 | result.g() = std::max(combiner_output.g(),dest.g()); | ||
| 743 | result.b() = std::max(combiner_output.b(),dest.b()); | ||
| 744 | combiner_output = result.Cast<u8>(); | ||
| 745 | break; | ||
| 746 | } | ||
| 747 | 743 | ||
| 748 | default: | 744 | blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); |
| 749 | LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", params.blend_equation_rgb.Value()); | 745 | blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); |
| 750 | exit(0); | ||
| 751 | } | ||
| 752 | } else { | 746 | } else { |
| 753 | LOG_CRITICAL(HW_GPU, "logic op: %x", registers.output_merger.logic_op); | 747 | LOG_CRITICAL(HW_GPU, "logic op: %x", registers.output_merger.logic_op); |
| 754 | exit(0); | 748 | exit(0); |
| 755 | } | 749 | } |
| 756 | 750 | ||
| 757 | const Math::Vec4<u8> result = { | 751 | const Math::Vec4<u8> result = { |
| 758 | registers.output_merger.red_enable ? combiner_output.r() : dest.r(), | 752 | registers.output_merger.red_enable ? blend_output.r() : dest.r(), |
| 759 | registers.output_merger.green_enable ? combiner_output.g() : dest.g(), | 753 | registers.output_merger.green_enable ? blend_output.g() : dest.g(), |
| 760 | registers.output_merger.blue_enable ? combiner_output.b() : dest.b(), | 754 | registers.output_merger.blue_enable ? blend_output.b() : dest.b(), |
| 761 | registers.output_merger.alpha_enable ? combiner_output.a() : dest.a() | 755 | registers.output_merger.alpha_enable ? blend_output.a() : dest.a() |
| 762 | }; | 756 | }; |
| 763 | 757 | ||
| 764 | DrawPixel(x >> 4, y >> 4, result); | 758 | DrawPixel(x >> 4, y >> 4, result); |