image.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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. auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
  55. : GetBindlessImage(instr.gpr39, type)};
  56. image.MarkWrite();
  57. MetaImage meta{image, values};
  58. const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))};
  59. bb.push_back(store);
  60. break;
  61. }
  62. default:
  63. UNIMPLEMENTED_MSG("Unhandled image instruction: {}", opcode->get().GetName());
  64. }
  65. return pc;
  66. }
  67. Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
  68. const auto offset{static_cast<u64>(image.index.Value())};
  69. // If this image has already been used, return the existing mapping.
  70. const auto it = used_images.find(offset);
  71. if (it != used_images.end()) {
  72. ASSERT(it->second.GetType() == type);
  73. return it->second;
  74. }
  75. // Otherwise create a new mapping for this image.
  76. const std::size_t next_index{used_images.size()};
  77. return used_images.emplace(offset, Image{offset, next_index, type}).first->second;
  78. }
  79. Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) {
  80. const Node image_register{GetRegister(reg)};
  81. const auto [base_image, cbuf_index, cbuf_offset]{
  82. TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
  83. const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
  84. // If this image has already been used, return the existing mapping.
  85. const auto it = used_images.find(cbuf_key);
  86. if (it != used_images.end()) {
  87. ASSERT(it->second.GetType() == type);
  88. return it->second;
  89. }
  90. // Otherwise create a new mapping for this image.
  91. const std::size_t next_index{used_images.size()};
  92. return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type})
  93. .first->second;
  94. }
  95. } // namespace VideoCommon::Shader