rasterizer.cpp 41 KB

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