rasterizer.cpp 37 KB

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