convert.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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 <cstring>
  6. #include <tuple>
  7. #include <vector>
  8. #include "common/assert.h"
  9. #include "common/common_types.h"
  10. #include "common/logging/log.h"
  11. #include "video_core/surface.h"
  12. #include "video_core/textures/astc.h"
  13. #include "video_core/textures/convert.h"
  14. namespace Tegra::Texture {
  15. using VideoCore::Surface::PixelFormat;
  16. template <bool reverse>
  17. void SwapS8Z24ToZ24S8(u8* data, u32 width, u32 height) {
  18. union S8Z24 {
  19. BitField<0, 24, u32> z24;
  20. BitField<24, 8, u32> s8;
  21. };
  22. static_assert(sizeof(S8Z24) == 4, "S8Z24 is incorrect size");
  23. union Z24S8 {
  24. BitField<0, 8, u32> s8;
  25. BitField<8, 24, u32> z24;
  26. };
  27. static_assert(sizeof(Z24S8) == 4, "Z24S8 is incorrect size");
  28. S8Z24 s8z24_pixel{};
  29. Z24S8 z24s8_pixel{};
  30. constexpr auto bpp{
  31. VideoCore::Surface::GetBytesPerPixel(VideoCore::Surface::PixelFormat::S8_UINT_D24_UNORM)};
  32. for (std::size_t y = 0; y < height; ++y) {
  33. for (std::size_t x = 0; x < width; ++x) {
  34. const std::size_t offset{bpp * (y * width + x)};
  35. if constexpr (reverse) {
  36. std::memcpy(&z24s8_pixel, &data[offset], sizeof(Z24S8));
  37. s8z24_pixel.s8.Assign(z24s8_pixel.s8);
  38. s8z24_pixel.z24.Assign(z24s8_pixel.z24);
  39. std::memcpy(&data[offset], &s8z24_pixel, sizeof(S8Z24));
  40. } else {
  41. std::memcpy(&s8z24_pixel, &data[offset], sizeof(S8Z24));
  42. z24s8_pixel.s8.Assign(s8z24_pixel.s8);
  43. z24s8_pixel.z24.Assign(s8z24_pixel.z24);
  44. std::memcpy(&data[offset], &z24s8_pixel, sizeof(Z24S8));
  45. }
  46. }
  47. }
  48. }
  49. static void ConvertS8Z24ToZ24S8(u8* data, u32 width, u32 height) {
  50. SwapS8Z24ToZ24S8<false>(data, width, height);
  51. }
  52. static void ConvertZ24S8ToS8Z24(u8* data, u32 width, u32 height) {
  53. SwapS8Z24ToZ24S8<true>(data, width, height);
  54. }
  55. void ConvertFromGuestToHost(u8* in_data, u8* out_data, PixelFormat pixel_format, u32 width,
  56. u32 height, u32 depth, bool convert_astc, bool convert_s8z24) {
  57. if (convert_astc && IsPixelFormatASTC(pixel_format)) {
  58. // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC.
  59. u32 block_width{};
  60. u32 block_height{};
  61. std::tie(block_width, block_height) = GetASTCBlockSize(pixel_format);
  62. const std::vector<u8> rgba8_data = Tegra::Texture::ASTC::Decompress(
  63. in_data, width, height, depth, block_width, block_height);
  64. std::copy(rgba8_data.begin(), rgba8_data.end(), out_data);
  65. } else if (convert_s8z24 && pixel_format == PixelFormat::S8_UINT_D24_UNORM) {
  66. Tegra::Texture::ConvertS8Z24ToZ24S8(in_data, width, height);
  67. }
  68. }
  69. void ConvertFromHostToGuest(u8* data, PixelFormat pixel_format, u32 width, u32 height, u32 depth,
  70. bool convert_astc, bool convert_s8z24) {
  71. if (convert_astc && IsPixelFormatASTC(pixel_format)) {
  72. LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented",
  73. static_cast<u32>(pixel_format));
  74. UNREACHABLE();
  75. } else if (convert_s8z24 && pixel_format == PixelFormat::S8_UINT_D24_UNORM) {
  76. Tegra::Texture::ConvertZ24S8ToS8Z24(data, width, height);
  77. }
  78. }
  79. } // namespace Tegra::Texture