summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/RenderState.cpp
blob: 344ec5b32ab1a74a9596582307ed30484abcf5f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "VideoCommon/RenderState.h"

void DepthState::Generate(const BPMemory& bp)
{
  testenable = bp.zmode.testenable.Value();
  updateenable = bp.zmode.updateenable.Value();
  func = bp.zmode.func.Value();
}

// If the framebuffer format has no alpha channel, it is assumed to
// ONE on blending. As the backends may emulate this framebuffer
// configuration with an alpha channel, we just drop all references
// to the destination alpha channel.
static BlendMode::BlendFactor RemoveDstAlphaUsage(BlendMode::BlendFactor factor)
{
  switch (factor)
  {
  case BlendMode::DSTALPHA:
    return BlendMode::ONE;
  case BlendMode::INVDSTALPHA:
    return BlendMode::ZERO;
  default:
    return factor;
  }
}

// We separate the blending parameter for rgb and alpha. For blending
// the alpha component, CLR and ALPHA are indentical. So just always
// use ALPHA as this makes it easier for the backends to use the second
// alpha value of dual source blending.
static BlendMode::BlendFactor RemoveSrcColorUsage(BlendMode::BlendFactor factor)
{
  switch (factor)
  {
  case BlendMode::SRCCLR:
    return BlendMode::SRCALPHA;
  case BlendMode::INVSRCCLR:
    return BlendMode::INVSRCALPHA;
  default:
    return factor;
  }
}

// Same as RemoveSrcColorUsage, but because of the overlapping enum,
// this must be written as another function.
static BlendMode::BlendFactor RemoveDstColorUsage(BlendMode::BlendFactor factor)
{
  switch (factor)
  {
  case BlendMode::DSTCLR:
    return BlendMode::DSTALPHA;
  case BlendMode::INVDSTCLR:
    return BlendMode::INVDSTALPHA;
  default:
    return factor;
  }
}

void BlendingState::Generate(const BPMemory& bp)
{
  // Start with everything disabled.
  hex = 0;

  bool target_has_alpha = bp.zcontrol.pixel_format == PEControl::RGBA6_Z24;
  bool alpha_test_may_success = bp.alpha_test.TestResult() != AlphaTest::FAIL;

  colorupdate = bp.blendmode.colorupdate && alpha_test_may_success;
  alphaupdate = bp.blendmode.alphaupdate && target_has_alpha && alpha_test_may_success;
  dstalpha = bp.dstalpha.enable && alphaupdate;
  usedualsrc = true;

  // The subtract bit has the highest priority
  if (bp.blendmode.subtract)
  {
    blendenable = true;
    subtractAlpha = subtract = true;
    srcfactoralpha = srcfactor = BlendMode::ONE;
    dstfactoralpha = dstfactor = BlendMode::ONE;

    if (dstalpha)
    {
      subtractAlpha = false;
      srcfactoralpha = BlendMode::ONE;
      dstfactoralpha = BlendMode::ZERO;
    }
  }

  // The blendenable bit has the middle priority
  else if (bp.blendmode.blendenable)
  {
    blendenable = true;
    srcfactor = bp.blendmode.srcfactor;
    dstfactor = bp.blendmode.dstfactor;
    if (!target_has_alpha)
    {
      // uses ONE instead of DSTALPHA
      srcfactor = RemoveDstAlphaUsage(srcfactor);
      dstfactor = RemoveDstAlphaUsage(dstfactor);
    }
    // replaces SRCCLR with SRCALPHA and DSTCLR with DSTALPHA, it is important to
    // use the dst function for the src factor and vice versa
    srcfactoralpha = RemoveDstColorUsage(srcfactor);
    dstfactoralpha = RemoveSrcColorUsage(dstfactor);

    if (dstalpha)
    {
      srcfactoralpha = BlendMode::ONE;
      dstfactoralpha = BlendMode::ZERO;
    }
  }

  // The logicop bit has the lowest priority
  else if (bp.blendmode.logicopenable)
  {
    if (bp.blendmode.logicmode == BlendMode::NOOP)
    {
      // Fast path for Kirby's Return to Dreamland, they use it with dstAlpha.
      colorupdate = false;
      alphaupdate = alphaupdate && dstalpha;
    }
    else
    {
      logicopenable = true;
      logicmode = bp.blendmode.logicmode;

      if (dstalpha)
      {
        // TODO: Not supported by backends.
      }
    }
  }
}