summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/cityhash.cpp178
-rw-r--r--src/common/cityhash.h34
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp7
-rw-r--r--src/input_common/sdl/sdl_impl.cpp7
-rw-r--r--src/tests/CMakeLists.txt1
-rw-r--r--src/tests/common/cityhash.cpp22
-rw-r--r--src/video_core/cdma_pusher.cpp63
-rw-r--r--src/video_core/cdma_pusher.h33
-rw-r--r--src/video_core/command_classes/codecs/codec.cpp7
-rw-r--r--src/video_core/command_classes/nvdec.cpp8
-rw-r--r--src/video_core/command_classes/nvdec.h2
-rw-r--r--src/video_core/command_classes/vic.cpp45
-rw-r--r--src/video_core/command_classes/vic.h51
-rw-r--r--src/video_core/gpu.cpp6
-rw-r--r--src/video_core/gpu_thread.cpp3
16 files changed, 200 insertions, 270 deletions
diff --git a/src/common/cityhash.cpp b/src/common/cityhash.cpp
index 4e1d874b5..66218fc21 100644
--- a/src/common/cityhash.cpp
+++ b/src/common/cityhash.cpp
@@ -28,8 +28,10 @@
// compromising on hash quality.
#include <algorithm>
-#include <string.h> // for memcpy and memset
-#include "cityhash.h"
+#include <cstring>
+#include <utility>
+
+#include "common/cityhash.h"
#include "common/swap.h"
// #include "config.h"
@@ -42,21 +44,17 @@
using namespace std;
-typedef uint8_t uint8;
-typedef uint32_t uint32;
-typedef uint64_t uint64;
-
namespace Common {
-static uint64 UNALIGNED_LOAD64(const char* p) {
- uint64 result;
- memcpy(&result, p, sizeof(result));
+static u64 unaligned_load64(const char* p) {
+ u64 result;
+ std::memcpy(&result, p, sizeof(result));
return result;
}
-static uint32 UNALIGNED_LOAD32(const char* p) {
- uint32 result;
- memcpy(&result, p, sizeof(result));
+static u32 unaligned_load32(const char* p) {
+ u32 result;
+ std::memcpy(&result, p, sizeof(result));
return result;
}
@@ -76,64 +74,64 @@ static uint32 UNALIGNED_LOAD32(const char* p) {
#endif
#endif
-static uint64 Fetch64(const char* p) {
- return uint64_in_expected_order(UNALIGNED_LOAD64(p));
+static u64 Fetch64(const char* p) {
+ return uint64_in_expected_order(unaligned_load64(p));
}
-static uint32 Fetch32(const char* p) {
- return uint32_in_expected_order(UNALIGNED_LOAD32(p));
+static u32 Fetch32(const char* p) {
+ return uint32_in_expected_order(unaligned_load32(p));
}
// Some primes between 2^63 and 2^64 for various uses.
-static const uint64 k0 = 0xc3a5c85c97cb3127ULL;
-static const uint64 k1 = 0xb492b66fbe98f273ULL;
-static const uint64 k2 = 0x9ae16a3b2f90404fULL;
+static constexpr u64 k0 = 0xc3a5c85c97cb3127ULL;
+static constexpr u64 k1 = 0xb492b66fbe98f273ULL;
+static constexpr u64 k2 = 0x9ae16a3b2f90404fULL;
// Bitwise right rotate. Normally this will compile to a single
// instruction, especially if the shift is a manifest constant.
-static uint64 Rotate(uint64 val, int shift) {
+static u64 Rotate(u64 val, int shift) {
// Avoid shifting by 64: doing so yields an undefined result.
return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
}
-static uint64 ShiftMix(uint64 val) {
+static u64 ShiftMix(u64 val) {
return val ^ (val >> 47);
}
-static uint64 HashLen16(uint64 u, uint64 v) {
- return Hash128to64(uint128(u, v));
+static u64 HashLen16(u64 u, u64 v) {
+ return Hash128to64(u128{u, v});
}
-static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
+static u64 HashLen16(u64 u, u64 v, u64 mul) {
// Murmur-inspired hashing.
- uint64 a = (u ^ v) * mul;
+ u64 a = (u ^ v) * mul;
a ^= (a >> 47);
- uint64 b = (v ^ a) * mul;
+ u64 b = (v ^ a) * mul;
b ^= (b >> 47);
b *= mul;
return b;
}
-static uint64 HashLen0to16(const char* s, std::size_t len) {
+static u64 HashLen0to16(const char* s, size_t len) {
if (len >= 8) {
- uint64 mul = k2 + len * 2;
- uint64 a = Fetch64(s) + k2;
- uint64 b = Fetch64(s + len - 8);
- uint64 c = Rotate(b, 37) * mul + a;
- uint64 d = (Rotate(a, 25) + b) * mul;
+ u64 mul = k2 + len * 2;
+ u64 a = Fetch64(s) + k2;
+ u64 b = Fetch64(s + len - 8);
+ u64 c = Rotate(b, 37) * mul + a;
+ u64 d = (Rotate(a, 25) + b) * mul;
return HashLen16(c, d, mul);
}
if (len >= 4) {
- uint64 mul = k2 + len * 2;
- uint64 a = Fetch32(s);
+ u64 mul = k2 + len * 2;
+ u64 a = Fetch32(s);
return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
}
if (len > 0) {
- uint8 a = s[0];
- uint8 b = s[len >> 1];
- uint8 c = s[len - 1];
- uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8);
- uint32 z = static_cast<uint32>(len) + (static_cast<uint32>(c) << 2);
+ u8 a = s[0];
+ u8 b = s[len >> 1];
+ u8 c = s[len - 1];
+ u32 y = static_cast<u32>(a) + (static_cast<u32>(b) << 8);
+ u32 z = static_cast<u32>(len) + (static_cast<u32>(c) << 2);
return ShiftMix(y * k2 ^ z * k0) * k2;
}
return k2;
@@ -141,22 +139,21 @@ static uint64 HashLen0to16(const char* s, std::size_t len) {
// This probably works well for 16-byte strings as well, but it may be overkill
// in that case.
-static uint64 HashLen17to32(const char* s, std::size_t len) {
- uint64 mul = k2 + len * 2;
- uint64 a = Fetch64(s) * k1;
- uint64 b = Fetch64(s + 8);
- uint64 c = Fetch64(s + len - 8) * mul;
- uint64 d = Fetch64(s + len - 16) * k2;
+static u64 HashLen17to32(const char* s, size_t len) {
+ u64 mul = k2 + len * 2;
+ u64 a = Fetch64(s) * k1;
+ u64 b = Fetch64(s + 8);
+ u64 c = Fetch64(s + len - 8) * mul;
+ u64 d = Fetch64(s + len - 16) * k2;
return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d, a + Rotate(b + k2, 18) + c, mul);
}
// Return a 16-byte hash for 48 bytes. Quick and dirty.
// Callers do best to use "random-looking" values for a and b.
-static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y, uint64 z, uint64 a,
- uint64 b) {
+static pair<u64, u64> WeakHashLen32WithSeeds(u64 w, u64 x, u64 y, u64 z, u64 a, u64 b) {
a += w;
b = Rotate(b + a + z, 21);
- uint64 c = a;
+ u64 c = a;
a += x;
a += y;
b += Rotate(a, 44);
@@ -164,34 +161,34 @@ static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y,
}
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
-static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint64 b) {
+static pair<u64, u64> WeakHashLen32WithSeeds(const char* s, u64 a, u64 b) {
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
b);
}
// Return an 8-byte hash for 33 to 64 bytes.
-static uint64 HashLen33to64(const char* s, std::size_t len) {
- uint64 mul = k2 + len * 2;
- uint64 a = Fetch64(s) * k2;
- uint64 b = Fetch64(s + 8);
- uint64 c = Fetch64(s + len - 24);
- uint64 d = Fetch64(s + len - 32);
- uint64 e = Fetch64(s + 16) * k2;
- uint64 f = Fetch64(s + 24) * 9;
- uint64 g = Fetch64(s + len - 8);
- uint64 h = Fetch64(s + len - 16) * mul;
- uint64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
- uint64 v = ((a + g) ^ d) + f + 1;
- uint64 w = swap64((u + v) * mul) + h;
- uint64 x = Rotate(e + f, 42) + c;
- uint64 y = (swap64((v + w) * mul) + g) * mul;
- uint64 z = e + f + c;
+static u64 HashLen33to64(const char* s, size_t len) {
+ u64 mul = k2 + len * 2;
+ u64 a = Fetch64(s) * k2;
+ u64 b = Fetch64(s + 8);
+ u64 c = Fetch64(s + len - 24);
+ u64 d = Fetch64(s + len - 32);
+ u64 e = Fetch64(s + 16) * k2;
+ u64 f = Fetch64(s + 24) * 9;
+ u64 g = Fetch64(s + len - 8);
+ u64 h = Fetch64(s + len - 16) * mul;
+ u64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
+ u64 v = ((a + g) ^ d) + f + 1;
+ u64 w = swap64((u + v) * mul) + h;
+ u64 x = Rotate(e + f, 42) + c;
+ u64 y = (swap64((v + w) * mul) + g) * mul;
+ u64 z = e + f + c;
a = swap64((x + z) * mul + y) + b;
b = ShiftMix((z + a) * mul + d + h) * mul;
return b + x;
}
-uint64 CityHash64(const char* s, std::size_t len) {
+u64 CityHash64(const char* s, size_t len) {
if (len <= 32) {
if (len <= 16) {
return HashLen0to16(s, len);
@@ -204,15 +201,15 @@ uint64 CityHash64(const char* s, std::size_t len) {
// For strings over 64 bytes we hash the end first, and then as we
// loop we keep 56 bytes of state: v, w, x, y, and z.
- uint64 x = Fetch64(s + len - 40);
- uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
- uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
- pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
- pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
+ u64 x = Fetch64(s + len - 40);
+ u64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
+ u64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
+ pair<u64, u64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
+ pair<u64, u64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
x = x * k1 + Fetch64(s);
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
- len = (len - 1) & ~static_cast<std::size_t>(63);
+ len = (len - 1) & ~static_cast<size_t>(63);
do {
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
@@ -229,21 +226,21 @@ uint64 CityHash64(const char* s, std::size_t len) {
HashLen16(v.second, w.second) + x);
}
-uint64 CityHash64WithSeed(const char* s, std::size_t len, uint64 seed) {
+u64 CityHash64WithSeed(const char* s, size_t len, u64 seed) {
return CityHash64WithSeeds(s, len, k2, seed);
}
-uint64 CityHash64WithSeeds(const char* s, std::size_t len, uint64 seed0, uint64 seed1) {
+u64 CityHash64WithSeeds(const char* s, size_t len, u64 seed0, u64 seed1) {
return HashLen16(CityHash64(s, len) - seed0, seed1);
}
// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
// of any length representable in signed long. Based on City and Murmur.
-static uint128 CityMurmur(const char* s, std::size_t len, uint128 seed) {
- uint64 a = Uint128Low64(seed);
- uint64 b = Uint128High64(seed);
- uint64 c = 0;
- uint64 d = 0;
+static u128 CityMurmur(const char* s, size_t len, u128 seed) {
+ u64 a = seed[0];
+ u64 b = seed[1];
+ u64 c = 0;
+ u64 d = 0;
signed long l = static_cast<long>(len) - 16;
if (l <= 0) { // len <= 16
a = ShiftMix(a * k1) * k1;
@@ -266,20 +263,20 @@ static uint128 CityMurmur(const char* s, std::size_t len, uint128 seed) {
}
a = HashLen16(a, c);
b = HashLen16(d, b);
- return uint128(a ^ b, HashLen16(b, a));
+ return u128{a ^ b, HashLen16(b, a)};
}
-uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
+u128 CityHash128WithSeed(const char* s, size_t len, u128 seed) {
if (len < 128) {
return CityMurmur(s, len, seed);
}
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
// v, w, x, y, and z.
- pair<uint64, uint64> v, w;
- uint64 x = Uint128Low64(seed);
- uint64 y = Uint128High64(seed);
- uint64 z = len * k1;
+ pair<u64, u64> v, w;
+ u64 x = seed[0];
+ u64 y = seed[1];
+ u64 z = len * k1;
v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
w.first = Rotate(y + z, 35) * k1 + x;
@@ -313,7 +310,7 @@ uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
w.first *= 9;
v.first *= k0;
// If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
- for (std::size_t tail_done = 0; tail_done < len;) {
+ for (size_t tail_done = 0; tail_done < len;) {
tail_done += 32;
y = Rotate(x + y, 42) * k0 + v.second;
w.first += Fetch64(s + len - tail_done + 16);
@@ -328,13 +325,12 @@ uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
// different 56-byte-to-8-byte hashes to get a 16-byte final result.
x = HashLen16(x, v.first);
y = HashLen16(y + z, w.first);
- return uint128(HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second));
+ return u128{HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second)};
}
-uint128 CityHash128(const char* s, std::size_t len) {
- return len >= 16
- ? CityHash128WithSeed(s + 16, len - 16, uint128(Fetch64(s), Fetch64(s + 8) + k0))
- : CityHash128WithSeed(s, len, uint128(k0, k1));
+u128 CityHash128(const char* s, size_t len) {
+ return len >= 16 ? CityHash128WithSeed(s + 16, len - 16, u128{Fetch64(s), Fetch64(s + 8) + k0})
+ : CityHash128WithSeed(s, len, u128{k0, k1});
}
} // namespace Common
diff --git a/src/common/cityhash.h b/src/common/cityhash.h
index a00804e01..022d0f7cb 100644
--- a/src/common/cityhash.h
+++ b/src/common/cityhash.h
@@ -61,50 +61,38 @@
#pragma once
-#include <cstddef>
-#include <cstdint>
-#include <utility>
+#include "common/common_types.h"
namespace Common {
-using uint128 = std::pair<uint64_t, uint64_t>;
-
-[[nodiscard]] inline uint64_t Uint128Low64(const uint128& x) {
- return x.first;
-}
-[[nodiscard]] inline uint64_t Uint128High64(const uint128& x) {
- return x.second;
-}
-
// Hash function for a byte array.
-[[nodiscard]] uint64_t CityHash64(const char* buf, std::size_t len);
+[[nodiscard]] u64 CityHash64(const char* buf, size_t len);
// Hash function for a byte array. For convenience, a 64-bit seed is also
// hashed into the result.
-[[nodiscard]] uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
+[[nodiscard]] u64 CityHash64WithSeed(const char* buf, size_t len, u64 seed);
// Hash function for a byte array. For convenience, two seeds are also
// hashed into the result.
-[[nodiscard]] uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0,
- uint64_t seed1);
+[[nodiscard]] u64 CityHash64WithSeeds(const char* buf, size_t len, u64 seed0, u64 seed1);
// Hash function for a byte array.
-[[nodiscard]] uint128 CityHash128(const char* s, std::size_t len);
+[[nodiscard]] u128 CityHash128(const char* s, size_t len);
// Hash function for a byte array. For convenience, a 128-bit seed is also
// hashed into the result.
-[[nodiscard]] uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
+[[nodiscard]] u128 CityHash128WithSeed(const char* s, size_t len, u128 seed);
// Hash 128 input bits down to 64 bits of output.
// This is intended to be a reasonably good hash function.
-[[nodiscard]] inline uint64_t Hash128to64(const uint128& x) {
+[[nodiscard]] inline u64 Hash128to64(const u128& x) {
// Murmur-inspired hashing.
- const uint64_t kMul = 0x9ddfea08eb382d69ULL;
- uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
+ const u64 mul = 0x9ddfea08eb382d69ULL;
+ u64 a = (x[0] ^ x[1]) * mul;
a ^= (a >> 47);
- uint64_t b = (Uint128High64(x) ^ a) * kMul;
+ u64 b = (x[1] ^ a) * mul;
b ^= (b >> 47);
- b *= kMul;
+ b *= mul;
return b;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 36970f828..ecba1dba1 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -34,8 +34,7 @@ NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input,
case 0xa: {
if (command.length == 0x1c) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
- Tegra::ChCommandHeaderList cmdlist(1);
- cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
+ Tegra::ChCommandHeaderList cmdlist{{0xDEADB33F}};
system.GPU().PushCommandBuffer(cmdlist);
}
return UnmapBuffer(input, output);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 72499654c..70849a9bd 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -28,8 +28,13 @@ NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::ve
return GetWaitbase(input, output);
case 0x9:
return MapBuffer(input, output);
- case 0xa:
+ case 0xa: {
+ if (command.length == 0x1c) {
+ Tegra::ChCommandHeaderList cmdlist{{0xDEADB33F}};
+ system.GPU().PushCommandBuffer(cmdlist);
+ }
return UnmapBuffer(input, output);
+ }
default:
break;
}
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index a88ae452f..f67de37e3 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -717,13 +717,6 @@ SDLState::SDLState() {
if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
}
-// these hints are only defined on sdl2.0.9 or higher
-#if SDL_VERSION_ATLEAST(2, 0, 9)
-#if !SDL_VERSION_ATLEAST(2, 0, 12)
- // There are also hints to toggle the individual drivers if needed.
- SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI, "0");
-#endif
-#endif
SDL_AddEventWatch(&SDLEventWatcher, this);
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 6a5c18945..4ea0076e9 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -1,5 +1,6 @@
add_executable(tests
common/bit_field.cpp
+ common/cityhash.cpp
common/fibers.cpp
common/param_package.cpp
common/ring_buffer.cpp
diff --git a/src/tests/common/cityhash.cpp b/src/tests/common/cityhash.cpp
new file mode 100644
index 000000000..7a40b6c4a
--- /dev/null
+++ b/src/tests/common/cityhash.cpp
@@ -0,0 +1,22 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <catch2/catch.hpp>
+
+#include "common/cityhash.h"
+
+constexpr char msg[] = "The blue frogs are singing under the crimson sky.\n"
+ "It is time to run, Robert.";
+
+using namespace Common;
+
+TEST_CASE("CityHash", "[common]") {
+ // These test results were built against a known good version.
+ REQUIRE(CityHash64(msg, sizeof(msg)) == 0x92d5c2e9cbfbbc01);
+ REQUIRE(CityHash64WithSeed(msg, sizeof(msg), 0xdead) == 0xbfbe93f21a2820dd);
+ REQUIRE(CityHash64WithSeeds(msg, sizeof(msg), 0xbeef, 0xcafe) == 0xb343317955fc8a06);
+ REQUIRE(CityHash128(msg, sizeof(msg)) == u128{0x98e60d0423747eaa, 0xd8694c5b6fcaede9});
+ REQUIRE(CityHash128WithSeed(msg, sizeof(msg), {0xdead, 0xbeef}) ==
+ u128{0xf0307dba81199ebe, 0xd77764e0c4a9eb74});
+}
diff --git a/src/video_core/cdma_pusher.cpp b/src/video_core/cdma_pusher.cpp
index 33b3c060b..a3fda1094 100644
--- a/src/video_core/cdma_pusher.cpp
+++ b/src/video_core/cdma_pusher.cpp
@@ -37,59 +37,43 @@ CDmaPusher::CDmaPusher(GPU& gpu_)
CDmaPusher::~CDmaPusher() = default;
-void CDmaPusher::Push(ChCommandHeaderList&& entries) {
- cdma_queue.push(std::move(entries));
-}
-
-void CDmaPusher::DispatchCalls() {
- while (!cdma_queue.empty()) {
- Step();
- }
-}
-
-void CDmaPusher::Step() {
- const auto entries{cdma_queue.front()};
- cdma_queue.pop();
-
- std::vector<u32> values(entries.size());
- std::memcpy(values.data(), entries.data(), entries.size() * sizeof(u32));
-
- for (const u32 value : values) {
+void CDmaPusher::ProcessEntries(ChCommandHeaderList&& entries) {
+ for (const auto& value : entries) {
if (mask != 0) {
const auto lbs = static_cast<u32>(std::countr_zero(mask));
mask &= ~(1U << lbs);
- ExecuteCommand(static_cast<u32>(offset + lbs), value);
+ ExecuteCommand(offset + lbs, value.raw);
continue;
} else if (count != 0) {
--count;
- ExecuteCommand(static_cast<u32>(offset), value);
+ ExecuteCommand(offset, value.raw);
if (incrementing) {
++offset;
}
continue;
}
- const auto mode = static_cast<ChSubmissionMode>((value >> 28) & 0xf);
+ const auto mode = value.submission_mode.Value();
switch (mode) {
case ChSubmissionMode::SetClass: {
- mask = value & 0x3f;
- offset = (value >> 16) & 0xfff;
- current_class = static_cast<ChClassId>((value >> 6) & 0x3ff);
+ mask = value.value & 0x3f;
+ offset = value.method_offset;
+ current_class = static_cast<ChClassId>((value.value >> 6) & 0x3ff);
break;
}
case ChSubmissionMode::Incrementing:
case ChSubmissionMode::NonIncrementing:
- count = value & 0xffff;
- offset = (value >> 16) & 0xfff;
+ count = value.value;
+ offset = value.method_offset;
incrementing = mode == ChSubmissionMode::Incrementing;
break;
case ChSubmissionMode::Mask:
- mask = value & 0xffff;
- offset = (value >> 16) & 0xfff;
+ mask = value.value;
+ offset = value.method_offset;
break;
case ChSubmissionMode::Immediate: {
- const u32 data = value & 0xfff;
- offset = (value >> 16) & 0xfff;
- ExecuteCommand(static_cast<u32>(offset), data);
+ const u32 data = value.value & 0xfff;
+ offset = value.method_offset;
+ ExecuteCommand(offset, data);
break;
}
default:
@@ -102,8 +86,8 @@ void CDmaPusher::Step() {
void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
switch (current_class) {
case ChClassId::NvDec:
- ThiStateWrite(nvdec_thi_state, state_offset, {data});
- switch (static_cast<ThiMethod>(state_offset)) {
+ ThiStateWrite(nvdec_thi_state, offset, data);
+ switch (static_cast<ThiMethod>(offset)) {
case ThiMethod::IncSyncpt: {
LOG_DEBUG(Service_NVDRV, "NVDEC Class IncSyncpt Method");
const auto syncpoint_id = static_cast<u32>(data & 0xFF);
@@ -120,7 +104,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
LOG_DEBUG(Service_NVDRV, "NVDEC method 0x{:X}",
static_cast<u32>(nvdec_thi_state.method_0));
nvdec_processor->ProcessMethod(static_cast<Nvdec::Method>(nvdec_thi_state.method_0),
- {data});
+ data);
break;
default:
break;
@@ -144,7 +128,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
case ThiMethod::SetMethod1:
LOG_DEBUG(Service_NVDRV, "VIC method 0x{:X}, Args=({})",
static_cast<u32>(vic_thi_state.method_0), data);
- vic_processor->ProcessMethod(static_cast<Vic::Method>(vic_thi_state.method_0), {data});
+ vic_processor->ProcessMethod(static_cast<Vic::Method>(vic_thi_state.method_0), data);
break;
default:
break;
@@ -153,7 +137,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
case ChClassId::Host1x:
// This device is mainly for syncpoint synchronization
LOG_DEBUG(Service_NVDRV, "Host1X Class Method");
- host1x_processor->ProcessMethod(static_cast<Host1x::Method>(state_offset), {data});
+ host1x_processor->ProcessMethod(static_cast<Host1x::Method>(offset), data);
break;
default:
UNIMPLEMENTED_MSG("Current class not implemented {:X}", static_cast<u32>(current_class));
@@ -161,10 +145,9 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
}
}
-void CDmaPusher::ThiStateWrite(ThiRegisters& state, u32 state_offset,
- const std::vector<u32>& arguments) {
- u8* const state_offset_ptr = reinterpret_cast<u8*>(&state) + sizeof(u32) * state_offset;
- std::memcpy(state_offset_ptr, arguments.data(), sizeof(u32) * arguments.size());
+void CDmaPusher::ThiStateWrite(ThiRegisters& state, u32 state_offset, u32 argument) {
+ u8* const offset_ptr = reinterpret_cast<u8*>(&state) + sizeof(u32) * state_offset;
+ std::memcpy(offset_ptr, &argument, sizeof(u32));
}
} // namespace Tegra
diff --git a/src/video_core/cdma_pusher.h b/src/video_core/cdma_pusher.h
index e5f212c1a..1bada44dd 100644
--- a/src/video_core/cdma_pusher.h
+++ b/src/video_core/cdma_pusher.h
@@ -5,9 +5,7 @@
#pragma once
#include <memory>
-#include <unordered_map>
#include <vector>
-#include <queue>
#include "common/bit_field.h"
#include "common/common_types.h"
@@ -16,9 +14,9 @@
namespace Tegra {
class GPU;
+class Host1x;
class Nvdec;
class Vic;
-class Host1x;
enum class ChSubmissionMode : u32 {
SetClass = 0,
@@ -48,16 +46,10 @@ enum class ChClassId : u32 {
NvDec = 0xf0
};
-enum class ChMethod : u32 {
- Empty = 0,
- SetMethod = 0x10,
- SetData = 0x11,
-};
-
union ChCommandHeader {
u32 raw;
BitField<0, 16, u32> value;
- BitField<16, 12, ChMethod> method_offset;
+ BitField<16, 12, u32> method_offset;
BitField<28, 4, ChSubmissionMode> submission_mode;
};
static_assert(sizeof(ChCommandHeader) == sizeof(u32), "ChCommand header is an invalid size");
@@ -99,21 +91,15 @@ public:
explicit CDmaPusher(GPU& gpu_);
~CDmaPusher();
- /// Push NVDEC command buffer entries into queue
- void Push(ChCommandHeaderList&& entries);
-
- /// Process queued command buffer entries
- void DispatchCalls();
-
- /// Process one queue element
- void Step();
+ /// Process the command entry
+ void ProcessEntries(ChCommandHeaderList&& entries);
+private:
/// Invoke command class devices to execute the command based on the current state
void ExecuteCommand(u32 state_offset, u32 data);
-private:
/// Write arguments value to the ThiRegisters member at the specified offset
- void ThiStateWrite(ThiRegisters& state, u32 state_offset, const std::vector<u32>& arguments);
+ void ThiStateWrite(ThiRegisters& state, u32 offset, u32 argument);
GPU& gpu;
std::shared_ptr<Tegra::Nvdec> nvdec_processor;
@@ -124,13 +110,10 @@ private:
ThiRegisters vic_thi_state{};
ThiRegisters nvdec_thi_state{};
- s32 count{};
- s32 offset{};
+ u32 count{};
+ u32 offset{};
u32 mask{};
bool incrementing{};
-
- // Queue of command lists to be processed
- std::queue<ChCommandHeaderList> cdma_queue;
};
} // namespace Tegra
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp
index 39bc923a5..d02dc6260 100644
--- a/src/video_core/command_classes/codecs/codec.cpp
+++ b/src/video_core/command_classes/codecs/codec.cpp
@@ -44,8 +44,10 @@ Codec::~Codec() {
}
void Codec::SetTargetCodec(NvdecCommon::VideoCodec codec) {
- LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", codec);
- current_codec = codec;
+ if (current_codec != codec) {
+ LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", static_cast<u32>(codec));
+ current_codec = codec;
+ }
}
void Codec::StateWrite(u32 offset, u64 arguments) {
@@ -55,7 +57,6 @@ void Codec::StateWrite(u32 offset, u64 arguments) {
void Codec::Decode() {
bool is_first_frame = false;
-
if (!initialized) {
if (current_codec == NvdecCommon::VideoCodec::H264) {
av_codec = avcodec_find_decoder(AV_CODEC_ID_H264);
diff --git a/src/video_core/command_classes/nvdec.cpp b/src/video_core/command_classes/nvdec.cpp
index 79e1f4e13..e4f919afd 100644
--- a/src/video_core/command_classes/nvdec.cpp
+++ b/src/video_core/command_classes/nvdec.cpp
@@ -12,16 +12,16 @@ Nvdec::Nvdec(GPU& gpu_) : gpu(gpu_), codec(std::make_unique<Codec>(gpu)) {}
Nvdec::~Nvdec() = default;
-void Nvdec::ProcessMethod(Method method, const std::vector<u32>& arguments) {
+void Nvdec::ProcessMethod(Method method, u32 argument) {
if (method == Method::SetVideoCodec) {
- codec->StateWrite(static_cast<u32>(method), arguments[0]);
+ codec->StateWrite(static_cast<u32>(method), argument);
} else {
- codec->StateWrite(static_cast<u32>(method), static_cast<u64>(arguments[0]) << 8);
+ codec->StateWrite(static_cast<u32>(method), static_cast<u64>(argument) << 8);
}
switch (method) {
case Method::SetVideoCodec:
- codec->SetTargetCodec(static_cast<NvdecCommon::VideoCodec>(arguments[0]));
+ codec->SetTargetCodec(static_cast<NvdecCommon::VideoCodec>(argument));
break;
case Method::Execute:
Execute();
diff --git a/src/video_core/command_classes/nvdec.h b/src/video_core/command_classes/nvdec.h
index e4877c533..e66be80b8 100644
--- a/src/video_core/command_classes/nvdec.h
+++ b/src/video_core/command_classes/nvdec.h
@@ -23,7 +23,7 @@ public:
~Nvdec();
/// Writes the method into the state, Invoke Execute() if encountered
- void ProcessMethod(Method method, const std::vector<u32>& arguments);
+ void ProcessMethod(Method method, u32 argument);
/// Return most recently decoded frame
[[nodiscard]] AVFramePtr GetFrame();
diff --git a/src/video_core/command_classes/vic.cpp b/src/video_core/command_classes/vic.cpp
index 2b7569335..0a8b82f2b 100644
--- a/src/video_core/command_classes/vic.cpp
+++ b/src/video_core/command_classes/vic.cpp
@@ -18,18 +18,14 @@ extern "C" {
namespace Tegra {
Vic::Vic(GPU& gpu_, std::shared_ptr<Nvdec> nvdec_processor_)
- : gpu(gpu_), nvdec_processor(std::move(nvdec_processor_)) {}
-Vic::~Vic() = default;
+ : gpu(gpu_),
+ nvdec_processor(std::move(nvdec_processor_)), converted_frame_buffer{nullptr, av_free} {}
-void Vic::VicStateWrite(u32 offset, u32 arguments) {
- u8* const state_offset = reinterpret_cast<u8*>(&vic_state) + offset * sizeof(u32);
- std::memcpy(state_offset, &arguments, sizeof(u32));
-}
+Vic::~Vic() = default;
-void Vic::ProcessMethod(Method method, const std::vector<u32>& arguments) {
- LOG_DEBUG(HW_GPU, "Vic method 0x{:X}", method);
- VicStateWrite(static_cast<u32>(method), arguments[0]);
- const u64 arg = static_cast<u64>(arguments[0]) << 8;
+void Vic::ProcessMethod(Method method, u32 argument) {
+ LOG_DEBUG(HW_GPU, "Vic method 0x{:X}", static_cast<u32>(method));
+ const u64 arg = static_cast<u64>(argument) << 8;
switch (method) {
case Method::Execute:
Execute();
@@ -53,8 +49,7 @@ void Vic::ProcessMethod(Method method, const std::vector<u32>& arguments) {
void Vic::Execute() {
if (output_surface_luma_address == 0) {
- LOG_ERROR(Service_NVDRV, "VIC Luma address not set. Received 0x{:X}",
- vic_state.output_surface.luma_offset);
+ LOG_ERROR(Service_NVDRV, "VIC Luma address not set.");
return;
}
const VicConfig config{gpu.MemoryManager().Read<u64>(config_struct_address + 0x20)};
@@ -89,8 +84,10 @@ void Vic::Execute() {
// Get Converted frame
const std::size_t linear_size = frame->width * frame->height * 4;
- using AVMallocPtr = std::unique_ptr<u8, decltype(&av_free)>;
- AVMallocPtr converted_frame_buffer{static_cast<u8*>(av_malloc(linear_size)), av_free};
+ // Only allocate frame_buffer once per stream, as the size is not expected to change
+ if (!converted_frame_buffer) {
+ converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(linear_size)), av_free};
+ }
const int converted_stride{frame->width * 4};
u8* const converted_frame_buf_addr{converted_frame_buffer.get()};
@@ -104,12 +101,12 @@ void Vic::Execute() {
const u32 block_height = static_cast<u32>(config.block_linear_height_log2);
const auto size = Tegra::Texture::CalculateSize(true, 4, frame->width, frame->height, 1,
block_height, 0);
- std::vector<u8> swizzled_data(size);
+ luma_buffer.resize(size);
Tegra::Texture::SwizzleSubrect(frame->width, frame->height, frame->width * 4,
- frame->width, 4, swizzled_data.data(),
+ frame->width, 4, luma_buffer.data(),
converted_frame_buffer.get(), block_height, 0, 0);
- gpu.MemoryManager().WriteBlock(output_surface_luma_address, swizzled_data.data(), size);
+ gpu.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(), size);
} else {
// send pitch linear frame
gpu.MemoryManager().WriteBlock(output_surface_luma_address, converted_frame_buf_addr,
@@ -132,15 +129,15 @@ void Vic::Execute() {
const auto stride = frame->linesize[0];
const auto half_stride = frame->linesize[1];
- std::vector<u8> luma_buffer(aligned_width * surface_height);
- std::vector<u8> chroma_buffer(aligned_width * half_height);
+ luma_buffer.resize(aligned_width * surface_height);
+ chroma_buffer.resize(aligned_width * half_height);
// Populate luma buffer
for (std::size_t y = 0; y < surface_height - 1; ++y) {
- std::size_t src = y * stride;
- std::size_t dst = y * aligned_width;
+ const std::size_t src = y * stride;
+ const std::size_t dst = y * aligned_width;
- std::size_t size = surface_width;
+ const std::size_t size = surface_width;
for (std::size_t offset = 0; offset < size; ++offset) {
luma_buffer[dst + offset] = luma_ptr[src + offset];
@@ -151,8 +148,8 @@ void Vic::Execute() {
// Populate chroma buffer from both channels with interleaving.
for (std::size_t y = 0; y < half_height; ++y) {
- std::size_t src = y * half_stride;
- std::size_t dst = y * aligned_width;
+ const std::size_t src = y * half_stride;
+ const std::size_t dst = y * aligned_width;
for (std::size_t x = 0; x < half_width; ++x) {
chroma_buffer[dst + x * 2] = chroma_b_ptr[src + x];
diff --git a/src/video_core/command_classes/vic.h b/src/video_core/command_classes/vic.h
index 8c4e284a1..f5a2ed100 100644
--- a/src/video_core/command_classes/vic.h
+++ b/src/video_core/command_classes/vic.h
@@ -15,43 +15,6 @@ namespace Tegra {
class GPU;
class Nvdec;
-struct PlaneOffsets {
- u32 luma_offset{};
- u32 chroma_u_offset{};
- u32 chroma_v_offset{};
-};
-
-struct VicRegisters {
- INSERT_PADDING_WORDS(64);
- u32 nop{};
- INSERT_PADDING_WORDS(15);
- u32 pm_trigger{};
- INSERT_PADDING_WORDS(47);
- u32 set_application_id{};
- u32 set_watchdog_timer{};
- INSERT_PADDING_WORDS(17);
- u32 context_save_area{};
- u32 context_switch{};
- INSERT_PADDING_WORDS(43);
- u32 execute{};
- INSERT_PADDING_WORDS(63);
- std::array<std::array<PlaneOffsets, 8>, 8> surfacex_slots{};
- u32 picture_index{};
- u32 control_params{};
- u32 config_struct_offset{};
- u32 filter_struct_offset{};
- u32 palette_offset{};
- u32 hist_offset{};
- u32 context_id{};
- u32 fce_ucode_size{};
- PlaneOffsets output_surface{};
- u32 fce_ucode_offset{};
- INSERT_PADDING_WORDS(4);
- std::array<u32, 8> slot_context_id{};
- INSERT_PADDING_WORDS(16);
-};
-static_assert(sizeof(VicRegisters) == 0x7A0, "VicRegisters is an invalid size");
-
class Vic {
public:
enum class Method : u32 {
@@ -67,14 +30,11 @@ public:
~Vic();
/// Write to the device state.
- void ProcessMethod(Method method, const std::vector<u32>& arguments);
+ void ProcessMethod(Method method, u32 argument);
private:
void Execute();
- void VicStateWrite(u32 offset, u32 arguments);
- VicRegisters vic_state{};
-
enum class VideoPixelFormat : u64_le {
RGBA8 = 0x1f,
BGRA8 = 0x20,
@@ -88,8 +48,6 @@ private:
BitField<9, 2, u64_le> chroma_loc_vert;
BitField<11, 4, u64_le> block_linear_kind;
BitField<15, 4, u64_le> block_linear_height_log2;
- BitField<19, 3, u64_le> reserved0;
- BitField<22, 10, u64_le> reserved1;
BitField<32, 14, u64_le> surface_width_minus1;
BitField<46, 14, u64_le> surface_height_minus1;
};
@@ -97,6 +55,13 @@ private:
GPU& gpu;
std::shared_ptr<Tegra::Nvdec> nvdec_processor;
+ /// Avoid reallocation of the following buffers every frame, as their
+ /// size does not change during a stream
+ using AVMallocPtr = std::unique_ptr<u8, decltype(&av_free)>;
+ AVMallocPtr converted_frame_buffer;
+ std::vector<u8> luma_buffer;
+ std::vector<u8> chroma_buffer;
+
GPUVAddr config_struct_address{};
GPUVAddr output_surface_luma_address{};
GPUVAddr output_surface_chroma_u_address{};
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 2a9bd4121..51c63af4a 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -30,8 +30,7 @@ MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
GPU::GPU(Core::System& system_, bool is_async_, bool use_nvdec_)
: system{system_}, memory_manager{std::make_unique<Tegra::MemoryManager>(system)},
- dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)},
- cdma_pusher{std::make_unique<Tegra::CDmaPusher>(*this)}, use_nvdec{use_nvdec_},
+ dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)}, use_nvdec{use_nvdec_},
maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)},
fermi_2d{std::make_unique<Engines::Fermi2D>()},
kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)},
@@ -494,8 +493,7 @@ void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) {
// TODO(ameerj): RE proper async nvdec operation
// gpu_thread.SubmitCommandBuffer(std::move(entries));
- cdma_pusher->Push(std::move(entries));
- cdma_pusher->DispatchCalls();
+ cdma_pusher->ProcessEntries(std::move(entries));
}
void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 50319f1d5..eb0e43c0c 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -48,8 +48,7 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
dma_pusher.DispatchCalls();
} else if (auto* command_list = std::get_if<SubmitChCommandEntries>(&next.data)) {
// NVDEC
- cdma_pusher.Push(std::move(command_list->entries));
- cdma_pusher.DispatchCalls();
+ cdma_pusher.ProcessEntries(std::move(command_list->entries));
} else if (const auto* data = std::get_if<SwapBuffersCommand>(&next.data)) {
renderer.SwapBuffers(data->framebuffer ? &*data->framebuffer : nullptr);
} else if (std::holds_alternative<OnCommandListEndCommand>(next.data)) {