rasterizer.cpp 34 KB

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