rasterizer.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include "common/common_types.h"
  6. #include "common/math_util.h"
  7. #include "math.h"
  8. #include "pica.h"
  9. #include "rasterizer.h"
  10. #include "vertex_shader.h"
  11. #include "debug_utils/debug_utils.h"
  12. namespace Pica {
  13. namespace Rasterizer {
  14. static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
  15. const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress();
  16. u32* color_buffer = reinterpret_cast<u32*>(Memory::GetPointer(PAddrToVAddr(addr)));
  17. // Similarly to textures, the render framebuffer is laid out from bottom to top, too.
  18. // NOTE: The framebuffer height register contains the actual FB height minus one.
  19. y = (registers.framebuffer.height - y);
  20. switch (registers.framebuffer.color_format) {
  21. case registers.framebuffer.RGBA8:
  22. {
  23. u32 value = (color.a() << 24) | (color.r() << 16) | (color.g() << 8) | color.b();
  24. *(color_buffer + x + y * registers.framebuffer.GetWidth()) = value;
  25. break;
  26. }
  27. default:
  28. LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format);
  29. exit(1);
  30. }
  31. }
  32. static const Math::Vec4<u8> GetPixel(int x, int y) {
  33. const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress();
  34. u32* color_buffer_u32 = reinterpret_cast<u32*>(Memory::GetPointer(PAddrToVAddr(addr)));
  35. y = (registers.framebuffer.height - y);
  36. u32 value = *(color_buffer_u32 + x + y * registers.framebuffer.GetWidth());
  37. Math::Vec4<u8> ret;
  38. ret.a() = value >> 24;
  39. ret.r() = (value >> 16) & 0xFF;
  40. ret.g() = (value >> 8) & 0xFF;
  41. ret.b() = value & 0xFF;
  42. return ret;
  43. }
  44. static u32 GetDepth(int x, int y) {
  45. const PAddr addr = registers.framebuffer.GetDepthBufferPhysicalAddress();
  46. u16* depth_buffer = reinterpret_cast<u16*>(Memory::GetPointer(PAddrToVAddr(addr)));
  47. y = (registers.framebuffer.height - y);
  48. // Assuming 16-bit depth buffer format until actual format handling is implemented
  49. return *(depth_buffer + x + y * registers.framebuffer.GetWidth());
  50. }
  51. static void SetDepth(int x, int y, u16 value) {
  52. const PAddr addr = registers.framebuffer.GetDepthBufferPhysicalAddress();
  53. u16* depth_buffer = reinterpret_cast<u16*>(Memory::GetPointer(PAddrToVAddr(addr)));
  54. y = (registers.framebuffer.height - y);
  55. // Assuming 16-bit depth buffer format until actual format handling is implemented
  56. *(depth_buffer + x + y * registers.framebuffer.GetWidth()) = value;
  57. }
  58. // NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values
  59. struct Fix12P4 {
  60. Fix12P4() {}
  61. Fix12P4(u16 val) : val(val) {}
  62. static u16 FracMask() { return 0xF; }
  63. static u16 IntMask() { return (u16)~0xF; }
  64. operator u16() const {
  65. return val;
  66. }
  67. bool operator < (const Fix12P4& oth) const {
  68. return (u16)*this < (u16)oth;
  69. }
  70. private:
  71. u16 val;
  72. };
  73. /**
  74. * Calculate signed area of the triangle spanned by the three argument vertices.
  75. * The sign denotes an orientation.
  76. *
  77. * @todo define orientation concretely.
  78. */
  79. static int SignedArea (const Math::Vec2<Fix12P4>& vtx1,
  80. const Math::Vec2<Fix12P4>& vtx2,
  81. const Math::Vec2<Fix12P4>& vtx3) {
  82. const auto vec1 = Math::MakeVec(vtx2 - vtx1, 0);
  83. const auto vec2 = Math::MakeVec(vtx3 - vtx1, 0);
  84. // TODO: There is a very small chance this will overflow for sizeof(int) == 4
  85. return Math::Cross(vec1, vec2).z;
  86. };
  87. /**
  88. * Helper function for ProcessTriangle with the "reversed" flag to allow for implementing
  89. * culling via recursion.
  90. */
  91. static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
  92. const VertexShader::OutputVertex& v1,
  93. const VertexShader::OutputVertex& v2,
  94. bool reversed = false)
  95. {
  96. // vertex positions in rasterizer coordinates
  97. auto FloatToFix = [](float24 flt) {
  98. // TODO: Rounding here is necessary to prevent garbage pixels at
  99. // triangle borders. Is it that the correct solution, though?
  100. return Fix12P4(static_cast<unsigned short>(round(flt.ToFloat32() * 16.0f)));
  101. };
  102. auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) {
  103. return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)};
  104. };
  105. Math::Vec3<Fix12P4> vtxpos[3]{ ScreenToRasterizerCoordinates(v0.screenpos),
  106. ScreenToRasterizerCoordinates(v1.screenpos),
  107. ScreenToRasterizerCoordinates(v2.screenpos) };
  108. if (registers.cull_mode == Regs::CullMode::KeepAll) {
  109. // Make sure we always end up with a triangle wound counter-clockwise
  110. if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) {
  111. ProcessTriangleInternal(v0, v2, v1, true);
  112. return;
  113. }
  114. } else {
  115. if (!reversed && registers.cull_mode == Regs::CullMode::KeepClockWise) {
  116. // Reverse vertex order and use the CCW code path.
  117. ProcessTriangleInternal(v0, v2, v1, true);
  118. return;
  119. }
  120. // Cull away triangles which are wound clockwise.
  121. if (SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0)
  122. return;
  123. }
  124. // TODO: Proper scissor rect test!
  125. u16 min_x = std::min({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x});
  126. u16 min_y = std::min({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y});
  127. u16 max_x = std::max({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x});
  128. u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y});
  129. min_x &= Fix12P4::IntMask();
  130. min_y &= Fix12P4::IntMask();
  131. max_x = ((max_x + Fix12P4::FracMask()) & Fix12P4::IntMask());
  132. max_y = ((max_y + Fix12P4::FracMask()) & Fix12P4::IntMask());
  133. // Triangle filling rules: Pixels on the right-sided edge or on flat bottom edges are not
  134. // drawn. Pixels on any other triangle border are drawn. This is implemented with three bias
  135. // values which are added to the barycentric coordinates w0, w1 and w2, respectively.
  136. // NOTE: These are the PSP filling rules. Not sure if the 3DS uses the same ones...
  137. auto IsRightSideOrFlatBottomEdge = [](const Math::Vec2<Fix12P4>& vtx,
  138. const Math::Vec2<Fix12P4>& line1,
  139. const Math::Vec2<Fix12P4>& line2)
  140. {
  141. if (line1.y == line2.y) {
  142. // just check if vertex is above us => bottom line parallel to x-axis
  143. return vtx.y < line1.y;
  144. } else {
  145. // check if vertex is on our left => right side
  146. // TODO: Not sure how likely this is to overflow
  147. return (int)vtx.x < (int)line1.x + ((int)line2.x - (int)line1.x) * ((int)vtx.y - (int)line1.y) / ((int)line2.y - (int)line1.y);
  148. }
  149. };
  150. int bias0 = IsRightSideOrFlatBottomEdge(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) ? -1 : 0;
  151. int bias1 = IsRightSideOrFlatBottomEdge(vtxpos[1].xy(), vtxpos[2].xy(), vtxpos[0].xy()) ? -1 : 0;
  152. int bias2 = IsRightSideOrFlatBottomEdge(vtxpos[2].xy(), vtxpos[0].xy(), vtxpos[1].xy()) ? -1 : 0;
  153. auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
  154. auto textures = registers.GetTextures();
  155. auto tev_stages = registers.GetTevStages();
  156. // Enter rasterization loop, starting at the center of the topleft bounding box corner.
  157. // TODO: Not sure if looping through x first might be faster
  158. for (u16 y = min_y + 8; y < max_y; y += 0x10) {
  159. for (u16 x = min_x + 8; x < max_x; x += 0x10) {
  160. // Calculate the barycentric coordinates w0, w1 and w2
  161. int w0 = bias0 + SignedArea(vtxpos[1].xy(), vtxpos[2].xy(), {x, y});
  162. int w1 = bias1 + SignedArea(vtxpos[2].xy(), vtxpos[0].xy(), {x, y});
  163. int w2 = bias2 + SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), {x, y});
  164. int wsum = w0 + w1 + w2;
  165. // If current pixel is not covered by the current primitive
  166. if (w0 < 0 || w1 < 0 || w2 < 0)
  167. continue;
  168. auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(static_cast<float>(w0)),
  169. float24::FromFloat32(static_cast<float>(w1)),
  170. float24::FromFloat32(static_cast<float>(w2)));
  171. float24 interpolated_w_inverse = float24::FromFloat32(1.0f) / Math::Dot(w_inverse, baricentric_coordinates);
  172. // Perspective correct attribute interpolation:
  173. // Attribute values cannot be calculated by simple linear interpolation since
  174. // they are not linear in screen space. For example, when interpolating a
  175. // texture coordinate across two vertices, something simple like
  176. // u = (u0*w0 + u1*w1)/(w0+w1)
  177. // will not work. However, the attribute value divided by the
  178. // clipspace w-coordinate (u/w) and and the inverse w-coordinate (1/w) are linear
  179. // in screenspace. Hence, we can linearly interpolate these two independently and
  180. // calculate the interpolated attribute by dividing the results.
  181. // I.e.
  182. // u_over_w = ((u0/v0.pos.w)*w0 + (u1/v1.pos.w)*w1)/(w0+w1)
  183. // one_over_w = (( 1/v0.pos.w)*w0 + ( 1/v1.pos.w)*w1)/(w0+w1)
  184. // u = u_over_w / one_over_w
  185. //
  186. // The generalization to three vertices is straightforward in baricentric coordinates.
  187. auto GetInterpolatedAttribute = [&](float24 attr0, float24 attr1, float24 attr2) {
  188. auto attr_over_w = Math::MakeVec(attr0, attr1, attr2);
  189. float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates);
  190. return interpolated_attr_over_w * interpolated_w_inverse;
  191. };
  192. Math::Vec4<u8> primary_color{
  193. (u8)(GetInterpolatedAttribute(v0.color.r(), v1.color.r(), v2.color.r()).ToFloat32() * 255),
  194. (u8)(GetInterpolatedAttribute(v0.color.g(), v1.color.g(), v2.color.g()).ToFloat32() * 255),
  195. (u8)(GetInterpolatedAttribute(v0.color.b(), v1.color.b(), v2.color.b()).ToFloat32() * 255),
  196. (u8)(GetInterpolatedAttribute(v0.color.a(), v1.color.a(), v2.color.a()).ToFloat32() * 255)
  197. };
  198. Math::Vec2<float24> uv[3];
  199. uv[0].u() = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u());
  200. uv[0].v() = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v());
  201. uv[1].u() = GetInterpolatedAttribute(v0.tc1.u(), v1.tc1.u(), v2.tc1.u());
  202. uv[1].v() = GetInterpolatedAttribute(v0.tc1.v(), v1.tc1.v(), v2.tc1.v());
  203. uv[2].u() = GetInterpolatedAttribute(v0.tc2.u(), v1.tc2.u(), v2.tc2.u());
  204. uv[2].v() = GetInterpolatedAttribute(v0.tc2.v(), v1.tc2.v(), v2.tc2.v());
  205. Math::Vec4<u8> texture_color[3]{};
  206. for (int i = 0; i < 3; ++i) {
  207. const auto& texture = textures[i];
  208. if (!texture.enabled)
  209. continue;
  210. DEBUG_ASSERT(0 != texture.config.address);
  211. int s = (int)(uv[i].u() * float24::FromFloat32(static_cast<float>(texture.config.width))).ToFloat32();
  212. int t = (int)(uv[i].v() * float24::FromFloat32(static_cast<float>(texture.config.height))).ToFloat32();
  213. static auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val, unsigned size) {
  214. switch (mode) {
  215. case Regs::TextureConfig::ClampToEdge:
  216. val = std::max(val, 0);
  217. val = std::min(val, (int)size - 1);
  218. return val;
  219. case Regs::TextureConfig::Repeat:
  220. return (int)((unsigned)val % size);
  221. case Regs::TextureConfig::MirroredRepeat:
  222. {
  223. int val = (int)((unsigned)val % (2 * size));
  224. if (val >= size)
  225. val = 2 * size - 1 - val;
  226. return val;
  227. }
  228. default:
  229. LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x\n", (int)mode);
  230. UNIMPLEMENTED();
  231. return 0;
  232. }
  233. };
  234. // Textures are laid out from bottom to top, hence we invert the t coordinate.
  235. // NOTE: This may not be the right place for the inversion.
  236. // TODO: Check if this applies to ETC textures, too.
  237. s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width);
  238. t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height);
  239. u8* texture_data = Memory::GetPointer(PAddrToVAddr(texture.config.GetPhysicalAddress()));
  240. auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format);
  241. texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info);
  242. DebugUtils::DumpTexture(texture.config, texture_data);
  243. }
  244. // Texture environment - consists of 6 stages of color and alpha combining.
  245. //
  246. // Color combiners take three input color values from some source (e.g. interpolated
  247. // vertex color, texture color, previous stage, etc), perform some very simple
  248. // operations on each of them (e.g. inversion) and then calculate the output color
  249. // with some basic arithmetic. Alpha combiners can be configured separately but work
  250. // analogously.
  251. Math::Vec4<u8> combiner_output;
  252. for (const auto& tev_stage : tev_stages) {
  253. using Source = Regs::TevStageConfig::Source;
  254. using ColorModifier = Regs::TevStageConfig::ColorModifier;
  255. using AlphaModifier = Regs::TevStageConfig::AlphaModifier;
  256. using Operation = Regs::TevStageConfig::Operation;
  257. auto GetSource = [&](Source source) -> Math::Vec4<u8> {
  258. switch (source) {
  259. // TODO: What's the difference between these two?
  260. case Source::PrimaryColor:
  261. case Source::PrimaryFragmentColor:
  262. return primary_color;
  263. case Source::Texture0:
  264. return texture_color[0];
  265. case Source::Texture1:
  266. return texture_color[1];
  267. case Source::Texture2:
  268. return texture_color[2];
  269. case Source::Constant:
  270. return {tev_stage.const_r, tev_stage.const_g, tev_stage.const_b, tev_stage.const_a};
  271. case Source::Previous:
  272. return combiner_output;
  273. default:
  274. LOG_ERROR(HW_GPU, "Unknown color combiner source %d\n", (int)source);
  275. UNIMPLEMENTED();
  276. return {};
  277. }
  278. };
  279. static auto GetColorModifier = [](ColorModifier factor, const Math::Vec4<u8>& values) -> Math::Vec3<u8> {
  280. switch (factor) {
  281. case ColorModifier::SourceColor:
  282. return values.rgb();
  283. case ColorModifier::OneMinusSourceColor:
  284. return (Math::Vec3<u8>(255, 255, 255) - values.rgb()).Cast<u8>();
  285. case ColorModifier::SourceAlpha:
  286. return values.aaa();
  287. case ColorModifier::OneMinusSourceAlpha:
  288. return (Math::Vec3<u8>(255, 255, 255) - values.aaa()).Cast<u8>();
  289. case ColorModifier::SourceRed:
  290. return values.rrr();
  291. case ColorModifier::OneMinusSourceRed:
  292. return (Math::Vec3<u8>(255, 255, 255) - values.rrr()).Cast<u8>();
  293. case ColorModifier::SourceGreen:
  294. return values.ggg();
  295. case ColorModifier::OneMinusSourceGreen:
  296. return (Math::Vec3<u8>(255, 255, 255) - values.ggg()).Cast<u8>();
  297. case ColorModifier::SourceBlue:
  298. return values.bbb();
  299. case ColorModifier::OneMinusSourceBlue:
  300. return (Math::Vec3<u8>(255, 255, 255) - values.bbb()).Cast<u8>();
  301. }
  302. };
  303. static auto GetAlphaModifier = [](AlphaModifier factor, const Math::Vec4<u8>& values) -> u8 {
  304. switch (factor) {
  305. case AlphaModifier::SourceAlpha:
  306. return values.a();
  307. case AlphaModifier::OneMinusSourceAlpha:
  308. return 255 - values.a();
  309. case AlphaModifier::SourceRed:
  310. return values.r();
  311. case AlphaModifier::OneMinusSourceRed:
  312. return 255 - values.r();
  313. case AlphaModifier::SourceGreen:
  314. return values.g();
  315. case AlphaModifier::OneMinusSourceGreen:
  316. return 255 - values.g();
  317. case AlphaModifier::SourceBlue:
  318. return values.b();
  319. case AlphaModifier::OneMinusSourceBlue:
  320. return 255 - values.b();
  321. }
  322. };
  323. static auto ColorCombine = [](Operation op, const Math::Vec3<u8> input[3]) -> Math::Vec3<u8> {
  324. switch (op) {
  325. case Operation::Replace:
  326. return input[0];
  327. case Operation::Modulate:
  328. return ((input[0] * input[1]) / 255).Cast<u8>();
  329. case Operation::Add:
  330. {
  331. auto result = input[0] + input[1];
  332. result.r() = std::min(255, result.r());
  333. result.g() = std::min(255, result.g());
  334. result.b() = std::min(255, result.b());
  335. return result.Cast<u8>();
  336. }
  337. case Operation::Lerp:
  338. return ((input[0] * input[2] + input[1] * (Math::MakeVec<u8>(255, 255, 255) - input[2]).Cast<u8>()) / 255).Cast<u8>();
  339. case Operation::Subtract:
  340. {
  341. auto result = input[0].Cast<int>() - input[1].Cast<int>();
  342. result.r() = std::max(0, result.r());
  343. result.g() = std::max(0, result.g());
  344. result.b() = std::max(0, result.b());
  345. return result.Cast<u8>();
  346. }
  347. case Operation::MultiplyThenAdd:
  348. {
  349. auto result = (input[0] * input[1] + 255 * input[2].Cast<int>()) / 255;
  350. result.r() = std::min(255, result.r());
  351. result.g() = std::min(255, result.g());
  352. result.b() = std::min(255, result.b());
  353. return result.Cast<u8>();
  354. }
  355. case Operation::AddThenMultiply:
  356. {
  357. auto result = input[0] + input[1];
  358. result.r() = std::min(255, result.r());
  359. result.g() = std::min(255, result.g());
  360. result.b() = std::min(255, result.b());
  361. result = (result * input[2].Cast<int>()) / 255;
  362. return result.Cast<u8>();
  363. }
  364. default:
  365. LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op);
  366. UNIMPLEMENTED();
  367. return {};
  368. }
  369. };
  370. static auto AlphaCombine = [](Operation op, const std::array<u8,3>& input) -> u8 {
  371. switch (op) {
  372. case Operation::Replace:
  373. return input[0];
  374. case Operation::Modulate:
  375. return input[0] * input[1] / 255;
  376. case Operation::Add:
  377. return std::min(255, input[0] + input[1]);
  378. case Operation::Lerp:
  379. return (input[0] * input[2] + input[1] * (255 - input[2])) / 255;
  380. case Operation::Subtract:
  381. return std::max(0, (int)input[0] - (int)input[1]);
  382. case Operation::MultiplyThenAdd:
  383. return std::min(255, (input[0] * input[1] + 255 * input[2]) / 255);
  384. case Operation::AddThenMultiply:
  385. return (std::min(255, (input[0] + input[1])) * input[2]) / 255;
  386. default:
  387. LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d\n", (int)op);
  388. UNIMPLEMENTED();
  389. return 0;
  390. }
  391. };
  392. // color combiner
  393. // NOTE: Not sure if the alpha combiner might use the color output of the previous
  394. // stage as input. Hence, we currently don't directly write the result to
  395. // combiner_output.rgb(), but instead store it in a temporary variable until
  396. // alpha combining has been done.
  397. Math::Vec3<u8> color_result[3] = {
  398. GetColorModifier(tev_stage.color_modifier1, GetSource(tev_stage.color_source1)),
  399. GetColorModifier(tev_stage.color_modifier2, GetSource(tev_stage.color_source2)),
  400. GetColorModifier(tev_stage.color_modifier3, GetSource(tev_stage.color_source3))
  401. };
  402. auto color_output = ColorCombine(tev_stage.color_op, color_result);
  403. // alpha combiner
  404. std::array<u8,3> alpha_result = {
  405. GetAlphaModifier(tev_stage.alpha_modifier1, GetSource(tev_stage.alpha_source1)),
  406. GetAlphaModifier(tev_stage.alpha_modifier2, GetSource(tev_stage.alpha_source2)),
  407. GetAlphaModifier(tev_stage.alpha_modifier3, GetSource(tev_stage.alpha_source3))
  408. };
  409. auto alpha_output = AlphaCombine(tev_stage.alpha_op, alpha_result);
  410. combiner_output = Math::MakeVec(color_output, alpha_output);
  411. }
  412. if (registers.output_merger.alpha_test.enable) {
  413. bool pass = false;
  414. switch (registers.output_merger.alpha_test.func) {
  415. case registers.output_merger.Never:
  416. pass = false;
  417. break;
  418. case registers.output_merger.Always:
  419. pass = true;
  420. break;
  421. case registers.output_merger.Equal:
  422. pass = combiner_output.a() == registers.output_merger.alpha_test.ref;
  423. break;
  424. case registers.output_merger.NotEqual:
  425. pass = combiner_output.a() != registers.output_merger.alpha_test.ref;
  426. break;
  427. case registers.output_merger.LessThan:
  428. pass = combiner_output.a() < registers.output_merger.alpha_test.ref;
  429. break;
  430. case registers.output_merger.LessThanOrEqual:
  431. pass = combiner_output.a() <= registers.output_merger.alpha_test.ref;
  432. break;
  433. case registers.output_merger.GreaterThan:
  434. pass = combiner_output.a() > registers.output_merger.alpha_test.ref;
  435. break;
  436. case registers.output_merger.GreaterThanOrEqual:
  437. pass = combiner_output.a() >= registers.output_merger.alpha_test.ref;
  438. break;
  439. }
  440. if (!pass)
  441. continue;
  442. }
  443. // TODO: Does depth indeed only get written even if depth testing is enabled?
  444. if (registers.output_merger.depth_test_enable) {
  445. u16 z = (u16)((v0.screenpos[2].ToFloat32() * w0 +
  446. v1.screenpos[2].ToFloat32() * w1 +
  447. v2.screenpos[2].ToFloat32() * w2) * 65535.f / wsum);
  448. u16 ref_z = GetDepth(x >> 4, y >> 4);
  449. bool pass = false;
  450. switch (registers.output_merger.depth_test_func) {
  451. case registers.output_merger.Never:
  452. pass = false;
  453. break;
  454. case registers.output_merger.Always:
  455. pass = true;
  456. break;
  457. case registers.output_merger.Equal:
  458. pass = z == ref_z;
  459. break;
  460. case registers.output_merger.NotEqual:
  461. pass = z != ref_z;
  462. break;
  463. case registers.output_merger.LessThan:
  464. pass = z < ref_z;
  465. break;
  466. case registers.output_merger.LessThanOrEqual:
  467. pass = z <= ref_z;
  468. break;
  469. case registers.output_merger.GreaterThan:
  470. pass = z > ref_z;
  471. break;
  472. case registers.output_merger.GreaterThanOrEqual:
  473. pass = z >= ref_z;
  474. break;
  475. }
  476. if (!pass)
  477. continue;
  478. if (registers.output_merger.depth_write_enable)
  479. SetDepth(x >> 4, y >> 4, z);
  480. }
  481. auto dest = GetPixel(x >> 4, y >> 4);
  482. Math::Vec4<u8> blend_output = combiner_output;
  483. if (registers.output_merger.alphablend_enable) {
  484. auto params = registers.output_merger.alpha_blending;
  485. auto LookupFactorRGB = [&](decltype(params)::BlendFactor factor) -> Math::Vec3<u8> {
  486. switch (factor) {
  487. case params.Zero:
  488. return Math::Vec3<u8>(0, 0, 0);
  489. case params.One:
  490. return Math::Vec3<u8>(255, 255, 255);
  491. case params.SourceColor:
  492. return combiner_output.rgb();
  493. case params.OneMinusSourceColor:
  494. return Math::Vec3<u8>(255 - combiner_output.r(), 255 - combiner_output.g(), 255 - combiner_output.b());
  495. case params.DestColor:
  496. return dest.rgb();
  497. case params.OneMinusDestColor:
  498. return Math::Vec3<u8>(255 - dest.r(), 255 - dest.g(), 255 - dest.b());
  499. case params.SourceAlpha:
  500. return Math::Vec3<u8>(combiner_output.a(), combiner_output.a(), combiner_output.a());
  501. case params.OneMinusSourceAlpha:
  502. return Math::Vec3<u8>(255 - combiner_output.a(), 255 - combiner_output.a(), 255 - combiner_output.a());
  503. case params.DestAlpha:
  504. return Math::Vec3<u8>(dest.a(), dest.a(), dest.a());
  505. case params.OneMinusDestAlpha:
  506. return Math::Vec3<u8>(255 - dest.a(), 255 - dest.a(), 255 - dest.a());
  507. case params.ConstantColor:
  508. return Math::Vec3<u8>(registers.output_merger.blend_const.r, registers.output_merger.blend_const.g, registers.output_merger.blend_const.b);
  509. case params.OneMinusConstantColor:
  510. return Math::Vec3<u8>(255 - registers.output_merger.blend_const.r, 255 - registers.output_merger.blend_const.g, 255 - registers.output_merger.blend_const.b);
  511. case params.ConstantAlpha:
  512. return Math::Vec3<u8>(registers.output_merger.blend_const.a, registers.output_merger.blend_const.a, registers.output_merger.blend_const.a);
  513. case params.OneMinusConstantAlpha:
  514. return Math::Vec3<u8>(255 - registers.output_merger.blend_const.a, 255 - registers.output_merger.blend_const.a, 255 - registers.output_merger.blend_const.a);
  515. default:
  516. LOG_CRITICAL(HW_GPU, "Unknown color blend factor %x", factor);
  517. exit(0);
  518. break;
  519. }
  520. };
  521. auto LookupFactorA = [&](decltype(params)::BlendFactor factor) -> u8 {
  522. switch (factor) {
  523. case params.Zero:
  524. return 0;
  525. case params.One:
  526. return 255;
  527. case params.SourceAlpha:
  528. return combiner_output.a();
  529. case params.OneMinusSourceAlpha:
  530. return 255 - combiner_output.a();
  531. case params.DestAlpha:
  532. return dest.a();
  533. case params.OneMinusDestAlpha:
  534. return 255 - dest.a();
  535. case params.ConstantAlpha:
  536. return registers.output_merger.blend_const.a;
  537. case params.OneMinusConstantAlpha:
  538. return 255 - registers.output_merger.blend_const.a;
  539. default:
  540. LOG_CRITICAL(HW_GPU, "Unknown alpha blend factor %x", factor);
  541. exit(0);
  542. break;
  543. }
  544. };
  545. using BlendEquation = decltype(params)::BlendEquation;
  546. static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
  547. const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
  548. BlendEquation equation) {
  549. Math::Vec4<int> result;
  550. auto src_result = (src * srcfactor).Cast<int>();
  551. auto dst_result = (dest * destfactor).Cast<int>();
  552. switch (equation) {
  553. case BlendEquation::Add:
  554. result = (src_result + dst_result) / 255;
  555. break;
  556. case BlendEquation::Subtract:
  557. result = (src_result - dst_result) / 255;
  558. break;
  559. case BlendEquation::ReverseSubtract:
  560. result = (dst_result - src_result) / 255;
  561. break;
  562. // TODO: How do these two actually work?
  563. // OpenGL doesn't include the blend factors in the min/max computations,
  564. // but is this what the 3DS actually does?
  565. case BlendEquation::Min:
  566. result.r() = std::min(src.r(), dest.r());
  567. result.g() = std::min(src.g(), dest.g());
  568. result.b() = std::min(src.b(), dest.b());
  569. result.a() = std::min(src.a(), dest.a());
  570. break;
  571. case BlendEquation::Max:
  572. result.r() = std::max(src.r(), dest.r());
  573. result.g() = std::max(src.g(), dest.g());
  574. result.b() = std::max(src.b(), dest.b());
  575. result.a() = std::max(src.a(), dest.a());
  576. break;
  577. default:
  578. LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", equation);
  579. exit(0);
  580. }
  581. return Math::Vec4<u8>(MathUtil::Clamp(result.r(), 0, 255),
  582. MathUtil::Clamp(result.g(), 0, 255),
  583. MathUtil::Clamp(result.b(), 0, 255),
  584. MathUtil::Clamp(result.a(), 0, 255));
  585. };
  586. auto srcfactor = Math::MakeVec(LookupFactorRGB(params.factor_source_rgb),
  587. LookupFactorA(params.factor_source_a));
  588. auto dstfactor = Math::MakeVec(LookupFactorRGB(params.factor_dest_rgb),
  589. LookupFactorA(params.factor_dest_a));
  590. blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb);
  591. blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a();
  592. } else {
  593. LOG_CRITICAL(HW_GPU, "logic op: %x", registers.output_merger.logic_op);
  594. exit(0);
  595. }
  596. const Math::Vec4<u8> result = {
  597. registers.output_merger.red_enable ? blend_output.r() : dest.r(),
  598. registers.output_merger.green_enable ? blend_output.g() : dest.g(),
  599. registers.output_merger.blue_enable ? blend_output.b() : dest.b(),
  600. registers.output_merger.alpha_enable ? blend_output.a() : dest.a()
  601. };
  602. DrawPixel(x >> 4, y >> 4, result);
  603. }
  604. }
  605. }
  606. void ProcessTriangle(const VertexShader::OutputVertex& v0,
  607. const VertexShader::OutputVertex& v1,
  608. const VertexShader::OutputVertex& v2) {
  609. ProcessTriangleInternal(v0, v1, v2);
  610. }
  611. } // namespace Rasterizer
  612. } // namespace Pica