rasterizer.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  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 <array>
  6. #include <cmath>
  7. #include <tuple>
  8. #include "common/assert.h"
  9. #include "common/bit_field.h"
  10. #include "common/color.h"
  11. #include "common/common_types.h"
  12. #include "common/logging/log.h"
  13. #include "common/math_util.h"
  14. #include "common/microprofile.h"
  15. #include "common/vector_math.h"
  16. #include "core/hw/gpu.h"
  17. #include "core/memory.h"
  18. #include "video_core/debug_utils/debug_utils.h"
  19. #include "video_core/pica_state.h"
  20. #include "video_core/pica_types.h"
  21. #include "video_core/regs_framebuffer.h"
  22. #include "video_core/regs_rasterizer.h"
  23. #include "video_core/regs_texturing.h"
  24. #include "video_core/shader/shader.h"
  25. #include "video_core/swrasterizer/framebuffer.h"
  26. #include "video_core/swrasterizer/proctex.h"
  27. #include "video_core/swrasterizer/rasterizer.h"
  28. #include "video_core/swrasterizer/texturing.h"
  29. #include "video_core/texture/texture_decode.h"
  30. #include "video_core/utils.h"
  31. namespace Pica {
  32. namespace Rasterizer {
  33. // NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values
  34. struct Fix12P4 {
  35. Fix12P4() {}
  36. Fix12P4(u16 val) : val(val) {}
  37. static u16 FracMask() {
  38. return 0xF;
  39. }
  40. static u16 IntMask() {
  41. return (u16)~0xF;
  42. }
  43. operator u16() const {
  44. return val;
  45. }
  46. bool operator<(const Fix12P4& oth) const {
  47. return (u16) * this < (u16)oth;
  48. }
  49. private:
  50. u16 val;
  51. };
  52. /**
  53. * Calculate signed area of the triangle spanned by the three argument vertices.
  54. * The sign denotes an orientation.
  55. *
  56. * @todo define orientation concretely.
  57. */
  58. static int SignedArea(const Math::Vec2<Fix12P4>& vtx1, const Math::Vec2<Fix12P4>& vtx2,
  59. const Math::Vec2<Fix12P4>& vtx3) {
  60. const auto vec1 = Math::MakeVec(vtx2 - vtx1, 0);
  61. const auto vec2 = Math::MakeVec(vtx3 - vtx1, 0);
  62. // TODO: There is a very small chance this will overflow for sizeof(int) == 4
  63. return Math::Cross(vec1, vec2).z;
  64. };
  65. /// Convert a 3D vector for cube map coordinates to 2D texture coordinates along with the face name
  66. static std::tuple<float24, float24, PAddr> ConvertCubeCoord(float24 u, float24 v, float24 w,
  67. const TexturingRegs& regs) {
  68. const float abs_u = std::abs(u.ToFloat32());
  69. const float abs_v = std::abs(v.ToFloat32());
  70. const float abs_w = std::abs(w.ToFloat32());
  71. float24 x, y, z;
  72. PAddr addr;
  73. if (abs_u > abs_v && abs_u > abs_w) {
  74. if (u > float24::FromFloat32(0)) {
  75. addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveX);
  76. y = -v;
  77. } else {
  78. addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeX);
  79. y = v;
  80. }
  81. x = -w;
  82. z = u;
  83. } else if (abs_v > abs_w) {
  84. if (v > float24::FromFloat32(0)) {
  85. addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveY);
  86. x = u;
  87. } else {
  88. addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeY);
  89. x = -u;
  90. }
  91. y = w;
  92. z = v;
  93. } else {
  94. if (w > float24::FromFloat32(0)) {
  95. addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveZ);
  96. y = -v;
  97. } else {
  98. addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeZ);
  99. y = v;
  100. }
  101. x = u;
  102. z = w;
  103. }
  104. const float24 half = float24::FromFloat32(0.5f);
  105. return std::make_tuple(x / z * half + half, y / z * half + half, addr);
  106. }
  107. MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240));
  108. /**
  109. * Helper function for ProcessTriangle with the "reversed" flag to allow for implementing
  110. * culling via recursion.
  111. */
  112. static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Vertex& v2,
  113. bool reversed = false) {
  114. const auto& regs = g_state.regs;
  115. MICROPROFILE_SCOPE(GPU_Rasterization);
  116. // vertex positions in rasterizer coordinates
  117. static auto FloatToFix = [](float24 flt) {
  118. // TODO: Rounding here is necessary to prevent garbage pixels at
  119. // triangle borders. Is it that the correct solution, though?
  120. return Fix12P4(static_cast<unsigned short>(round(flt.ToFloat32() * 16.0f)));
  121. };
  122. static auto ScreenToRasterizerCoordinates = [](const Math::Vec3<float24>& vec) {
  123. return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)};
  124. };
  125. Math::Vec3<Fix12P4> vtxpos[3]{ScreenToRasterizerCoordinates(v0.screenpos),
  126. ScreenToRasterizerCoordinates(v1.screenpos),
  127. ScreenToRasterizerCoordinates(v2.screenpos)};
  128. if (regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepAll) {
  129. // Make sure we always end up with a triangle wound counter-clockwise
  130. if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) {
  131. ProcessTriangleInternal(v0, v2, v1, true);
  132. return;
  133. }
  134. } else {
  135. if (!reversed && regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepClockWise) {
  136. // Reverse vertex order and use the CCW code path.
  137. ProcessTriangleInternal(v0, v2, v1, true);
  138. return;
  139. }
  140. // Cull away triangles which are wound clockwise.
  141. if (SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0)
  142. return;
  143. }
  144. u16 min_x = std::min({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x});
  145. u16 min_y = std::min({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y});
  146. u16 max_x = std::max({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x});
  147. u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y});
  148. // Convert the scissor box coordinates to 12.4 fixed point
  149. u16 scissor_x1 = (u16)(regs.rasterizer.scissor_test.x1 << 4);
  150. u16 scissor_y1 = (u16)(regs.rasterizer.scissor_test.y1 << 4);
  151. // x2,y2 have +1 added to cover the entire sub-pixel area
  152. u16 scissor_x2 = (u16)((regs.rasterizer.scissor_test.x2 + 1) << 4);
  153. u16 scissor_y2 = (u16)((regs.rasterizer.scissor_test.y2 + 1) << 4);
  154. if (regs.rasterizer.scissor_test.mode == RasterizerRegs::ScissorMode::Include) {
  155. // Calculate the new bounds
  156. min_x = std::max(min_x, scissor_x1);
  157. min_y = std::max(min_y, scissor_y1);
  158. max_x = std::min(max_x, scissor_x2);
  159. max_y = std::min(max_y, scissor_y2);
  160. }
  161. min_x &= Fix12P4::IntMask();
  162. min_y &= Fix12P4::IntMask();
  163. max_x = ((max_x + Fix12P4::FracMask()) & Fix12P4::IntMask());
  164. max_y = ((max_y + Fix12P4::FracMask()) & Fix12P4::IntMask());
  165. // Triangle filling rules: Pixels on the right-sided edge or on flat bottom edges are not
  166. // drawn. Pixels on any other triangle border are drawn. This is implemented with three bias
  167. // values which are added to the barycentric coordinates w0, w1 and w2, respectively.
  168. // NOTE: These are the PSP filling rules. Not sure if the 3DS uses the same ones...
  169. auto IsRightSideOrFlatBottomEdge = [](const Math::Vec2<Fix12P4>& vtx,
  170. const Math::Vec2<Fix12P4>& line1,
  171. const Math::Vec2<Fix12P4>& line2) {
  172. if (line1.y == line2.y) {
  173. // just check if vertex is above us => bottom line parallel to x-axis
  174. return vtx.y < line1.y;
  175. } else {
  176. // check if vertex is on our left => right side
  177. // TODO: Not sure how likely this is to overflow
  178. return (int)vtx.x < (int)line1.x +
  179. ((int)line2.x - (int)line1.x) * ((int)vtx.y - (int)line1.y) /
  180. ((int)line2.y - (int)line1.y);
  181. }
  182. };
  183. int bias0 =
  184. IsRightSideOrFlatBottomEdge(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) ? -1 : 0;
  185. int bias1 =
  186. IsRightSideOrFlatBottomEdge(vtxpos[1].xy(), vtxpos[2].xy(), vtxpos[0].xy()) ? -1 : 0;
  187. int bias2 =
  188. IsRightSideOrFlatBottomEdge(vtxpos[2].xy(), vtxpos[0].xy(), vtxpos[1].xy()) ? -1 : 0;
  189. auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
  190. auto textures = regs.texturing.GetTextures();
  191. auto tev_stages = regs.texturing.GetTevStages();
  192. bool stencil_action_enable =
  193. g_state.regs.framebuffer.output_merger.stencil_test.enable &&
  194. g_state.regs.framebuffer.framebuffer.depth_format == FramebufferRegs::DepthFormat::D24S8;
  195. const auto stencil_test = g_state.regs.framebuffer.output_merger.stencil_test;
  196. // Enter rasterization loop, starting at the center of the topleft bounding box corner.
  197. // TODO: Not sure if looping through x first might be faster
  198. for (u16 y = min_y + 8; y < max_y; y += 0x10) {
  199. for (u16 x = min_x + 8; x < max_x; x += 0x10) {
  200. // Do not process the pixel if it's inside the scissor box and the scissor mode is set
  201. // to Exclude
  202. if (regs.rasterizer.scissor_test.mode == RasterizerRegs::ScissorMode::Exclude) {
  203. if (x >= scissor_x1 && x < scissor_x2 && y >= scissor_y1 && y < scissor_y2)
  204. continue;
  205. }
  206. // Calculate the barycentric coordinates w0, w1 and w2
  207. int w0 = bias0 + SignedArea(vtxpos[1].xy(), vtxpos[2].xy(), {x, y});
  208. int w1 = bias1 + SignedArea(vtxpos[2].xy(), vtxpos[0].xy(), {x, y});
  209. int w2 = bias2 + SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), {x, y});
  210. int wsum = w0 + w1 + w2;
  211. // If current pixel is not covered by the current primitive
  212. if (w0 < 0 || w1 < 0 || w2 < 0)
  213. continue;
  214. auto baricentric_coordinates =
  215. Math::MakeVec(float24::FromFloat32(static_cast<float>(w0)),
  216. float24::FromFloat32(static_cast<float>(w1)),
  217. float24::FromFloat32(static_cast<float>(w2)));
  218. float24 interpolated_w_inverse =
  219. float24::FromFloat32(1.0f) / Math::Dot(w_inverse, baricentric_coordinates);
  220. // interpolated_z = z / w
  221. float interpolated_z_over_w =
  222. (v0.screenpos[2].ToFloat32() * w0 + v1.screenpos[2].ToFloat32() * w1 +
  223. v2.screenpos[2].ToFloat32() * w2) /
  224. wsum;
  225. // Not fully accurate. About 3 bits in precision are missing.
  226. // Z-Buffer (z / w * scale + offset)
  227. float depth_scale = float24::FromRaw(regs.rasterizer.viewport_depth_range).ToFloat32();
  228. float depth_offset =
  229. float24::FromRaw(regs.rasterizer.viewport_depth_near_plane).ToFloat32();
  230. float depth = interpolated_z_over_w * depth_scale + depth_offset;
  231. // Potentially switch to W-Buffer
  232. if (regs.rasterizer.depthmap_enable ==
  233. Pica::RasterizerRegs::DepthBuffering::WBuffering) {
  234. // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w)
  235. depth *= interpolated_w_inverse.ToFloat32() * wsum;
  236. }
  237. // Clamp the result
  238. depth = MathUtil::Clamp(depth, 0.0f, 1.0f);
  239. // Perspective correct attribute interpolation:
  240. // Attribute values cannot be calculated by simple linear interpolation since
  241. // they are not linear in screen space. For example, when interpolating a
  242. // texture coordinate across two vertices, something simple like
  243. // u = (u0*w0 + u1*w1)/(w0+w1)
  244. // will not work. However, the attribute value divided by the
  245. // clipspace w-coordinate (u/w) and and the inverse w-coordinate (1/w) are linear
  246. // in screenspace. Hence, we can linearly interpolate these two independently and
  247. // calculate the interpolated attribute by dividing the results.
  248. // I.e.
  249. // u_over_w = ((u0/v0.pos.w)*w0 + (u1/v1.pos.w)*w1)/(w0+w1)
  250. // one_over_w = (( 1/v0.pos.w)*w0 + ( 1/v1.pos.w)*w1)/(w0+w1)
  251. // u = u_over_w / one_over_w
  252. //
  253. // The generalization to three vertices is straightforward in baricentric coordinates.
  254. auto GetInterpolatedAttribute = [&](float24 attr0, float24 attr1, float24 attr2) {
  255. auto attr_over_w = Math::MakeVec(attr0, attr1, attr2);
  256. float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates);
  257. return interpolated_attr_over_w * interpolated_w_inverse;
  258. };
  259. Math::Vec4<u8> primary_color{
  260. (u8)(
  261. GetInterpolatedAttribute(v0.color.r(), v1.color.r(), v2.color.r()).ToFloat32() *
  262. 255),
  263. (u8)(
  264. GetInterpolatedAttribute(v0.color.g(), v1.color.g(), v2.color.g()).ToFloat32() *
  265. 255),
  266. (u8)(
  267. GetInterpolatedAttribute(v0.color.b(), v1.color.b(), v2.color.b()).ToFloat32() *
  268. 255),
  269. (u8)(
  270. GetInterpolatedAttribute(v0.color.a(), v1.color.a(), v2.color.a()).ToFloat32() *
  271. 255),
  272. };
  273. Math::Vec2<float24> uv[3];
  274. uv[0].u() = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u());
  275. uv[0].v() = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v());
  276. uv[1].u() = GetInterpolatedAttribute(v0.tc1.u(), v1.tc1.u(), v2.tc1.u());
  277. uv[1].v() = GetInterpolatedAttribute(v0.tc1.v(), v1.tc1.v(), v2.tc1.v());
  278. uv[2].u() = GetInterpolatedAttribute(v0.tc2.u(), v1.tc2.u(), v2.tc2.u());
  279. uv[2].v() = GetInterpolatedAttribute(v0.tc2.v(), v1.tc2.v(), v2.tc2.v());
  280. Math::Vec4<u8> texture_color[4]{};
  281. for (int i = 0; i < 3; ++i) {
  282. const auto& texture = textures[i];
  283. if (!texture.enabled)
  284. continue;
  285. DEBUG_ASSERT(0 != texture.config.address);
  286. int coordinate_i =
  287. (i == 2 && regs.texturing.main_config.texture2_use_coord1) ? 1 : i;
  288. float24 u = uv[coordinate_i].u();
  289. float24 v = uv[coordinate_i].v();
  290. // Only unit 0 respects the texturing type (according to 3DBrew)
  291. // TODO: Refactor so cubemaps and shadowmaps can be handled
  292. PAddr texture_address = texture.config.GetPhysicalAddress();
  293. if (i == 0) {
  294. switch (texture.config.type) {
  295. case TexturingRegs::TextureConfig::Texture2D:
  296. break;
  297. case TexturingRegs::TextureConfig::TextureCube: {
  298. auto w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
  299. std::tie(u, v, texture_address) = ConvertCubeCoord(u, v, w, regs.texturing);
  300. break;
  301. }
  302. case TexturingRegs::TextureConfig::Projection2D: {
  303. auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
  304. u /= tc0_w;
  305. v /= tc0_w;
  306. break;
  307. }
  308. default:
  309. // TODO: Change to LOG_ERROR when more types are handled.
  310. LOG_DEBUG(HW_GPU, "Unhandled texture type %x", (int)texture.config.type);
  311. UNIMPLEMENTED();
  312. break;
  313. }
  314. }
  315. int s = (int)(u * float24::FromFloat32(static_cast<float>(texture.config.width)))
  316. .ToFloat32();
  317. int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height)))
  318. .ToFloat32();
  319. bool use_border_s = false;
  320. bool use_border_t = false;
  321. if (texture.config.wrap_s == TexturingRegs::TextureConfig::ClampToBorder) {
  322. use_border_s = s < 0 || s >= static_cast<int>(texture.config.width);
  323. } else if (texture.config.wrap_s == TexturingRegs::TextureConfig::ClampToBorder2) {
  324. use_border_s = s >= static_cast<int>(texture.config.width);
  325. }
  326. if (texture.config.wrap_t == TexturingRegs::TextureConfig::ClampToBorder) {
  327. use_border_t = t < 0 || t >= static_cast<int>(texture.config.height);
  328. } else if (texture.config.wrap_t == TexturingRegs::TextureConfig::ClampToBorder2) {
  329. use_border_t = t >= static_cast<int>(texture.config.height);
  330. }
  331. if (use_border_s || use_border_t) {
  332. auto border_color = texture.config.border_color;
  333. texture_color[i] = {border_color.r, border_color.g, border_color.b,
  334. border_color.a};
  335. } else {
  336. // Textures are laid out from bottom to top, hence we invert the t coordinate.
  337. // NOTE: This may not be the right place for the inversion.
  338. // TODO: Check if this applies to ETC textures, too.
  339. s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width);
  340. t = texture.config.height - 1 -
  341. GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height);
  342. const u8* texture_data = Memory::GetPhysicalPointer(texture_address);
  343. auto info =
  344. Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
  345. // TODO: Apply the min and mag filters to the texture
  346. texture_color[i] = Texture::LookupTexture(texture_data, s, t, info);
  347. #if PICA_DUMP_TEXTURES
  348. DebugUtils::DumpTexture(texture.config, texture_data);
  349. #endif
  350. }
  351. }
  352. // sample procedural texture
  353. if (regs.texturing.main_config.texture3_enable) {
  354. const auto& proctex_uv = uv[regs.texturing.main_config.texture3_coordinates];
  355. texture_color[3] = ProcTex(proctex_uv.u().ToFloat32(), proctex_uv.v().ToFloat32(),
  356. g_state.regs.texturing, g_state.proctex);
  357. }
  358. // Texture environment - consists of 6 stages of color and alpha combining.
  359. //
  360. // Color combiners take three input color values from some source (e.g. interpolated
  361. // vertex color, texture color, previous stage, etc), perform some very simple
  362. // operations on each of them (e.g. inversion) and then calculate the output color
  363. // with some basic arithmetic. Alpha combiners can be configured separately but work
  364. // analogously.
  365. Math::Vec4<u8> combiner_output;
  366. Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
  367. Math::Vec4<u8> next_combiner_buffer = {
  368. regs.texturing.tev_combiner_buffer_color.r,
  369. regs.texturing.tev_combiner_buffer_color.g,
  370. regs.texturing.tev_combiner_buffer_color.b,
  371. regs.texturing.tev_combiner_buffer_color.a,
  372. };
  373. for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();
  374. ++tev_stage_index) {
  375. const auto& tev_stage = tev_stages[tev_stage_index];
  376. using Source = TexturingRegs::TevStageConfig::Source;
  377. auto GetSource = [&](Source source) -> Math::Vec4<u8> {
  378. switch (source) {
  379. case Source::PrimaryColor:
  380. // HACK: Until we implement fragment lighting, use primary_color
  381. case Source::PrimaryFragmentColor:
  382. return primary_color;
  383. // HACK: Until we implement fragment lighting, use zero
  384. case Source::SecondaryFragmentColor:
  385. return {0, 0, 0, 0};
  386. case Source::Texture0:
  387. return texture_color[0];
  388. case Source::Texture1:
  389. return texture_color[1];
  390. case Source::Texture2:
  391. return texture_color[2];
  392. case Source::Texture3:
  393. return texture_color[3];
  394. case Source::PreviousBuffer:
  395. return combiner_buffer;
  396. case Source::Constant:
  397. return {tev_stage.const_r, tev_stage.const_g, tev_stage.const_b,
  398. tev_stage.const_a};
  399. case Source::Previous:
  400. return combiner_output;
  401. default:
  402. LOG_ERROR(HW_GPU, "Unknown color combiner source %d", (int)source);
  403. UNIMPLEMENTED();
  404. return {0, 0, 0, 0};
  405. }
  406. };
  407. // color combiner
  408. // NOTE: Not sure if the alpha combiner might use the color output of the previous
  409. // stage as input. Hence, we currently don't directly write the result to
  410. // combiner_output.rgb(), but instead store it in a temporary variable until
  411. // alpha combining has been done.
  412. Math::Vec3<u8> color_result[3] = {
  413. GetColorModifier(tev_stage.color_modifier1, GetSource(tev_stage.color_source1)),
  414. GetColorModifier(tev_stage.color_modifier2, GetSource(tev_stage.color_source2)),
  415. GetColorModifier(tev_stage.color_modifier3, GetSource(tev_stage.color_source3)),
  416. };
  417. auto color_output = ColorCombine(tev_stage.color_op, color_result);
  418. u8 alpha_output;
  419. if (tev_stage.color_op == TexturingRegs::TevStageConfig::Operation::Dot3_RGBA) {
  420. // result of Dot3_RGBA operation is also placed to the alpha component
  421. alpha_output = color_output.x;
  422. } else {
  423. // alpha combiner
  424. std::array<u8, 3> alpha_result = {{
  425. GetAlphaModifier(tev_stage.alpha_modifier1,
  426. GetSource(tev_stage.alpha_source1)),
  427. GetAlphaModifier(tev_stage.alpha_modifier2,
  428. GetSource(tev_stage.alpha_source2)),
  429. GetAlphaModifier(tev_stage.alpha_modifier3,
  430. GetSource(tev_stage.alpha_source3)),
  431. }};
  432. alpha_output = AlphaCombine(tev_stage.alpha_op, alpha_result);
  433. }
  434. combiner_output[0] =
  435. std::min((unsigned)255, color_output.r() * tev_stage.GetColorMultiplier());
  436. combiner_output[1] =
  437. std::min((unsigned)255, color_output.g() * tev_stage.GetColorMultiplier());
  438. combiner_output[2] =
  439. std::min((unsigned)255, color_output.b() * tev_stage.GetColorMultiplier());
  440. combiner_output[3] =
  441. std::min((unsigned)255, alpha_output * tev_stage.GetAlphaMultiplier());
  442. combiner_buffer = next_combiner_buffer;
  443. if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(
  444. tev_stage_index)) {
  445. next_combiner_buffer.r() = combiner_output.r();
  446. next_combiner_buffer.g() = combiner_output.g();
  447. next_combiner_buffer.b() = combiner_output.b();
  448. }
  449. if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(
  450. tev_stage_index)) {
  451. next_combiner_buffer.a() = combiner_output.a();
  452. }
  453. }
  454. const auto& output_merger = regs.framebuffer.output_merger;
  455. // TODO: Does alpha testing happen before or after stencil?
  456. if (output_merger.alpha_test.enable) {
  457. bool pass = false;
  458. switch (output_merger.alpha_test.func) {
  459. case FramebufferRegs::CompareFunc::Never:
  460. pass = false;
  461. break;
  462. case FramebufferRegs::CompareFunc::Always:
  463. pass = true;
  464. break;
  465. case FramebufferRegs::CompareFunc::Equal:
  466. pass = combiner_output.a() == output_merger.alpha_test.ref;
  467. break;
  468. case FramebufferRegs::CompareFunc::NotEqual:
  469. pass = combiner_output.a() != output_merger.alpha_test.ref;
  470. break;
  471. case FramebufferRegs::CompareFunc::LessThan:
  472. pass = combiner_output.a() < output_merger.alpha_test.ref;
  473. break;
  474. case FramebufferRegs::CompareFunc::LessThanOrEqual:
  475. pass = combiner_output.a() <= output_merger.alpha_test.ref;
  476. break;
  477. case FramebufferRegs::CompareFunc::GreaterThan:
  478. pass = combiner_output.a() > output_merger.alpha_test.ref;
  479. break;
  480. case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
  481. pass = combiner_output.a() >= output_merger.alpha_test.ref;
  482. break;
  483. }
  484. if (!pass)
  485. continue;
  486. }
  487. // Apply fog combiner
  488. // Not fully accurate. We'd have to know what data type is used to
  489. // store the depth etc. Using float for now until we know more
  490. // about Pica datatypes
  491. if (regs.texturing.fog_mode == TexturingRegs::FogMode::Fog) {
  492. const Math::Vec3<u8> fog_color = {
  493. static_cast<u8>(regs.texturing.fog_color.r.Value()),
  494. static_cast<u8>(regs.texturing.fog_color.g.Value()),
  495. static_cast<u8>(regs.texturing.fog_color.b.Value()),
  496. };
  497. // Get index into fog LUT
  498. float fog_index;
  499. if (g_state.regs.texturing.fog_flip) {
  500. fog_index = (1.0f - depth) * 128.0f;
  501. } else {
  502. fog_index = depth * 128.0f;
  503. }
  504. // Generate clamped fog factor from LUT for given fog index
  505. float fog_i = MathUtil::Clamp(floorf(fog_index), 0.0f, 127.0f);
  506. float fog_f = fog_index - fog_i;
  507. const auto& fog_lut_entry = g_state.fog.lut[static_cast<unsigned int>(fog_i)];
  508. float fog_factor = fog_lut_entry.ToFloat() + fog_lut_entry.DiffToFloat() * fog_f;
  509. fog_factor = MathUtil::Clamp(fog_factor, 0.0f, 1.0f);
  510. // Blend the fog
  511. for (unsigned i = 0; i < 3; i++) {
  512. combiner_output[i] = static_cast<u8>(fog_factor * combiner_output[i] +
  513. (1.0f - fog_factor) * fog_color[i]);
  514. }
  515. }
  516. u8 old_stencil = 0;
  517. auto UpdateStencil = [stencil_test, x, y,
  518. &old_stencil](Pica::FramebufferRegs::StencilAction action) {
  519. u8 new_stencil =
  520. PerformStencilAction(action, old_stencil, stencil_test.reference_value);
  521. if (g_state.regs.framebuffer.framebuffer.allow_depth_stencil_write != 0)
  522. SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) |
  523. (old_stencil & ~stencil_test.write_mask));
  524. };
  525. if (stencil_action_enable) {
  526. old_stencil = GetStencil(x >> 4, y >> 4);
  527. u8 dest = old_stencil & stencil_test.input_mask;
  528. u8 ref = stencil_test.reference_value & stencil_test.input_mask;
  529. bool pass = false;
  530. switch (stencil_test.func) {
  531. case FramebufferRegs::CompareFunc::Never:
  532. pass = false;
  533. break;
  534. case FramebufferRegs::CompareFunc::Always:
  535. pass = true;
  536. break;
  537. case FramebufferRegs::CompareFunc::Equal:
  538. pass = (ref == dest);
  539. break;
  540. case FramebufferRegs::CompareFunc::NotEqual:
  541. pass = (ref != dest);
  542. break;
  543. case FramebufferRegs::CompareFunc::LessThan:
  544. pass = (ref < dest);
  545. break;
  546. case FramebufferRegs::CompareFunc::LessThanOrEqual:
  547. pass = (ref <= dest);
  548. break;
  549. case FramebufferRegs::CompareFunc::GreaterThan:
  550. pass = (ref > dest);
  551. break;
  552. case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
  553. pass = (ref >= dest);
  554. break;
  555. }
  556. if (!pass) {
  557. UpdateStencil(stencil_test.action_stencil_fail);
  558. continue;
  559. }
  560. }
  561. // Convert float to integer
  562. unsigned num_bits =
  563. FramebufferRegs::DepthBitsPerPixel(regs.framebuffer.framebuffer.depth_format);
  564. u32 z = (u32)(depth * ((1 << num_bits) - 1));
  565. if (output_merger.depth_test_enable) {
  566. u32 ref_z = GetDepth(x >> 4, y >> 4);
  567. bool pass = false;
  568. switch (output_merger.depth_test_func) {
  569. case FramebufferRegs::CompareFunc::Never:
  570. pass = false;
  571. break;
  572. case FramebufferRegs::CompareFunc::Always:
  573. pass = true;
  574. break;
  575. case FramebufferRegs::CompareFunc::Equal:
  576. pass = z == ref_z;
  577. break;
  578. case FramebufferRegs::CompareFunc::NotEqual:
  579. pass = z != ref_z;
  580. break;
  581. case FramebufferRegs::CompareFunc::LessThan:
  582. pass = z < ref_z;
  583. break;
  584. case FramebufferRegs::CompareFunc::LessThanOrEqual:
  585. pass = z <= ref_z;
  586. break;
  587. case FramebufferRegs::CompareFunc::GreaterThan:
  588. pass = z > ref_z;
  589. break;
  590. case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
  591. pass = z >= ref_z;
  592. break;
  593. }
  594. if (!pass) {
  595. if (stencil_action_enable)
  596. UpdateStencil(stencil_test.action_depth_fail);
  597. continue;
  598. }
  599. }
  600. if (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 &&
  601. output_merger.depth_write_enable) {
  602. SetDepth(x >> 4, y >> 4, z);
  603. }
  604. // The stencil depth_pass action is executed even if depth testing is disabled
  605. if (stencil_action_enable)
  606. UpdateStencil(stencil_test.action_depth_pass);
  607. auto dest = GetPixel(x >> 4, y >> 4);
  608. Math::Vec4<u8> blend_output = combiner_output;
  609. if (output_merger.alphablend_enable) {
  610. auto params = output_merger.alpha_blending;
  611. auto LookupFactor = [&](unsigned channel,
  612. FramebufferRegs::BlendFactor factor) -> u8 {
  613. DEBUG_ASSERT(channel < 4);
  614. const Math::Vec4<u8> blend_const = {
  615. static_cast<u8>(output_merger.blend_const.r),
  616. static_cast<u8>(output_merger.blend_const.g),
  617. static_cast<u8>(output_merger.blend_const.b),
  618. static_cast<u8>(output_merger.blend_const.a),
  619. };
  620. switch (factor) {
  621. case FramebufferRegs::BlendFactor::Zero:
  622. return 0;
  623. case FramebufferRegs::BlendFactor::One:
  624. return 255;
  625. case FramebufferRegs::BlendFactor::SourceColor:
  626. return combiner_output[channel];
  627. case FramebufferRegs::BlendFactor::OneMinusSourceColor:
  628. return 255 - combiner_output[channel];
  629. case FramebufferRegs::BlendFactor::DestColor:
  630. return dest[channel];
  631. case FramebufferRegs::BlendFactor::OneMinusDestColor:
  632. return 255 - dest[channel];
  633. case FramebufferRegs::BlendFactor::SourceAlpha:
  634. return combiner_output.a();
  635. case FramebufferRegs::BlendFactor::OneMinusSourceAlpha:
  636. return 255 - combiner_output.a();
  637. case FramebufferRegs::BlendFactor::DestAlpha:
  638. return dest.a();
  639. case FramebufferRegs::BlendFactor::OneMinusDestAlpha:
  640. return 255 - dest.a();
  641. case FramebufferRegs::BlendFactor::ConstantColor:
  642. return blend_const[channel];
  643. case FramebufferRegs::BlendFactor::OneMinusConstantColor:
  644. return 255 - blend_const[channel];
  645. case FramebufferRegs::BlendFactor::ConstantAlpha:
  646. return blend_const.a();
  647. case FramebufferRegs::BlendFactor::OneMinusConstantAlpha:
  648. return 255 - blend_const.a();
  649. case FramebufferRegs::BlendFactor::SourceAlphaSaturate:
  650. // Returns 1.0 for the alpha channel
  651. if (channel == 3)
  652. return 255;
  653. return std::min(combiner_output.a(), static_cast<u8>(255 - dest.a()));
  654. default:
  655. LOG_CRITICAL(HW_GPU, "Unknown blend factor %x", factor);
  656. UNIMPLEMENTED();
  657. break;
  658. }
  659. return combiner_output[channel];
  660. };
  661. auto srcfactor = Math::MakeVec(LookupFactor(0, params.factor_source_rgb),
  662. LookupFactor(1, params.factor_source_rgb),
  663. LookupFactor(2, params.factor_source_rgb),
  664. LookupFactor(3, params.factor_source_a));
  665. auto dstfactor = Math::MakeVec(LookupFactor(0, params.factor_dest_rgb),
  666. LookupFactor(1, params.factor_dest_rgb),
  667. LookupFactor(2, params.factor_dest_rgb),
  668. LookupFactor(3, params.factor_dest_a));
  669. blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor,
  670. params.blend_equation_rgb);
  671. blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest,
  672. dstfactor, params.blend_equation_a)
  673. .a();
  674. } else {
  675. blend_output =
  676. Math::MakeVec(LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op),
  677. LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op),
  678. LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op),
  679. LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op));
  680. }
  681. const Math::Vec4<u8> result = {
  682. output_merger.red_enable ? blend_output.r() : dest.r(),
  683. output_merger.green_enable ? blend_output.g() : dest.g(),
  684. output_merger.blue_enable ? blend_output.b() : dest.b(),
  685. output_merger.alpha_enable ? blend_output.a() : dest.a(),
  686. };
  687. if (regs.framebuffer.framebuffer.allow_color_write != 0)
  688. DrawPixel(x >> 4, y >> 4, result);
  689. }
  690. }
  691. }
  692. void ProcessTriangle(const Vertex& v0, const Vertex& v1, const Vertex& v2) {
  693. ProcessTriangleInternal(v0, v1, v2);
  694. }
  695. } // namespace Rasterizer
  696. } // namespace Pica