image.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <vector>
  6. #include <fmt/format.h>
  7. #include "common/assert.h"
  8. #include "common/bit_field.h"
  9. #include "common/common_types.h"
  10. #include "common/logging/log.h"
  11. #include "video_core/engines/shader_bytecode.h"
  12. #include "video_core/shader/node_helper.h"
  13. #include "video_core/shader/shader_ir.h"
  14. namespace VideoCommon::Shader {
  15. using Tegra::Shader::Instruction;
  16. using Tegra::Shader::OpCode;
  17. namespace {
  18. std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) {
  19. switch (image_type) {
  20. case Tegra::Shader::ImageType::Texture1D:
  21. case Tegra::Shader::ImageType::TextureBuffer:
  22. return 1;
  23. case Tegra::Shader::ImageType::Texture1DArray:
  24. case Tegra::Shader::ImageType::Texture2D:
  25. return 2;
  26. case Tegra::Shader::ImageType::Texture2DArray:
  27. case Tegra::Shader::ImageType::Texture3D:
  28. return 3;
  29. }
  30. UNREACHABLE();
  31. return 1;
  32. }
  33. } // Anonymous namespace
  34. u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
  35. const Instruction instr = {program_code[pc]};
  36. const auto opcode = OpCode::Decode(instr);
  37. switch (opcode->get().GetId()) {
  38. case OpCode::Id::SUST: {
  39. UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P);
  40. UNIMPLEMENTED_IF(instr.sust.image_type == Tegra::Shader::ImageType::TextureBuffer);
  41. UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore);
  42. UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store
  43. std::vector<Node> values;
  44. constexpr std::size_t hardcoded_size{4};
  45. for (std::size_t i = 0; i < hardcoded_size; ++i) {
  46. values.push_back(GetRegister(instr.gpr0.Value() + i));
  47. }
  48. std::vector<Node> coords;
  49. const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)};
  50. for (std::size_t i = 0; i < num_coords; ++i) {
  51. coords.push_back(GetRegister(instr.gpr8.Value() + i));
  52. }
  53. const auto type{instr.sust.image_type};
  54. const auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
  55. : GetBindlessImage(instr.gpr39, type)};
  56. MetaImage meta{image, values};
  57. const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))};
  58. bb.push_back(store);
  59. break;
  60. }
  61. default:
  62. UNIMPLEMENTED_MSG("Unhandled conversion instruction: {}", opcode->get().GetName());
  63. }
  64. return pc;
  65. }
  66. const Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
  67. const auto offset{static_cast<std::size_t>(image.index.Value())};
  68. // If this image has already been used, return the existing mapping.
  69. const auto itr{std::find_if(used_images.begin(), used_images.end(),
  70. [=](const Image& entry) { return entry.GetOffset() == offset; })};
  71. if (itr != used_images.end()) {
  72. ASSERT(itr->GetType() == type);
  73. return *itr;
  74. }
  75. // Otherwise create a new mapping for this image.
  76. const std::size_t next_index{used_images.size()};
  77. const Image entry{offset, next_index, type};
  78. return *used_images.emplace(entry).first;
  79. }
  80. const Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg,
  81. Tegra::Shader::ImageType type) {
  82. const Node image_register{GetRegister(reg)};
  83. const Node base_image{
  84. TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
  85. const auto cbuf{std::get_if<CbufNode>(&*base_image)};
  86. const auto cbuf_offset_imm{std::get_if<ImmediateNode>(&*cbuf->GetOffset())};
  87. const auto cbuf_offset{cbuf_offset_imm->GetValue()};
  88. const auto cbuf_index{cbuf->GetIndex()};
  89. const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
  90. // If this image has already been used, return the existing mapping.
  91. const auto itr{std::find_if(used_images.begin(), used_images.end(),
  92. [=](const Image& entry) { return entry.GetOffset() == cbuf_key; })};
  93. if (itr != used_images.end()) {
  94. ASSERT(itr->GetType() == type);
  95. return *itr;
  96. }
  97. // Otherwise create a new mapping for this image.
  98. const std::size_t next_index{used_images.size()};
  99. const Image entry{cbuf_index, cbuf_offset, next_index, type};
  100. return *used_images.emplace(entry).first;
  101. }
  102. } // namespace VideoCommon::Shader