draw_manager.cpp 10 KB

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