draw_manager.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/settings.h"
  4. #include "video_core/dirty_flags.h"
  5. #include "video_core/engines/draw_manager.h"
  6. #include "video_core/rasterizer_interface.h"
  7. namespace Tegra::Engines {
  8. DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {}
  9. void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
  10. const auto& regs{maxwell3d->regs};
  11. switch (method) {
  12. case MAXWELL3D_REG_INDEX(clear_surface):
  13. return Clear(1);
  14. case MAXWELL3D_REG_INDEX(draw.begin):
  15. return DrawBegin();
  16. case MAXWELL3D_REG_INDEX(draw.end):
  17. return DrawEnd();
  18. case MAXWELL3D_REG_INDEX(vertex_buffer.first):
  19. case MAXWELL3D_REG_INDEX(vertex_buffer.count):
  20. case MAXWELL3D_REG_INDEX(index_buffer.first):
  21. break;
  22. case MAXWELL3D_REG_INDEX(index_buffer.count):
  23. draw_state.draw_indexed = true;
  24. break;
  25. case MAXWELL3D_REG_INDEX(index_buffer32_subsequent):
  26. case MAXWELL3D_REG_INDEX(index_buffer16_subsequent):
  27. case MAXWELL3D_REG_INDEX(index_buffer8_subsequent):
  28. draw_state.instance_count++;
  29. [[fallthrough]];
  30. case MAXWELL3D_REG_INDEX(index_buffer32_first):
  31. case MAXWELL3D_REG_INDEX(index_buffer16_first):
  32. case MAXWELL3D_REG_INDEX(index_buffer8_first):
  33. return DrawIndexSmall(argument);
  34. case MAXWELL3D_REG_INDEX(draw_inline_index):
  35. SetInlineIndexBuffer(argument);
  36. break;
  37. case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
  38. SetInlineIndexBuffer(regs.inline_index_2x16.even);
  39. SetInlineIndexBuffer(regs.inline_index_2x16.odd);
  40. break;
  41. case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
  42. SetInlineIndexBuffer(regs.inline_index_4x8.index0);
  43. SetInlineIndexBuffer(regs.inline_index_4x8.index1);
  44. SetInlineIndexBuffer(regs.inline_index_4x8.index2);
  45. SetInlineIndexBuffer(regs.inline_index_4x8.index3);
  46. break;
  47. case MAXWELL3D_REG_INDEX(vertex_array_instance_first):
  48. DrawArrayInstanced(regs.vertex_array_instance_first.topology.Value(),
  49. regs.vertex_array_instance_first.start.Value(),
  50. regs.vertex_array_instance_first.count.Value(), false);
  51. break;
  52. case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): {
  53. DrawArrayInstanced(regs.vertex_array_instance_subsequent.topology.Value(),
  54. regs.vertex_array_instance_subsequent.start.Value(),
  55. regs.vertex_array_instance_subsequent.count.Value(), true);
  56. break;
  57. }
  58. case MAXWELL3D_REG_INDEX(draw_texture.src_y0): {
  59. DrawTexture();
  60. break;
  61. }
  62. default:
  63. break;
  64. }
  65. }
  66. void DrawManager::Clear(u32 layer_count) {
  67. if (maxwell3d->ShouldExecute()) {
  68. maxwell3d->rasterizer->Clear(layer_count);
  69. }
  70. }
  71. void DrawManager::DrawDeferred() {
  72. if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0) {
  73. return;
  74. }
  75. DrawEnd(draw_state.instance_count + 1, true);
  76. draw_state.instance_count = 0;
  77. }
  78. void DrawManager::DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
  79. u32 base_instance, u32 num_instances) {
  80. draw_state.topology = topology;
  81. draw_state.vertex_buffer.first = vertex_first;
  82. draw_state.vertex_buffer.count = vertex_count;
  83. draw_state.base_instance = base_instance;
  84. ProcessDraw(false, num_instances);
  85. }
  86. void DrawManager::DrawArrayInstanced(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
  87. bool subsequent) {
  88. draw_state.topology = topology;
  89. draw_state.vertex_buffer.first = vertex_first;
  90. draw_state.vertex_buffer.count = vertex_count;
  91. if (!subsequent) {
  92. draw_state.instance_count = 1;
  93. }
  94. draw_state.base_instance = draw_state.instance_count - 1;
  95. draw_state.draw_mode = DrawMode::Instance;
  96. draw_state.instance_count++;
  97. ProcessDraw(false, 1);
  98. }
  99. void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count,
  100. u32 base_index, u32 base_instance, u32 num_instances) {
  101. const auto& regs{maxwell3d->regs};
  102. draw_state.topology = topology;
  103. draw_state.index_buffer = regs.index_buffer;
  104. draw_state.index_buffer.first = index_first;
  105. draw_state.index_buffer.count = index_count;
  106. draw_state.base_index = base_index;
  107. draw_state.base_instance = base_instance;
  108. ProcessDraw(true, num_instances);
  109. }
  110. void DrawManager::DrawArrayIndirect(PrimitiveTopology topology) {
  111. draw_state.topology = topology;
  112. ProcessDrawIndirect();
  113. }
  114. void DrawManager::DrawIndexedIndirect(PrimitiveTopology topology, u32 index_first,
  115. u32 index_count) {
  116. const auto& regs{maxwell3d->regs};
  117. draw_state.topology = topology;
  118. draw_state.index_buffer = regs.index_buffer;
  119. draw_state.index_buffer.first = index_first;
  120. draw_state.index_buffer.count = index_count;
  121. ProcessDrawIndirect();
  122. }
  123. void DrawManager::SetInlineIndexBuffer(u32 index) {
  124. draw_state.inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff));
  125. draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8));
  126. draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16));
  127. draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24));
  128. draw_state.draw_mode = DrawMode::InlineIndex;
  129. }
  130. void DrawManager::DrawBegin() {
  131. const auto& regs{maxwell3d->regs};
  132. auto reset_instance_count = regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First;
  133. auto increment_instance_count =
  134. regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent;
  135. if (reset_instance_count) {
  136. DrawDeferred();
  137. draw_state.instance_count = 0;
  138. draw_state.draw_mode = DrawMode::General;
  139. } else if (increment_instance_count) {
  140. draw_state.instance_count++;
  141. draw_state.draw_mode = DrawMode::Instance;
  142. }
  143. draw_state.topology = regs.draw.topology;
  144. }
  145. void DrawManager::DrawEnd(u32 instance_count, bool force_draw) {
  146. const auto& regs{maxwell3d->regs};
  147. switch (draw_state.draw_mode) {
  148. case DrawMode::Instance:
  149. if (!force_draw) {
  150. break;
  151. }
  152. [[fallthrough]];
  153. case DrawMode::General:
  154. draw_state.base_instance = regs.global_base_instance_index;
  155. draw_state.base_index = regs.global_base_vertex_index;
  156. if (draw_state.draw_indexed) {
  157. draw_state.index_buffer = regs.index_buffer;
  158. ProcessDraw(true, instance_count);
  159. } else {
  160. draw_state.vertex_buffer = regs.vertex_buffer;
  161. ProcessDraw(false, instance_count);
  162. }
  163. draw_state.draw_indexed = false;
  164. break;
  165. case DrawMode::InlineIndex:
  166. draw_state.base_instance = regs.global_base_instance_index;
  167. draw_state.base_index = regs.global_base_vertex_index;
  168. draw_state.index_buffer = regs.index_buffer;
  169. draw_state.index_buffer.count =
  170. static_cast<u32>(draw_state.inline_index_draw_indexes.size() / 4);
  171. draw_state.index_buffer.format = Maxwell3D::Regs::IndexFormat::UnsignedInt;
  172. maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
  173. ProcessDraw(true, instance_count);
  174. draw_state.inline_index_draw_indexes.clear();
  175. break;
  176. }
  177. }
  178. void DrawManager::DrawIndexSmall(u32 argument) {
  179. const auto& regs{maxwell3d->regs};
  180. IndexBufferSmall index_small_params{argument};
  181. draw_state.base_instance = regs.global_base_instance_index;
  182. draw_state.base_index = regs.global_base_vertex_index;
  183. draw_state.index_buffer = regs.index_buffer;
  184. draw_state.index_buffer.first = index_small_params.first;
  185. draw_state.index_buffer.count = index_small_params.count;
  186. draw_state.topology = index_small_params.topology;
  187. maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
  188. ProcessDraw(true, 1);
  189. }
  190. void DrawManager::DrawTexture() {
  191. const auto& regs{maxwell3d->regs};
  192. draw_texture_state.dst_x0 = static_cast<float>(regs.draw_texture.dst_x0) / 4096.f;
  193. draw_texture_state.dst_y0 = static_cast<float>(regs.draw_texture.dst_y0) / 4096.f;
  194. const auto dst_width = static_cast<float>(regs.draw_texture.dst_width) / 4096.f;
  195. const auto dst_height = static_cast<float>(regs.draw_texture.dst_height) / 4096.f;
  196. const bool lower_left{regs.window_origin.mode !=
  197. Maxwell3D::Regs::WindowOrigin::Mode::UpperLeft};
  198. if (lower_left) {
  199. draw_texture_state.dst_y0 -= dst_height;
  200. }
  201. draw_texture_state.dst_x1 =
  202. draw_texture_state.dst_x0 +
  203. static_cast<f32>(Settings::values.resolution_info.ScaleUp(static_cast<u32>(dst_width)));
  204. draw_texture_state.dst_y1 =
  205. draw_texture_state.dst_y0 +
  206. static_cast<f32>(Settings::values.resolution_info.ScaleUp(static_cast<u32>(dst_height)));
  207. draw_texture_state.src_x0 = static_cast<float>(regs.draw_texture.src_x0) / 4096.f;
  208. draw_texture_state.src_y0 = static_cast<float>(regs.draw_texture.src_y0) / 4096.f;
  209. draw_texture_state.src_x1 =
  210. (static_cast<float>(regs.draw_texture.dx_du) / 4294967296.f) * dst_width +
  211. draw_texture_state.src_x0;
  212. draw_texture_state.src_y1 =
  213. (static_cast<float>(regs.draw_texture.dy_dv) / 4294967296.f) * dst_height +
  214. draw_texture_state.src_y0;
  215. draw_texture_state.src_sampler = regs.draw_texture.src_sampler;
  216. draw_texture_state.src_texture = regs.draw_texture.src_texture;
  217. maxwell3d->rasterizer->DrawTexture();
  218. }
  219. void DrawManager::UpdateTopology() {
  220. const auto& regs{maxwell3d->regs};
  221. switch (regs.primitive_topology_control) {
  222. case PrimitiveTopologyControl::UseInBeginMethods:
  223. break;
  224. case PrimitiveTopologyControl::UseSeparateState:
  225. switch (regs.topology_override) {
  226. case PrimitiveTopologyOverride::None:
  227. break;
  228. case PrimitiveTopologyOverride::Points:
  229. draw_state.topology = PrimitiveTopology::Points;
  230. break;
  231. case PrimitiveTopologyOverride::Lines:
  232. draw_state.topology = PrimitiveTopology::Lines;
  233. break;
  234. case PrimitiveTopologyOverride::LineStrip:
  235. draw_state.topology = PrimitiveTopology::LineStrip;
  236. break;
  237. default:
  238. draw_state.topology = static_cast<PrimitiveTopology>(regs.topology_override);
  239. break;
  240. }
  241. break;
  242. }
  243. }
  244. void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) {
  245. LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology,
  246. draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count);
  247. UpdateTopology();
  248. if (maxwell3d->ShouldExecute()) {
  249. maxwell3d->rasterizer->Draw(draw_indexed, instance_count);
  250. }
  251. }
  252. void DrawManager::ProcessDrawIndirect() {
  253. LOG_TRACE(
  254. HW_GPU,
  255. "called, topology={}, is_indexed={}, includes_count={}, buffer_size={}, max_draw_count={}",
  256. draw_state.topology, indirect_state.is_indexed, indirect_state.include_count,
  257. indirect_state.buffer_size, indirect_state.max_draw_counts);
  258. UpdateTopology();
  259. if (maxwell3d->ShouldExecute()) {
  260. maxwell3d->rasterizer->DrawIndirect();
  261. }
  262. }
  263. } // namespace Tegra::Engines