diff options
Diffstat (limited to 'src')
166 files changed, 5740 insertions, 3114 deletions
diff --git a/src/common/assert.h b/src/common/assert.h index 3ee07f6a2..0d4eddc19 100644 --- a/src/common/assert.h +++ b/src/common/assert.h | |||
| @@ -30,15 +30,14 @@ __declspec(noinline, noreturn) | |||
| 30 | #define ASSERT(_a_) \ | 30 | #define ASSERT(_a_) \ |
| 31 | do \ | 31 | do \ |
| 32 | if (!(_a_)) { \ | 32 | if (!(_a_)) { \ |
| 33 | assert_noinline_call([] { NGLOG_CRITICAL(Debug, "Assertion Failed!"); }); \ | 33 | assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \ |
| 34 | } \ | 34 | } \ |
| 35 | while (0) | 35 | while (0) |
| 36 | 36 | ||
| 37 | #define ASSERT_MSG(_a_, ...) \ | 37 | #define ASSERT_MSG(_a_, ...) \ |
| 38 | do \ | 38 | do \ |
| 39 | if (!(_a_)) { \ | 39 | if (!(_a_)) { \ |
| 40 | assert_noinline_call( \ | 40 | assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \ |
| 41 | [&] { NGLOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \ | ||
| 42 | } \ | 41 | } \ |
| 43 | while (0) | 42 | while (0) |
| 44 | 43 | ||
| @@ -53,5 +52,5 @@ __declspec(noinline, noreturn) | |||
| 53 | #define DEBUG_ASSERT_MSG(_a_, _desc_, ...) | 52 | #define DEBUG_ASSERT_MSG(_a_, _desc_, ...) |
| 54 | #endif | 53 | #endif |
| 55 | 54 | ||
| 56 | #define UNIMPLEMENTED() DEBUG_ASSERT_MSG(false, "Unimplemented code!") | 55 | #define UNIMPLEMENTED() LOG_CRITICAL(Debug, "Unimplemented code!") |
| 57 | #define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__) | 56 | #define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__) |
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 7cf7b7997..995938d0b 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #if !defined(ARCHITECTURE_x86_64) && !defined(_M_ARM) | 7 | #if !defined(ARCHITECTURE_x86_64) && !defined(ARCHITECTURE_ARM) |
| 8 | #include <cstdlib> // for exit | 8 | #include <cstdlib> // for exit |
| 9 | #endif | 9 | #endif |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| @@ -30,7 +30,7 @@ | |||
| 30 | 30 | ||
| 31 | #ifdef ARCHITECTURE_x86_64 | 31 | #ifdef ARCHITECTURE_x86_64 |
| 32 | #define Crash() __asm__ __volatile__("int $3") | 32 | #define Crash() __asm__ __volatile__("int $3") |
| 33 | #elif defined(_M_ARM) | 33 | #elif defined(ARCHITECTURE_ARM) |
| 34 | #define Crash() __asm__ __volatile__("trap") | 34 | #define Crash() __asm__ __volatile__("trap") |
| 35 | #else | 35 | #else |
| 36 | #define Crash() exit(1) | 36 | #define Crash() exit(1) |
diff --git a/src/common/common_paths.h b/src/common/common_paths.h index 0a6132dab..9bf3efaf2 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h | |||
| @@ -32,12 +32,15 @@ | |||
| 32 | #define SDMC_DIR "sdmc" | 32 | #define SDMC_DIR "sdmc" |
| 33 | #define NAND_DIR "nand" | 33 | #define NAND_DIR "nand" |
| 34 | #define SYSDATA_DIR "sysdata" | 34 | #define SYSDATA_DIR "sysdata" |
| 35 | #define LOG_DIR "log" | ||
| 35 | 36 | ||
| 36 | // Filenames | 37 | // Filenames |
| 37 | // Files in the directory returned by GetUserPath(D_CONFIG_IDX) | 38 | // Files in the directory returned by GetUserPath(D_CONFIG_IDX) |
| 38 | #define EMU_CONFIG "emu.ini" | 39 | #define EMU_CONFIG "emu.ini" |
| 39 | #define DEBUGGER_CONFIG "debugger.ini" | 40 | #define DEBUGGER_CONFIG "debugger.ini" |
| 40 | #define LOGGER_CONFIG "logger.ini" | 41 | #define LOGGER_CONFIG "logger.ini" |
| 42 | // Files in the directory returned by GetUserPath(D_LOGS_IDX) | ||
| 43 | #define LOG_FILE "yuzu_log.txt" | ||
| 41 | 44 | ||
| 42 | // Sys files | 45 | // Sys files |
| 43 | #define SHARED_FONT "shared_font.bin" | 46 | #define SHARED_FONT "shared_font.bin" |
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 2d0b81c6e..7213abe18 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -118,7 +118,7 @@ bool IsDirectory(const std::string& filename) { | |||
| 118 | #endif | 118 | #endif |
| 119 | 119 | ||
| 120 | if (result < 0) { | 120 | if (result < 0) { |
| 121 | NGLOG_DEBUG(Common_Filesystem, "stat failed on {}: {}", filename, GetLastErrorMsg()); | 121 | LOG_DEBUG(Common_Filesystem, "stat failed on {}: {}", filename, GetLastErrorMsg()); |
| 122 | return false; | 122 | return false; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| @@ -128,29 +128,29 @@ bool IsDirectory(const std::string& filename) { | |||
| 128 | // Deletes a given filename, return true on success | 128 | // Deletes a given filename, return true on success |
| 129 | // Doesn't supports deleting a directory | 129 | // Doesn't supports deleting a directory |
| 130 | bool Delete(const std::string& filename) { | 130 | bool Delete(const std::string& filename) { |
| 131 | NGLOG_TRACE(Common_Filesystem, "file {}", filename); | 131 | LOG_TRACE(Common_Filesystem, "file {}", filename); |
| 132 | 132 | ||
| 133 | // Return true because we care about the file no | 133 | // Return true because we care about the file no |
| 134 | // being there, not the actual delete. | 134 | // being there, not the actual delete. |
| 135 | if (!Exists(filename)) { | 135 | if (!Exists(filename)) { |
| 136 | NGLOG_DEBUG(Common_Filesystem, "{} does not exist", filename); | 136 | LOG_DEBUG(Common_Filesystem, "{} does not exist", filename); |
| 137 | return true; | 137 | return true; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | // We can't delete a directory | 140 | // We can't delete a directory |
| 141 | if (IsDirectory(filename)) { | 141 | if (IsDirectory(filename)) { |
| 142 | NGLOG_ERROR(Common_Filesystem, "Failed: {} is a directory", filename); | 142 | LOG_ERROR(Common_Filesystem, "Failed: {} is a directory", filename); |
| 143 | return false; | 143 | return false; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | #ifdef _WIN32 | 146 | #ifdef _WIN32 |
| 147 | if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str())) { | 147 | if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str())) { |
| 148 | NGLOG_ERROR(Common_Filesystem, "DeleteFile failed on {}: {}", filename, GetLastErrorMsg()); | 148 | LOG_ERROR(Common_Filesystem, "DeleteFile failed on {}: {}", filename, GetLastErrorMsg()); |
| 149 | return false; | 149 | return false; |
| 150 | } | 150 | } |
| 151 | #else | 151 | #else |
| 152 | if (unlink(filename.c_str()) == -1) { | 152 | if (unlink(filename.c_str()) == -1) { |
| 153 | NGLOG_ERROR(Common_Filesystem, "unlink failed on {}: {}", filename, GetLastErrorMsg()); | 153 | LOG_ERROR(Common_Filesystem, "unlink failed on {}: {}", filename, GetLastErrorMsg()); |
| 154 | return false; | 154 | return false; |
| 155 | } | 155 | } |
| 156 | #endif | 156 | #endif |
| @@ -160,16 +160,16 @@ bool Delete(const std::string& filename) { | |||
| 160 | 160 | ||
| 161 | // Returns true if successful, or path already exists. | 161 | // Returns true if successful, or path already exists. |
| 162 | bool CreateDir(const std::string& path) { | 162 | bool CreateDir(const std::string& path) { |
| 163 | NGLOG_TRACE(Common_Filesystem, "directory {}", path); | 163 | LOG_TRACE(Common_Filesystem, "directory {}", path); |
| 164 | #ifdef _WIN32 | 164 | #ifdef _WIN32 |
| 165 | if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr)) | 165 | if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr)) |
| 166 | return true; | 166 | return true; |
| 167 | DWORD error = GetLastError(); | 167 | DWORD error = GetLastError(); |
| 168 | if (error == ERROR_ALREADY_EXISTS) { | 168 | if (error == ERROR_ALREADY_EXISTS) { |
| 169 | NGLOG_DEBUG(Common_Filesystem, "CreateDirectory failed on {}: already exists", path); | 169 | LOG_DEBUG(Common_Filesystem, "CreateDirectory failed on {}: already exists", path); |
| 170 | return true; | 170 | return true; |
| 171 | } | 171 | } |
| 172 | NGLOG_ERROR(Common_Filesystem, "CreateDirectory failed on {}: {}", path, error); | 172 | LOG_ERROR(Common_Filesystem, "CreateDirectory failed on {}: {}", path, error); |
| 173 | return false; | 173 | return false; |
| 174 | #else | 174 | #else |
| 175 | if (mkdir(path.c_str(), 0755) == 0) | 175 | if (mkdir(path.c_str(), 0755) == 0) |
| @@ -178,11 +178,11 @@ bool CreateDir(const std::string& path) { | |||
| 178 | int err = errno; | 178 | int err = errno; |
| 179 | 179 | ||
| 180 | if (err == EEXIST) { | 180 | if (err == EEXIST) { |
| 181 | NGLOG_DEBUG(Common_Filesystem, "mkdir failed on {}: already exists", path); | 181 | LOG_DEBUG(Common_Filesystem, "mkdir failed on {}: already exists", path); |
| 182 | return true; | 182 | return true; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | NGLOG_ERROR(Common_Filesystem, "mkdir failed on {}: {}", path, strerror(err)); | 185 | LOG_ERROR(Common_Filesystem, "mkdir failed on {}: {}", path, strerror(err)); |
| 186 | return false; | 186 | return false; |
| 187 | #endif | 187 | #endif |
| 188 | } | 188 | } |
| @@ -190,10 +190,10 @@ bool CreateDir(const std::string& path) { | |||
| 190 | // Creates the full path of fullPath returns true on success | 190 | // Creates the full path of fullPath returns true on success |
| 191 | bool CreateFullPath(const std::string& fullPath) { | 191 | bool CreateFullPath(const std::string& fullPath) { |
| 192 | int panicCounter = 100; | 192 | int panicCounter = 100; |
| 193 | NGLOG_TRACE(Common_Filesystem, "path {}", fullPath); | 193 | LOG_TRACE(Common_Filesystem, "path {}", fullPath); |
| 194 | 194 | ||
| 195 | if (FileUtil::Exists(fullPath)) { | 195 | if (FileUtil::Exists(fullPath)) { |
| 196 | NGLOG_DEBUG(Common_Filesystem, "path exists {}", fullPath); | 196 | LOG_DEBUG(Common_Filesystem, "path exists {}", fullPath); |
| 197 | return true; | 197 | return true; |
| 198 | } | 198 | } |
| 199 | 199 | ||
| @@ -209,14 +209,14 @@ bool CreateFullPath(const std::string& fullPath) { | |||
| 209 | // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") | 209 | // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") |
| 210 | std::string const subPath(fullPath.substr(0, position + 1)); | 210 | std::string const subPath(fullPath.substr(0, position + 1)); |
| 211 | if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) { | 211 | if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) { |
| 212 | NGLOG_ERROR(Common, "CreateFullPath: directory creation failed"); | 212 | LOG_ERROR(Common, "CreateFullPath: directory creation failed"); |
| 213 | return false; | 213 | return false; |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | // A safety check | 216 | // A safety check |
| 217 | panicCounter--; | 217 | panicCounter--; |
| 218 | if (panicCounter <= 0) { | 218 | if (panicCounter <= 0) { |
| 219 | NGLOG_ERROR(Common, "CreateFullPath: directory structure is too deep"); | 219 | LOG_ERROR(Common, "CreateFullPath: directory structure is too deep"); |
| 220 | return false; | 220 | return false; |
| 221 | } | 221 | } |
| 222 | position++; | 222 | position++; |
| @@ -225,11 +225,11 @@ bool CreateFullPath(const std::string& fullPath) { | |||
| 225 | 225 | ||
| 226 | // Deletes a directory filename, returns true on success | 226 | // Deletes a directory filename, returns true on success |
| 227 | bool DeleteDir(const std::string& filename) { | 227 | bool DeleteDir(const std::string& filename) { |
| 228 | NGLOG_TRACE(Common_Filesystem, "directory {}", filename); | 228 | LOG_TRACE(Common_Filesystem, "directory {}", filename); |
| 229 | 229 | ||
| 230 | // check if a directory | 230 | // check if a directory |
| 231 | if (!FileUtil::IsDirectory(filename)) { | 231 | if (!FileUtil::IsDirectory(filename)) { |
| 232 | NGLOG_ERROR(Common_Filesystem, "Not a directory {}", filename); | 232 | LOG_ERROR(Common_Filesystem, "Not a directory {}", filename); |
| 233 | return false; | 233 | return false; |
| 234 | } | 234 | } |
| 235 | 235 | ||
| @@ -240,14 +240,14 @@ bool DeleteDir(const std::string& filename) { | |||
| 240 | if (rmdir(filename.c_str()) == 0) | 240 | if (rmdir(filename.c_str()) == 0) |
| 241 | return true; | 241 | return true; |
| 242 | #endif | 242 | #endif |
| 243 | NGLOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg()); | 243 | LOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg()); |
| 244 | 244 | ||
| 245 | return false; | 245 | return false; |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | // renames file srcFilename to destFilename, returns true on success | 248 | // renames file srcFilename to destFilename, returns true on success |
| 249 | bool Rename(const std::string& srcFilename, const std::string& destFilename) { | 249 | bool Rename(const std::string& srcFilename, const std::string& destFilename) { |
| 250 | NGLOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename); | 250 | LOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename); |
| 251 | #ifdef _WIN32 | 251 | #ifdef _WIN32 |
| 252 | if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(), | 252 | if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(), |
| 253 | Common::UTF8ToUTF16W(destFilename).c_str()) == 0) | 253 | Common::UTF8ToUTF16W(destFilename).c_str()) == 0) |
| @@ -256,21 +256,21 @@ bool Rename(const std::string& srcFilename, const std::string& destFilename) { | |||
| 256 | if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) | 256 | if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) |
| 257 | return true; | 257 | return true; |
| 258 | #endif | 258 | #endif |
| 259 | NGLOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename, | 259 | LOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename, |
| 260 | GetLastErrorMsg()); | 260 | GetLastErrorMsg()); |
| 261 | return false; | 261 | return false; |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | // copies file srcFilename to destFilename, returns true on success | 264 | // copies file srcFilename to destFilename, returns true on success |
| 265 | bool Copy(const std::string& srcFilename, const std::string& destFilename) { | 265 | bool Copy(const std::string& srcFilename, const std::string& destFilename) { |
| 266 | NGLOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename); | 266 | LOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename); |
| 267 | #ifdef _WIN32 | 267 | #ifdef _WIN32 |
| 268 | if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(), | 268 | if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(), |
| 269 | Common::UTF8ToUTF16W(destFilename).c_str(), FALSE)) | 269 | Common::UTF8ToUTF16W(destFilename).c_str(), FALSE)) |
| 270 | return true; | 270 | return true; |
| 271 | 271 | ||
| 272 | NGLOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename, | 272 | LOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename, |
| 273 | GetLastErrorMsg()); | 273 | GetLastErrorMsg()); |
| 274 | return false; | 274 | return false; |
| 275 | #else | 275 | #else |
| 276 | 276 | ||
| @@ -282,8 +282,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) { | |||
| 282 | // Open input file | 282 | // Open input file |
| 283 | FILE* input = fopen(srcFilename.c_str(), "rb"); | 283 | FILE* input = fopen(srcFilename.c_str(), "rb"); |
| 284 | if (!input) { | 284 | if (!input) { |
| 285 | NGLOG_ERROR(Common_Filesystem, "opening input failed {} --> {}: {}", srcFilename, | 285 | LOG_ERROR(Common_Filesystem, "opening input failed {} --> {}: {}", srcFilename, |
| 286 | destFilename, GetLastErrorMsg()); | 286 | destFilename, GetLastErrorMsg()); |
| 287 | return false; | 287 | return false; |
| 288 | } | 288 | } |
| 289 | 289 | ||
| @@ -291,8 +291,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) { | |||
| 291 | FILE* output = fopen(destFilename.c_str(), "wb"); | 291 | FILE* output = fopen(destFilename.c_str(), "wb"); |
| 292 | if (!output) { | 292 | if (!output) { |
| 293 | fclose(input); | 293 | fclose(input); |
| 294 | NGLOG_ERROR(Common_Filesystem, "opening output failed {} --> {}: {}", srcFilename, | 294 | LOG_ERROR(Common_Filesystem, "opening output failed {} --> {}: {}", srcFilename, |
| 295 | destFilename, GetLastErrorMsg()); | 295 | destFilename, GetLastErrorMsg()); |
| 296 | return false; | 296 | return false; |
| 297 | } | 297 | } |
| 298 | 298 | ||
| @@ -302,8 +302,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) { | |||
| 302 | size_t rnum = fread(buffer, sizeof(char), BSIZE, input); | 302 | size_t rnum = fread(buffer, sizeof(char), BSIZE, input); |
| 303 | if (rnum != BSIZE) { | 303 | if (rnum != BSIZE) { |
| 304 | if (ferror(input) != 0) { | 304 | if (ferror(input) != 0) { |
| 305 | NGLOG_ERROR(Common_Filesystem, "failed reading from source, {} --> {}: {}", | 305 | LOG_ERROR(Common_Filesystem, "failed reading from source, {} --> {}: {}", |
| 306 | srcFilename, destFilename, GetLastErrorMsg()); | 306 | srcFilename, destFilename, GetLastErrorMsg()); |
| 307 | goto bail; | 307 | goto bail; |
| 308 | } | 308 | } |
| 309 | } | 309 | } |
| @@ -311,8 +311,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) { | |||
| 311 | // write output | 311 | // write output |
| 312 | size_t wnum = fwrite(buffer, sizeof(char), rnum, output); | 312 | size_t wnum = fwrite(buffer, sizeof(char), rnum, output); |
| 313 | if (wnum != rnum) { | 313 | if (wnum != rnum) { |
| 314 | NGLOG_ERROR(Common_Filesystem, "failed writing to output, {} --> {}: {}", srcFilename, | 314 | LOG_ERROR(Common_Filesystem, "failed writing to output, {} --> {}: {}", srcFilename, |
| 315 | destFilename, GetLastErrorMsg()); | 315 | destFilename, GetLastErrorMsg()); |
| 316 | goto bail; | 316 | goto bail; |
| 317 | } | 317 | } |
| 318 | } | 318 | } |
| @@ -332,12 +332,12 @@ bail: | |||
| 332 | // Returns the size of filename (64bit) | 332 | // Returns the size of filename (64bit) |
| 333 | u64 GetSize(const std::string& filename) { | 333 | u64 GetSize(const std::string& filename) { |
| 334 | if (!Exists(filename)) { | 334 | if (!Exists(filename)) { |
| 335 | NGLOG_ERROR(Common_Filesystem, "failed {}: No such file", filename); | 335 | LOG_ERROR(Common_Filesystem, "failed {}: No such file", filename); |
| 336 | return 0; | 336 | return 0; |
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | if (IsDirectory(filename)) { | 339 | if (IsDirectory(filename)) { |
| 340 | NGLOG_ERROR(Common_Filesystem, "failed {}: is a directory", filename); | 340 | LOG_ERROR(Common_Filesystem, "failed {}: is a directory", filename); |
| 341 | return 0; | 341 | return 0; |
| 342 | } | 342 | } |
| 343 | 343 | ||
| @@ -348,11 +348,11 @@ u64 GetSize(const std::string& filename) { | |||
| 348 | if (stat(filename.c_str(), &buf) == 0) | 348 | if (stat(filename.c_str(), &buf) == 0) |
| 349 | #endif | 349 | #endif |
| 350 | { | 350 | { |
| 351 | NGLOG_TRACE(Common_Filesystem, "{}: {}", filename, buf.st_size); | 351 | LOG_TRACE(Common_Filesystem, "{}: {}", filename, buf.st_size); |
| 352 | return buf.st_size; | 352 | return buf.st_size; |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | NGLOG_ERROR(Common_Filesystem, "Stat failed {}: {}", filename, GetLastErrorMsg()); | 355 | LOG_ERROR(Common_Filesystem, "Stat failed {}: {}", filename, GetLastErrorMsg()); |
| 356 | return 0; | 356 | return 0; |
| 357 | } | 357 | } |
| 358 | 358 | ||
| @@ -360,7 +360,7 @@ u64 GetSize(const std::string& filename) { | |||
| 360 | u64 GetSize(const int fd) { | 360 | u64 GetSize(const int fd) { |
| 361 | struct stat buf; | 361 | struct stat buf; |
| 362 | if (fstat(fd, &buf) != 0) { | 362 | if (fstat(fd, &buf) != 0) { |
| 363 | NGLOG_ERROR(Common_Filesystem, "GetSize: stat failed {}: {}", fd, GetLastErrorMsg()); | 363 | LOG_ERROR(Common_Filesystem, "GetSize: stat failed {}: {}", fd, GetLastErrorMsg()); |
| 364 | return 0; | 364 | return 0; |
| 365 | } | 365 | } |
| 366 | return buf.st_size; | 366 | return buf.st_size; |
| @@ -371,14 +371,12 @@ u64 GetSize(FILE* f) { | |||
| 371 | // can't use off_t here because it can be 32-bit | 371 | // can't use off_t here because it can be 32-bit |
| 372 | u64 pos = ftello(f); | 372 | u64 pos = ftello(f); |
| 373 | if (fseeko(f, 0, SEEK_END) != 0) { | 373 | if (fseeko(f, 0, SEEK_END) != 0) { |
| 374 | NGLOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f), | 374 | LOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f), GetLastErrorMsg()); |
| 375 | GetLastErrorMsg()); | ||
| 376 | return 0; | 375 | return 0; |
| 377 | } | 376 | } |
| 378 | u64 size = ftello(f); | 377 | u64 size = ftello(f); |
| 379 | if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { | 378 | if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { |
| 380 | NGLOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f), | 379 | LOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f), GetLastErrorMsg()); |
| 381 | GetLastErrorMsg()); | ||
| 382 | return 0; | 380 | return 0; |
| 383 | } | 381 | } |
| 384 | return size; | 382 | return size; |
| @@ -386,10 +384,10 @@ u64 GetSize(FILE* f) { | |||
| 386 | 384 | ||
| 387 | // creates an empty file filename, returns true on success | 385 | // creates an empty file filename, returns true on success |
| 388 | bool CreateEmptyFile(const std::string& filename) { | 386 | bool CreateEmptyFile(const std::string& filename) { |
| 389 | NGLOG_TRACE(Common_Filesystem, "{}", filename); | 387 | LOG_TRACE(Common_Filesystem, "{}", filename); |
| 390 | 388 | ||
| 391 | if (!FileUtil::IOFile(filename, "wb")) { | 389 | if (!FileUtil::IOFile(filename, "wb")) { |
| 392 | NGLOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg()); | 390 | LOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg()); |
| 393 | return false; | 391 | return false; |
| 394 | } | 392 | } |
| 395 | 393 | ||
| @@ -398,7 +396,7 @@ bool CreateEmptyFile(const std::string& filename) { | |||
| 398 | 396 | ||
| 399 | bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory, | 397 | bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory, |
| 400 | DirectoryEntryCallable callback) { | 398 | DirectoryEntryCallable callback) { |
| 401 | NGLOG_TRACE(Common_Filesystem, "directory {}", directory); | 399 | LOG_TRACE(Common_Filesystem, "directory {}", directory); |
| 402 | 400 | ||
| 403 | // How many files + directories we found | 401 | // How many files + directories we found |
| 404 | unsigned found_entries = 0; | 402 | unsigned found_entries = 0; |
| @@ -556,7 +554,7 @@ std::string GetCurrentDir() { | |||
| 556 | char* dir; | 554 | char* dir; |
| 557 | if (!(dir = getcwd(nullptr, 0))) { | 555 | if (!(dir = getcwd(nullptr, 0))) { |
| 558 | #endif | 556 | #endif |
| 559 | NGLOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg()); | 557 | LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg()); |
| 560 | return nullptr; | 558 | return nullptr; |
| 561 | } | 559 | } |
| 562 | #ifdef _WIN32 | 560 | #ifdef _WIN32 |
| @@ -676,11 +674,11 @@ std::string GetSysDirectory() { | |||
| 676 | #endif | 674 | #endif |
| 677 | sysDir += DIR_SEP; | 675 | sysDir += DIR_SEP; |
| 678 | 676 | ||
| 679 | NGLOG_DEBUG(Common_Filesystem, "Setting to {}:", sysDir); | 677 | LOG_DEBUG(Common_Filesystem, "Setting to {}:", sysDir); |
| 680 | return sysDir; | 678 | return sysDir; |
| 681 | } | 679 | } |
| 682 | 680 | ||
| 683 | // Returns a string with a Citra data dir or file in the user's home | 681 | // Returns a string with a yuzu data dir or file in the user's home |
| 684 | // directory. To be used in "multi-user" mode (that is, installed). | 682 | // directory. To be used in "multi-user" mode (that is, installed). |
| 685 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath) { | 683 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath) { |
| 686 | static std::string paths[NUM_PATH_INDICES]; | 684 | static std::string paths[NUM_PATH_INDICES]; |
| @@ -692,7 +690,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new | |||
| 692 | if (!FileUtil::IsDirectory(paths[D_USER_IDX])) { | 690 | if (!FileUtil::IsDirectory(paths[D_USER_IDX])) { |
| 693 | paths[D_USER_IDX] = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP; | 691 | paths[D_USER_IDX] = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP; |
| 694 | } else { | 692 | } else { |
| 695 | NGLOG_INFO(Common_Filesystem, "Using the local user directory"); | 693 | LOG_INFO(Common_Filesystem, "Using the local user directory"); |
| 696 | } | 694 | } |
| 697 | 695 | ||
| 698 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; | 696 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; |
| @@ -715,11 +713,13 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new | |||
| 715 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; | 713 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; |
| 716 | paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP; | 714 | paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP; |
| 717 | paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP; | 715 | paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP; |
| 716 | // TODO: Put the logs in a better location for each OS | ||
| 717 | paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOG_DIR DIR_SEP; | ||
| 718 | } | 718 | } |
| 719 | 719 | ||
| 720 | if (!newPath.empty()) { | 720 | if (!newPath.empty()) { |
| 721 | if (!FileUtil::IsDirectory(newPath)) { | 721 | if (!FileUtil::IsDirectory(newPath)) { |
| 722 | NGLOG_ERROR(Common_Filesystem, "Invalid path specified {}", newPath); | 722 | LOG_ERROR(Common_Filesystem, "Invalid path specified {}", newPath); |
| 723 | return paths[DirIDX]; | 723 | return paths[DirIDX]; |
| 724 | } else { | 724 | } else { |
| 725 | paths[DirIDX] = newPath; | 725 | paths[DirIDX] = newPath; |
| @@ -801,8 +801,8 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam | |||
| 801 | 801 | ||
| 802 | IOFile::IOFile() {} | 802 | IOFile::IOFile() {} |
| 803 | 803 | ||
| 804 | IOFile::IOFile(const std::string& filename, const char openmode[]) { | 804 | IOFile::IOFile(const std::string& filename, const char openmode[], int flags) { |
| 805 | Open(filename, openmode); | 805 | Open(filename, openmode, flags); |
| 806 | } | 806 | } |
| 807 | 807 | ||
| 808 | IOFile::~IOFile() { | 808 | IOFile::~IOFile() { |
| @@ -823,11 +823,16 @@ void IOFile::Swap(IOFile& other) noexcept { | |||
| 823 | std::swap(m_good, other.m_good); | 823 | std::swap(m_good, other.m_good); |
| 824 | } | 824 | } |
| 825 | 825 | ||
| 826 | bool IOFile::Open(const std::string& filename, const char openmode[]) { | 826 | bool IOFile::Open(const std::string& filename, const char openmode[], int flags) { |
| 827 | Close(); | 827 | Close(); |
| 828 | #ifdef _WIN32 | 828 | #ifdef _WIN32 |
| 829 | _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), | 829 | if (flags != 0) { |
| 830 | Common::UTF8ToUTF16W(openmode).c_str()); | 830 | m_file = _wfsopen(Common::UTF8ToUTF16W(filename).c_str(), |
| 831 | Common::UTF8ToUTF16W(openmode).c_str(), flags); | ||
| 832 | } else { | ||
| 833 | _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), | ||
| 834 | Common::UTF8ToUTF16W(openmode).c_str()); | ||
| 835 | } | ||
| 831 | #else | 836 | #else |
| 832 | m_file = fopen(filename.c_str(), openmode); | 837 | m_file = fopen(filename.c_str(), openmode); |
| 833 | #endif | 838 | #endif |
diff --git a/src/common/file_util.h b/src/common/file_util.h index fc6b3ea46..5bc7fbf7c 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -156,7 +156,10 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam | |||
| 156 | class IOFile : public NonCopyable { | 156 | class IOFile : public NonCopyable { |
| 157 | public: | 157 | public: |
| 158 | IOFile(); | 158 | IOFile(); |
| 159 | IOFile(const std::string& filename, const char openmode[]); | 159 | // flags is used for windows specific file open mode flags, which |
| 160 | // allows yuzu to open the logs in shared write mode, so that the file | ||
| 161 | // isn't considered "locked" while yuzu is open and people can open the log file and view it | ||
| 162 | IOFile(const std::string& filename, const char openmode[], int flags = 0); | ||
| 160 | 163 | ||
| 161 | ~IOFile(); | 164 | ~IOFile(); |
| 162 | 165 | ||
| @@ -165,7 +168,7 @@ public: | |||
| 165 | 168 | ||
| 166 | void Swap(IOFile& other) noexcept; | 169 | void Swap(IOFile& other) noexcept; |
| 167 | 170 | ||
| 168 | bool Open(const std::string& filename, const char openmode[]); | 171 | bool Open(const std::string& filename, const char openmode[], int flags = 0); |
| 169 | bool Close(); | 172 | bool Close(); |
| 170 | 173 | ||
| 171 | template <typename T> | 174 | template <typename T> |
| @@ -220,6 +223,10 @@ public: | |||
| 220 | return WriteArray(&object, 1); | 223 | return WriteArray(&object, 1); |
| 221 | } | 224 | } |
| 222 | 225 | ||
| 226 | size_t WriteString(const std::string& str) { | ||
| 227 | return WriteArray(str.c_str(), str.length()); | ||
| 228 | } | ||
| 229 | |||
| 223 | bool IsOpen() const { | 230 | bool IsOpen() const { |
| 224 | return nullptr != m_file; | 231 | return nullptr != m_file; |
| 225 | } | 232 | } |
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index c26b20062..242914c6a 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -2,16 +2,145 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <utility> | 5 | #include <algorithm> |
| 6 | #include <array> | ||
| 7 | #include <chrono> | ||
| 8 | #include <condition_variable> | ||
| 9 | #include <memory> | ||
| 10 | #include <thread> | ||
| 11 | #ifdef _WIN32 | ||
| 12 | #include <share.h> // For _SH_DENYWR | ||
| 13 | #else | ||
| 14 | #define _SH_DENYWR 0 | ||
| 15 | #endif | ||
| 6 | #include "common/assert.h" | 16 | #include "common/assert.h" |
| 17 | #include "common/common_funcs.h" // snprintf compatibility define | ||
| 7 | #include "common/logging/backend.h" | 18 | #include "common/logging/backend.h" |
| 8 | #include "common/logging/filter.h" | ||
| 9 | #include "common/logging/log.h" | 19 | #include "common/logging/log.h" |
| 10 | #include "common/logging/text_formatter.h" | 20 | #include "common/logging/text_formatter.h" |
| 11 | #include "common/string_util.h" | 21 | #include "common/string_util.h" |
| 22 | #include "common/threadsafe_queue.h" | ||
| 12 | 23 | ||
| 13 | namespace Log { | 24 | namespace Log { |
| 14 | 25 | ||
| 26 | /** | ||
| 27 | * Static state as a singleton. | ||
| 28 | */ | ||
| 29 | class Impl { | ||
| 30 | public: | ||
| 31 | static Impl& Instance() { | ||
| 32 | static Impl backend; | ||
| 33 | return backend; | ||
| 34 | } | ||
| 35 | |||
| 36 | Impl(Impl const&) = delete; | ||
| 37 | const Impl& operator=(Impl const&) = delete; | ||
| 38 | |||
| 39 | void PushEntry(Entry e) { | ||
| 40 | std::lock_guard<std::mutex> lock(message_mutex); | ||
| 41 | message_queue.Push(std::move(e)); | ||
| 42 | message_cv.notify_one(); | ||
| 43 | } | ||
| 44 | |||
| 45 | void AddBackend(std::unique_ptr<Backend> backend) { | ||
| 46 | std::lock_guard<std::mutex> lock(writing_mutex); | ||
| 47 | backends.push_back(std::move(backend)); | ||
| 48 | } | ||
| 49 | |||
| 50 | void RemoveBackend(const std::string& backend_name) { | ||
| 51 | std::lock_guard<std::mutex> lock(writing_mutex); | ||
| 52 | auto it = std::remove_if(backends.begin(), backends.end(), [&backend_name](const auto& i) { | ||
| 53 | return !strcmp(i->GetName(), backend_name.c_str()); | ||
| 54 | }); | ||
| 55 | backends.erase(it, backends.end()); | ||
| 56 | } | ||
| 57 | |||
| 58 | const Filter& GetGlobalFilter() const { | ||
| 59 | return filter; | ||
| 60 | } | ||
| 61 | |||
| 62 | void SetGlobalFilter(const Filter& f) { | ||
| 63 | filter = f; | ||
| 64 | } | ||
| 65 | |||
| 66 | Backend* GetBackend(const std::string& backend_name) { | ||
| 67 | auto it = std::find_if(backends.begin(), backends.end(), [&backend_name](const auto& i) { | ||
| 68 | return !strcmp(i->GetName(), backend_name.c_str()); | ||
| 69 | }); | ||
| 70 | if (it == backends.end()) | ||
| 71 | return nullptr; | ||
| 72 | return it->get(); | ||
| 73 | } | ||
| 74 | |||
| 75 | private: | ||
| 76 | Impl() { | ||
| 77 | backend_thread = std::thread([&] { | ||
| 78 | Entry entry; | ||
| 79 | auto write_logs = [&](Entry& e) { | ||
| 80 | std::lock_guard<std::mutex> lock(writing_mutex); | ||
| 81 | for (const auto& backend : backends) { | ||
| 82 | backend->Write(e); | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | while (true) { | ||
| 86 | std::unique_lock<std::mutex> lock(message_mutex); | ||
| 87 | message_cv.wait(lock, [&] { return !running || message_queue.Pop(entry); }); | ||
| 88 | if (!running) { | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | write_logs(entry); | ||
| 92 | } | ||
| 93 | // Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case | ||
| 94 | // where a system is repeatedly spamming logs even on close. | ||
| 95 | constexpr int MAX_LOGS_TO_WRITE = 100; | ||
| 96 | int logs_written = 0; | ||
| 97 | while (logs_written++ < MAX_LOGS_TO_WRITE && message_queue.Pop(entry)) { | ||
| 98 | write_logs(entry); | ||
| 99 | } | ||
| 100 | }); | ||
| 101 | } | ||
| 102 | |||
| 103 | ~Impl() { | ||
| 104 | running = false; | ||
| 105 | message_cv.notify_one(); | ||
| 106 | backend_thread.join(); | ||
| 107 | } | ||
| 108 | |||
| 109 | std::atomic_bool running{true}; | ||
| 110 | std::mutex message_mutex, writing_mutex; | ||
| 111 | std::condition_variable message_cv; | ||
| 112 | std::thread backend_thread; | ||
| 113 | std::vector<std::unique_ptr<Backend>> backends; | ||
| 114 | Common::MPSCQueue<Log::Entry> message_queue; | ||
| 115 | Filter filter; | ||
| 116 | }; | ||
| 117 | |||
| 118 | void ConsoleBackend::Write(const Entry& entry) { | ||
| 119 | PrintMessage(entry); | ||
| 120 | } | ||
| 121 | |||
| 122 | void ColorConsoleBackend::Write(const Entry& entry) { | ||
| 123 | PrintColoredMessage(entry); | ||
| 124 | } | ||
| 125 | |||
| 126 | // _SH_DENYWR allows read only access to the file for other programs. | ||
| 127 | // It is #defined to 0 on other platforms | ||
| 128 | FileBackend::FileBackend(const std::string& filename) | ||
| 129 | : file(filename, "w", _SH_DENYWR), bytes_written(0) {} | ||
| 130 | |||
| 131 | void FileBackend::Write(const Entry& entry) { | ||
| 132 | // prevent logs from going over the maximum size (in case its spamming and the user doesn't | ||
| 133 | // know) | ||
| 134 | constexpr size_t MAX_BYTES_WRITTEN = 50 * 1024L * 1024L; | ||
| 135 | if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) { | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | bytes_written += file.WriteString(FormatLogMessage(entry) + '\n'); | ||
| 139 | if (entry.log_level >= Level::Error) { | ||
| 140 | file.Flush(); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 15 | /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. | 144 | /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. |
| 16 | #define ALL_LOG_CLASSES() \ | 145 | #define ALL_LOG_CLASSES() \ |
| 17 | CLS(Log) \ | 146 | CLS(Log) \ |
| @@ -125,20 +254,32 @@ Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsign | |||
| 125 | return entry; | 254 | return entry; |
| 126 | } | 255 | } |
| 127 | 256 | ||
| 128 | static Filter* filter = nullptr; | 257 | void SetGlobalFilter(const Filter& filter) { |
| 258 | Impl::Instance().SetGlobalFilter(filter); | ||
| 259 | } | ||
| 260 | |||
| 261 | void AddBackend(std::unique_ptr<Backend> backend) { | ||
| 262 | Impl::Instance().AddBackend(std::move(backend)); | ||
| 263 | } | ||
| 129 | 264 | ||
| 130 | void SetFilter(Filter* new_filter) { | 265 | void RemoveBackend(const std::string& backend_name) { |
| 131 | filter = new_filter; | 266 | Impl::Instance().RemoveBackend(backend_name); |
| 267 | } | ||
| 268 | |||
| 269 | Backend* GetBackend(const std::string& backend_name) { | ||
| 270 | return Impl::Instance().GetBackend(backend_name); | ||
| 132 | } | 271 | } |
| 133 | 272 | ||
| 134 | void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, | 273 | void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, |
| 135 | unsigned int line_num, const char* function, const char* format, | 274 | unsigned int line_num, const char* function, const char* format, |
| 136 | const fmt::format_args& args) { | 275 | const fmt::format_args& args) { |
| 137 | if (filter && !filter->CheckMessage(log_class, log_level)) | 276 | auto filter = Impl::Instance().GetGlobalFilter(); |
| 277 | if (!filter.CheckMessage(log_class, log_level)) | ||
| 138 | return; | 278 | return; |
| 279 | |||
| 139 | Entry entry = | 280 | Entry entry = |
| 140 | CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args)); | 281 | CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args)); |
| 141 | 282 | ||
| 142 | PrintColoredMessage(entry); | 283 | Impl::Instance().PushEntry(std::move(entry)); |
| 143 | } | 284 | } |
| 144 | } // namespace Log | 285 | } // namespace Log \ No newline at end of file |
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index 7e81efb23..57cdf6b2d 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h | |||
| @@ -1,13 +1,15 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | 1 | // Copyright 2014 Citra Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | |||
| 5 | #pragma once | 4 | #pragma once |
| 6 | 5 | ||
| 7 | #include <chrono> | 6 | #include <chrono> |
| 8 | #include <cstdarg> | 7 | #include <cstdarg> |
| 8 | #include <memory> | ||
| 9 | #include <string> | 9 | #include <string> |
| 10 | #include <utility> | 10 | #include <utility> |
| 11 | #include "common/file_util.h" | ||
| 12 | #include "common/logging/filter.h" | ||
| 11 | #include "common/logging/log.h" | 13 | #include "common/logging/log.h" |
| 12 | 14 | ||
| 13 | namespace Log { | 15 | namespace Log { |
| @@ -35,6 +37,80 @@ struct Entry { | |||
| 35 | }; | 37 | }; |
| 36 | 38 | ||
| 37 | /** | 39 | /** |
| 40 | * Interface for logging backends. As loggers can be created and removed at runtime, this can be | ||
| 41 | * used by a frontend for adding a custom logging backend as needed | ||
| 42 | */ | ||
| 43 | class Backend { | ||
| 44 | public: | ||
| 45 | virtual ~Backend() = default; | ||
| 46 | virtual void SetFilter(const Filter& new_filter) { | ||
| 47 | filter = new_filter; | ||
| 48 | } | ||
| 49 | virtual const char* GetName() const = 0; | ||
| 50 | virtual void Write(const Entry& entry) = 0; | ||
| 51 | |||
| 52 | private: | ||
| 53 | Filter filter; | ||
| 54 | }; | ||
| 55 | |||
| 56 | /** | ||
| 57 | * Backend that writes to stderr without any color commands | ||
| 58 | */ | ||
| 59 | class ConsoleBackend : public Backend { | ||
| 60 | public: | ||
| 61 | static const char* Name() { | ||
| 62 | return "console"; | ||
| 63 | } | ||
| 64 | const char* GetName() const override { | ||
| 65 | return Name(); | ||
| 66 | } | ||
| 67 | void Write(const Entry& entry) override; | ||
| 68 | }; | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Backend that writes to stderr and with color | ||
| 72 | */ | ||
| 73 | class ColorConsoleBackend : public Backend { | ||
| 74 | public: | ||
| 75 | static const char* Name() { | ||
| 76 | return "color_console"; | ||
| 77 | } | ||
| 78 | |||
| 79 | const char* GetName() const override { | ||
| 80 | return Name(); | ||
| 81 | } | ||
| 82 | void Write(const Entry& entry) override; | ||
| 83 | }; | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Backend that writes to a file passed into the constructor | ||
| 87 | */ | ||
| 88 | class FileBackend : public Backend { | ||
| 89 | public: | ||
| 90 | explicit FileBackend(const std::string& filename); | ||
| 91 | |||
| 92 | static const char* Name() { | ||
| 93 | return "file"; | ||
| 94 | } | ||
| 95 | |||
| 96 | const char* GetName() const override { | ||
| 97 | return Name(); | ||
| 98 | } | ||
| 99 | |||
| 100 | void Write(const Entry& entry) override; | ||
| 101 | |||
| 102 | private: | ||
| 103 | FileUtil::IOFile file; | ||
| 104 | size_t bytes_written; | ||
| 105 | }; | ||
| 106 | |||
| 107 | void AddBackend(std::unique_ptr<Backend> backend); | ||
| 108 | |||
| 109 | void RemoveBackend(const std::string& backend_name); | ||
| 110 | |||
| 111 | Backend* GetBackend(const std::string& backend_name); | ||
| 112 | |||
| 113 | /** | ||
| 38 | * Returns the name of the passed log class as a C-string. Subclasses are separated by periods | 114 | * Returns the name of the passed log class as a C-string. Subclasses are separated by periods |
| 39 | * instead of underscores as in the enumeration. | 115 | * instead of underscores as in the enumeration. |
| 40 | */ | 116 | */ |
| @@ -49,5 +125,10 @@ const char* GetLevelName(Level log_level); | |||
| 49 | Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, | 125 | Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, |
| 50 | const char* function, std::string message); | 126 | const char* function, std::string message); |
| 51 | 127 | ||
| 52 | void SetFilter(Filter* filter); | 128 | /** |
| 53 | } // namespace Log | 129 | * The global filter will prevent any messages from even being processed if they are filtered. Each |
| 130 | * backend can have a filter, but if the level is lower than the global filter, the backend will | ||
| 131 | * never get the message | ||
| 132 | */ | ||
| 133 | void SetGlobalFilter(const Filter& filter); | ||
| 134 | } // namespace Log \ No newline at end of file | ||
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 428723dce..4e783a577 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp | |||
| @@ -65,14 +65,14 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin, | |||
| 65 | const std::string::const_iterator end) { | 65 | const std::string::const_iterator end) { |
| 66 | auto level_separator = std::find(begin, end, ':'); | 66 | auto level_separator = std::find(begin, end, ':'); |
| 67 | if (level_separator == end) { | 67 | if (level_separator == end) { |
| 68 | NGLOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s", | 68 | LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}", |
| 69 | std::string(begin, end).c_str()); | 69 | std::string(begin, end)); |
| 70 | return false; | 70 | return false; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | const Level level = GetLevelByName(level_separator + 1, end); | 73 | const Level level = GetLevelByName(level_separator + 1, end); |
| 74 | if (level == Level::Count) { | 74 | if (level == Level::Count) { |
| 75 | NGLOG_ERROR(Log, "Unknown log level in filter: %s", std::string(begin, end).c_str()); | 75 | LOG_ERROR(Log, "Unknown log level in filter: {}", std::string(begin, end)); |
| 76 | return false; | 76 | return false; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| @@ -83,7 +83,7 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin, | |||
| 83 | 83 | ||
| 84 | const Class log_class = GetClassByName(begin, level_separator); | 84 | const Class log_class = GetClassByName(begin, level_separator); |
| 85 | if (log_class == Class::Count) { | 85 | if (log_class == Class::Count) { |
| 86 | NGLOG_ERROR(Log, "Unknown log class in filter: %s", std::string(begin, end).c_str()); | 86 | LOG_ERROR(Log, "Unknown log class in filter: {}", std::string(begin, end)); |
| 87 | return false; | 87 | return false; |
| 88 | } | 88 | } |
| 89 | 89 | ||
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index c5015531c..e96c90e16 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -109,25 +109,25 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig | |||
| 109 | } // namespace Log | 109 | } // namespace Log |
| 110 | 110 | ||
| 111 | #ifdef _DEBUG | 111 | #ifdef _DEBUG |
| 112 | #define NGLOG_TRACE(log_class, ...) \ | 112 | #define LOG_TRACE(log_class, ...) \ |
| 113 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, __FILE__, __LINE__, \ | 113 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, __FILE__, __LINE__, \ |
| 114 | __func__, __VA_ARGS__) | 114 | __func__, __VA_ARGS__) |
| 115 | #else | 115 | #else |
| 116 | #define NGLOG_TRACE(log_class, fmt, ...) (void(0)) | 116 | #define LOG_TRACE(log_class, fmt, ...) (void(0)) |
| 117 | #endif | 117 | #endif |
| 118 | 118 | ||
| 119 | #define NGLOG_DEBUG(log_class, ...) \ | 119 | #define LOG_DEBUG(log_class, ...) \ |
| 120 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Debug, __FILE__, __LINE__, \ | 120 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Debug, __FILE__, __LINE__, \ |
| 121 | __func__, __VA_ARGS__) | 121 | __func__, __VA_ARGS__) |
| 122 | #define NGLOG_INFO(log_class, ...) \ | 122 | #define LOG_INFO(log_class, ...) \ |
| 123 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Info, __FILE__, __LINE__, \ | 123 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Info, __FILE__, __LINE__, \ |
| 124 | __func__, __VA_ARGS__) | 124 | __func__, __VA_ARGS__) |
| 125 | #define NGLOG_WARNING(log_class, ...) \ | 125 | #define LOG_WARNING(log_class, ...) \ |
| 126 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Warning, __FILE__, __LINE__, \ | 126 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Warning, __FILE__, __LINE__, \ |
| 127 | __func__, __VA_ARGS__) | 127 | __func__, __VA_ARGS__) |
| 128 | #define NGLOG_ERROR(log_class, ...) \ | 128 | #define LOG_ERROR(log_class, ...) \ |
| 129 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Error, __FILE__, __LINE__, \ | 129 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Error, __FILE__, __LINE__, \ |
| 130 | __func__, __VA_ARGS__) | 130 | __func__, __VA_ARGS__) |
| 131 | #define NGLOG_CRITICAL(log_class, ...) \ | 131 | #define LOG_CRITICAL(log_class, ...) \ |
| 132 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Critical, __FILE__, __LINE__, \ | 132 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Critical, __FILE__, __LINE__, \ |
| 133 | __func__, __VA_ARGS__) | 133 | __func__, __VA_ARGS__) |
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp index 4d1ec8fb9..09462ccee 100644 --- a/src/common/memory_util.cpp +++ b/src/common/memory_util.cpp | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | #include <sys/mman.h> | 16 | #include <sys/mman.h> |
| 17 | #endif | 17 | #endif |
| 18 | 18 | ||
| 19 | #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) | 19 | #if !defined(_WIN32) && defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT) |
| 20 | #include <unistd.h> | 20 | #include <unistd.h> |
| 21 | #define PAGE_MASK (getpagesize() - 1) | 21 | #define PAGE_MASK (getpagesize() - 1) |
| 22 | #define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) | 22 | #define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) |
| @@ -30,7 +30,7 @@ void* AllocateExecutableMemory(size_t size, bool low) { | |||
| 30 | void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); | 30 | void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); |
| 31 | #else | 31 | #else |
| 32 | static char* map_hint = nullptr; | 32 | static char* map_hint = nullptr; |
| 33 | #if defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) | 33 | #if defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT) |
| 34 | // This OS has no flag to enforce allocation below the 4 GB boundary, | 34 | // This OS has no flag to enforce allocation below the 4 GB boundary, |
| 35 | // but if we hint that we want a low address it is very likely we will | 35 | // but if we hint that we want a low address it is very likely we will |
| 36 | // get one. | 36 | // get one. |
| @@ -42,7 +42,7 @@ void* AllocateExecutableMemory(size_t size, bool low) { | |||
| 42 | #endif | 42 | #endif |
| 43 | void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, | 43 | void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, |
| 44 | MAP_ANON | MAP_PRIVATE | 44 | MAP_ANON | MAP_PRIVATE |
| 45 | #if defined(ARCHITECTURE_X64) && defined(MAP_32BIT) | 45 | #if defined(ARCHITECTURE_x86_64) && defined(MAP_32BIT) |
| 46 | | (low ? MAP_32BIT : 0) | 46 | | (low ? MAP_32BIT : 0) |
| 47 | #endif | 47 | #endif |
| 48 | , | 48 | , |
| @@ -55,9 +55,9 @@ void* AllocateExecutableMemory(size_t size, bool low) { | |||
| 55 | if (ptr == MAP_FAILED) { | 55 | if (ptr == MAP_FAILED) { |
| 56 | ptr = nullptr; | 56 | ptr = nullptr; |
| 57 | #endif | 57 | #endif |
| 58 | NGLOG_ERROR(Common_Memory, "Failed to allocate executable memory"); | 58 | LOG_ERROR(Common_Memory, "Failed to allocate executable memory"); |
| 59 | } | 59 | } |
| 60 | #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) | 60 | #if !defined(_WIN32) && defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT) |
| 61 | else { | 61 | else { |
| 62 | if (low) { | 62 | if (low) { |
| 63 | map_hint += size; | 63 | map_hint += size; |
| @@ -68,7 +68,7 @@ void* AllocateExecutableMemory(size_t size, bool low) { | |||
| 68 | 68 | ||
| 69 | #if EMU_ARCH_BITS == 64 | 69 | #if EMU_ARCH_BITS == 64 |
| 70 | if ((u64)ptr >= 0x80000000 && low == true) | 70 | if ((u64)ptr >= 0x80000000 && low == true) |
| 71 | NGLOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!"); | 71 | LOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!"); |
| 72 | #endif | 72 | #endif |
| 73 | 73 | ||
| 74 | return ptr; | 74 | return ptr; |
| @@ -85,7 +85,7 @@ void* AllocateMemoryPages(size_t size) { | |||
| 85 | #endif | 85 | #endif |
| 86 | 86 | ||
| 87 | if (ptr == nullptr) | 87 | if (ptr == nullptr) |
| 88 | NGLOG_ERROR(Common_Memory, "Failed to allocate raw memory"); | 88 | LOG_ERROR(Common_Memory, "Failed to allocate raw memory"); |
| 89 | 89 | ||
| 90 | return ptr; | 90 | return ptr; |
| 91 | } | 91 | } |
| @@ -99,12 +99,12 @@ void* AllocateAlignedMemory(size_t size, size_t alignment) { | |||
| 99 | ptr = memalign(alignment, size); | 99 | ptr = memalign(alignment, size); |
| 100 | #else | 100 | #else |
| 101 | if (posix_memalign(&ptr, alignment, size) != 0) | 101 | if (posix_memalign(&ptr, alignment, size) != 0) |
| 102 | NGLOG_ERROR(Common_Memory, "Failed to allocate aligned memory"); | 102 | LOG_ERROR(Common_Memory, "Failed to allocate aligned memory"); |
| 103 | #endif | 103 | #endif |
| 104 | #endif | 104 | #endif |
| 105 | 105 | ||
| 106 | if (ptr == nullptr) | 106 | if (ptr == nullptr) |
| 107 | NGLOG_ERROR(Common_Memory, "Failed to allocate aligned memory"); | 107 | LOG_ERROR(Common_Memory, "Failed to allocate aligned memory"); |
| 108 | 108 | ||
| 109 | return ptr; | 109 | return ptr; |
| 110 | } | 110 | } |
| @@ -113,7 +113,7 @@ void FreeMemoryPages(void* ptr, size_t size) { | |||
| 113 | if (ptr) { | 113 | if (ptr) { |
| 114 | #ifdef _WIN32 | 114 | #ifdef _WIN32 |
| 115 | if (!VirtualFree(ptr, 0, MEM_RELEASE)) | 115 | if (!VirtualFree(ptr, 0, MEM_RELEASE)) |
| 116 | NGLOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n{}", GetLastErrorMsg()); | 116 | LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n{}", GetLastErrorMsg()); |
| 117 | #else | 117 | #else |
| 118 | munmap(ptr, size); | 118 | munmap(ptr, size); |
| 119 | #endif | 119 | #endif |
| @@ -134,7 +134,7 @@ void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) { | |||
| 134 | #ifdef _WIN32 | 134 | #ifdef _WIN32 |
| 135 | DWORD oldValue; | 135 | DWORD oldValue; |
| 136 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) | 136 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) |
| 137 | NGLOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n{}", GetLastErrorMsg()); | 137 | LOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n{}", GetLastErrorMsg()); |
| 138 | #else | 138 | #else |
| 139 | mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); | 139 | mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); |
| 140 | #endif | 140 | #endif |
| @@ -145,7 +145,7 @@ void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) { | |||
| 145 | DWORD oldValue; | 145 | DWORD oldValue; |
| 146 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, | 146 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, |
| 147 | &oldValue)) | 147 | &oldValue)) |
| 148 | NGLOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n{}", GetLastErrorMsg()); | 148 | LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n{}", GetLastErrorMsg()); |
| 149 | #else | 149 | #else |
| 150 | mprotect(ptr, size, | 150 | mprotect(ptr, size, |
| 151 | allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); | 151 | allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); |
diff --git a/src/common/param_package.cpp b/src/common/param_package.cpp index ab0154133..e0df430ab 100644 --- a/src/common/param_package.cpp +++ b/src/common/param_package.cpp | |||
| @@ -25,7 +25,7 @@ ParamPackage::ParamPackage(const std::string& serialized) { | |||
| 25 | std::vector<std::string> key_value; | 25 | std::vector<std::string> key_value; |
| 26 | Common::SplitString(pair, KEY_VALUE_SEPARATOR, key_value); | 26 | Common::SplitString(pair, KEY_VALUE_SEPARATOR, key_value); |
| 27 | if (key_value.size() != 2) { | 27 | if (key_value.size() != 2) { |
| 28 | NGLOG_ERROR(Common, "invalid key pair {}", pair); | 28 | LOG_ERROR(Common, "invalid key pair {}", pair); |
| 29 | continue; | 29 | continue; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| @@ -64,7 +64,7 @@ std::string ParamPackage::Serialize() const { | |||
| 64 | std::string ParamPackage::Get(const std::string& key, const std::string& default_value) const { | 64 | std::string ParamPackage::Get(const std::string& key, const std::string& default_value) const { |
| 65 | auto pair = data.find(key); | 65 | auto pair = data.find(key); |
| 66 | if (pair == data.end()) { | 66 | if (pair == data.end()) { |
| 67 | NGLOG_DEBUG(Common, "key '{}' not found", key); | 67 | LOG_DEBUG(Common, "key '{}' not found", key); |
| 68 | return default_value; | 68 | return default_value; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| @@ -74,14 +74,14 @@ std::string ParamPackage::Get(const std::string& key, const std::string& default | |||
| 74 | int ParamPackage::Get(const std::string& key, int default_value) const { | 74 | int ParamPackage::Get(const std::string& key, int default_value) const { |
| 75 | auto pair = data.find(key); | 75 | auto pair = data.find(key); |
| 76 | if (pair == data.end()) { | 76 | if (pair == data.end()) { |
| 77 | NGLOG_DEBUG(Common, "key '{}' not found", key); | 77 | LOG_DEBUG(Common, "key '{}' not found", key); |
| 78 | return default_value; | 78 | return default_value; |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | try { | 81 | try { |
| 82 | return std::stoi(pair->second); | 82 | return std::stoi(pair->second); |
| 83 | } catch (const std::logic_error&) { | 83 | } catch (const std::logic_error&) { |
| 84 | NGLOG_ERROR(Common, "failed to convert {} to int", pair->second); | 84 | LOG_ERROR(Common, "failed to convert {} to int", pair->second); |
| 85 | return default_value; | 85 | return default_value; |
| 86 | } | 86 | } |
| 87 | } | 87 | } |
| @@ -89,14 +89,14 @@ int ParamPackage::Get(const std::string& key, int default_value) const { | |||
| 89 | float ParamPackage::Get(const std::string& key, float default_value) const { | 89 | float ParamPackage::Get(const std::string& key, float default_value) const { |
| 90 | auto pair = data.find(key); | 90 | auto pair = data.find(key); |
| 91 | if (pair == data.end()) { | 91 | if (pair == data.end()) { |
| 92 | NGLOG_DEBUG(Common, "key {} not found", key); | 92 | LOG_DEBUG(Common, "key {} not found", key); |
| 93 | return default_value; | 93 | return default_value; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | try { | 96 | try { |
| 97 | return std::stof(pair->second); | 97 | return std::stof(pair->second); |
| 98 | } catch (const std::logic_error&) { | 98 | } catch (const std::logic_error&) { |
| 99 | NGLOG_ERROR(Common, "failed to convert {} to float", pair->second); | 99 | LOG_ERROR(Common, "failed to convert {} to float", pair->second); |
| 100 | return default_value; | 100 | return default_value; |
| 101 | } | 101 | } |
| 102 | } | 102 | } |
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 646400db0..ea9d8f77c 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -281,7 +281,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& | |||
| 281 | 281 | ||
| 282 | iconv_t const conv_desc = iconv_open("UTF-8", fromcode); | 282 | iconv_t const conv_desc = iconv_open("UTF-8", fromcode); |
| 283 | if ((iconv_t)(-1) == conv_desc) { | 283 | if ((iconv_t)(-1) == conv_desc) { |
| 284 | NGLOG_ERROR(Common, "Iconv initialization failure [{}]: {}", fromcode, strerror(errno)); | 284 | LOG_ERROR(Common, "Iconv initialization failure [{}]: {}", fromcode, strerror(errno)); |
| 285 | iconv_close(conv_desc); | 285 | iconv_close(conv_desc); |
| 286 | return {}; | 286 | return {}; |
| 287 | } | 287 | } |
| @@ -310,7 +310,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& | |||
| 310 | ++src_buffer; | 310 | ++src_buffer; |
| 311 | } | 311 | } |
| 312 | } else { | 312 | } else { |
| 313 | NGLOG_ERROR(Common, "iconv failure [{}]: {}", fromcode, strerror(errno)); | 313 | LOG_ERROR(Common, "iconv failure [{}]: {}", fromcode, strerror(errno)); |
| 314 | break; | 314 | break; |
| 315 | } | 315 | } |
| 316 | } | 316 | } |
| @@ -329,7 +329,7 @@ std::u16string UTF8ToUTF16(const std::string& input) { | |||
| 329 | 329 | ||
| 330 | iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8"); | 330 | iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8"); |
| 331 | if ((iconv_t)(-1) == conv_desc) { | 331 | if ((iconv_t)(-1) == conv_desc) { |
| 332 | NGLOG_ERROR(Common, "Iconv initialization failure [UTF-8]: {}", strerror(errno)); | 332 | LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: {}", strerror(errno)); |
| 333 | iconv_close(conv_desc); | 333 | iconv_close(conv_desc); |
| 334 | return {}; | 334 | return {}; |
| 335 | } | 335 | } |
| @@ -358,7 +358,7 @@ std::u16string UTF8ToUTF16(const std::string& input) { | |||
| 358 | ++src_buffer; | 358 | ++src_buffer; |
| 359 | } | 359 | } |
| 360 | } else { | 360 | } else { |
| 361 | NGLOG_ERROR(Common, "iconv failure [UTF-8]: {}", strerror(errno)); | 361 | LOG_ERROR(Common, "iconv failure [UTF-8]: {}", strerror(errno)); |
| 362 | break; | 362 | break; |
| 363 | } | 363 | } |
| 364 | } | 364 | } |
diff --git a/src/common/swap.h b/src/common/swap.h index 4a4012d1a..f025f7450 100644 --- a/src/common/swap.h +++ b/src/common/swap.h | |||
| @@ -69,7 +69,7 @@ inline u32 swap32(u32 _data) { | |||
| 69 | inline u64 swap64(u64 _data) { | 69 | inline u64 swap64(u64 _data) { |
| 70 | return _byteswap_uint64(_data); | 70 | return _byteswap_uint64(_data); |
| 71 | } | 71 | } |
| 72 | #elif _M_ARM | 72 | #elif ARCHITECTURE_ARM |
| 73 | inline u16 swap16(u16 _data) { | 73 | inline u16 swap16(u16 _data) { |
| 74 | u32 data = _data; | 74 | u32 data = _data; |
| 75 | __asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data)); | 75 | __asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data)); |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ba5b02174..3dff068df 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -40,6 +40,8 @@ add_library(core STATIC | |||
| 40 | hle/config_mem.h | 40 | hle/config_mem.h |
| 41 | hle/ipc.h | 41 | hle/ipc.h |
| 42 | hle/ipc_helpers.h | 42 | hle/ipc_helpers.h |
| 43 | hle/kernel/address_arbiter.cpp | ||
| 44 | hle/kernel/address_arbiter.h | ||
| 43 | hle/kernel/client_port.cpp | 45 | hle/kernel/client_port.cpp |
| 44 | hle/kernel/client_port.h | 46 | hle/kernel/client_port.h |
| 45 | hle/kernel/client_session.cpp | 47 | hle/kernel/client_session.cpp |
| @@ -124,6 +126,8 @@ add_library(core STATIC | |||
| 124 | hle/service/audio/audren_u.h | 126 | hle/service/audio/audren_u.h |
| 125 | hle/service/audio/codecctl.cpp | 127 | hle/service/audio/codecctl.cpp |
| 126 | hle/service/audio/codecctl.h | 128 | hle/service/audio/codecctl.h |
| 129 | hle/service/audio/hwopus.cpp | ||
| 130 | hle/service/audio/hwopus.h | ||
| 127 | hle/service/bcat/module.cpp | 131 | hle/service/bcat/module.cpp |
| 128 | hle/service/bcat/module.h | 132 | hle/service/bcat/module.h |
| 129 | hle/service/bcat/bcat.cpp | 133 | hle/service/bcat/bcat.cpp |
| @@ -257,6 +261,8 @@ add_library(core STATIC | |||
| 257 | loader/linker.h | 261 | loader/linker.h |
| 258 | loader/loader.cpp | 262 | loader/loader.cpp |
| 259 | loader/loader.h | 263 | loader/loader.h |
| 264 | loader/nca.cpp | ||
| 265 | loader/nca.h | ||
| 260 | loader/nro.cpp | 266 | loader/nro.cpp |
| 261 | loader/nro.h | 267 | loader/nro.h |
| 262 | loader/nso.cpp | 268 | loader/nso.cpp |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index b5db47667..42605374b 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp | |||
| @@ -55,8 +55,8 @@ public: | |||
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | void InterpreterFallback(u64 pc, size_t num_instructions) override { | 57 | void InterpreterFallback(u64 pc, size_t num_instructions) override { |
| 58 | NGLOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc, | 58 | LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc, |
| 59 | num_instructions, MemoryReadCode(pc)); | 59 | num_instructions, MemoryReadCode(pc)); |
| 60 | 60 | ||
| 61 | ARM_Interface::ThreadContext ctx; | 61 | ARM_Interface::ThreadContext ctx; |
| 62 | parent.SaveContext(ctx); | 62 | parent.SaveContext(ctx); |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 84ab876cc..8335d502e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -87,15 +87,15 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file | |||
| 87 | app_loader = Loader::GetLoader(filepath); | 87 | app_loader = Loader::GetLoader(filepath); |
| 88 | 88 | ||
| 89 | if (!app_loader) { | 89 | if (!app_loader) { |
| 90 | NGLOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); | 90 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); |
| 91 | return ResultStatus::ErrorGetLoader; | 91 | return ResultStatus::ErrorGetLoader; |
| 92 | } | 92 | } |
| 93 | std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode = | 93 | std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode = |
| 94 | app_loader->LoadKernelSystemMode(); | 94 | app_loader->LoadKernelSystemMode(); |
| 95 | 95 | ||
| 96 | if (system_mode.second != Loader::ResultStatus::Success) { | 96 | if (system_mode.second != Loader::ResultStatus::Success) { |
| 97 | NGLOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", | 97 | LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", |
| 98 | static_cast<int>(system_mode.second)); | 98 | static_cast<int>(system_mode.second)); |
| 99 | 99 | ||
| 100 | switch (system_mode.second) { | 100 | switch (system_mode.second) { |
| 101 | case Loader::ResultStatus::ErrorEncrypted: | 101 | case Loader::ResultStatus::ErrorEncrypted: |
| @@ -111,15 +111,15 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file | |||
| 111 | 111 | ||
| 112 | ResultStatus init_result{Init(emu_window, system_mode.first.get())}; | 112 | ResultStatus init_result{Init(emu_window, system_mode.first.get())}; |
| 113 | if (init_result != ResultStatus::Success) { | 113 | if (init_result != ResultStatus::Success) { |
| 114 | NGLOG_CRITICAL(Core, "Failed to initialize system (Error {})!", | 114 | LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", |
| 115 | static_cast<int>(init_result)); | 115 | static_cast<int>(init_result)); |
| 116 | System::Shutdown(); | 116 | System::Shutdown(); |
| 117 | return init_result; | 117 | return init_result; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | const Loader::ResultStatus load_result{app_loader->Load(current_process)}; | 120 | const Loader::ResultStatus load_result{app_loader->Load(current_process)}; |
| 121 | if (Loader::ResultStatus::Success != load_result) { | 121 | if (Loader::ResultStatus::Success != load_result) { |
| 122 | NGLOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); | 122 | LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); |
| 123 | System::Shutdown(); | 123 | System::Shutdown(); |
| 124 | 124 | ||
| 125 | switch (load_result) { | 125 | switch (load_result) { |
| @@ -161,7 +161,7 @@ Cpu& System::CpuCore(size_t core_index) { | |||
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { | 163 | System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { |
| 164 | NGLOG_DEBUG(HW_Memory, "initialized OK"); | 164 | LOG_DEBUG(HW_Memory, "initialized OK"); |
| 165 | 165 | ||
| 166 | CoreTiming::Init(); | 166 | CoreTiming::Init(); |
| 167 | 167 | ||
| @@ -196,7 +196,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { | |||
| 196 | } | 196 | } |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | NGLOG_DEBUG(Core, "Initialized OK"); | 199 | LOG_DEBUG(Core, "Initialized OK"); |
| 200 | 200 | ||
| 201 | // Reset counters and set time origin to current frame | 201 | // Reset counters and set time origin to current frame |
| 202 | GetAndResetPerfStats(); | 202 | GetAndResetPerfStats(); |
| @@ -245,7 +245,7 @@ void System::Shutdown() { | |||
| 245 | // Close app loader | 245 | // Close app loader |
| 246 | app_loader.reset(); | 246 | app_loader.reset(); |
| 247 | 247 | ||
| 248 | NGLOG_DEBUG(Core, "Shutdown OK"); | 248 | LOG_DEBUG(Core, "Shutdown OK"); |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | Service::SM::ServiceManager& System::ServiceManager() { | 251 | Service::SM::ServiceManager& System::ServiceManager() { |
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index 099f2bb1a..f22d6a9d0 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp | |||
| @@ -56,7 +56,7 @@ Cpu::Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index) | |||
| 56 | arm_interface = std::make_shared<ARM_Dynarmic>(); | 56 | arm_interface = std::make_shared<ARM_Dynarmic>(); |
| 57 | #else | 57 | #else |
| 58 | cpu_core = std::make_shared<ARM_Unicorn>(); | 58 | cpu_core = std::make_shared<ARM_Unicorn>(); |
| 59 | NGLOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); | 59 | LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); |
| 60 | #endif | 60 | #endif |
| 61 | } else { | 61 | } else { |
| 62 | arm_interface = std::make_shared<ARM_Unicorn>(); | 62 | arm_interface = std::make_shared<ARM_Unicorn>(); |
| @@ -75,7 +75,7 @@ void Cpu::RunLoop(bool tight_loop) { | |||
| 75 | // If we don't have a currently active thread then don't execute instructions, | 75 | // If we don't have a currently active thread then don't execute instructions, |
| 76 | // instead advance to the next event and try to yield to the next thread | 76 | // instead advance to the next event and try to yield to the next thread |
| 77 | if (Kernel::GetCurrentThread() == nullptr) { | 77 | if (Kernel::GetCurrentThread() == nullptr) { |
| 78 | NGLOG_TRACE(Core, "Core-{} idling", core_index); | 78 | LOG_TRACE(Core, "Core-{} idling", core_index); |
| 79 | 79 | ||
| 80 | if (IsMainCore()) { | 80 | if (IsMainCore()) { |
| 81 | CoreTiming::Idle(); | 81 | CoreTiming::Idle(); |
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index dc1d8668f..50d1e3fc9 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -74,11 +74,11 @@ static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) {} | |||
| 74 | 74 | ||
| 75 | s64 usToCycles(s64 us) { | 75 | s64 usToCycles(s64 us) { |
| 76 | if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) { | 76 | if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) { |
| 77 | NGLOG_ERROR(Core_Timing, "Integer overflow, use max value"); | 77 | LOG_ERROR(Core_Timing, "Integer overflow, use max value"); |
| 78 | return std::numeric_limits<s64>::max(); | 78 | return std::numeric_limits<s64>::max(); |
| 79 | } | 79 | } |
| 80 | if (us > MAX_VALUE_TO_MULTIPLY) { | 80 | if (us > MAX_VALUE_TO_MULTIPLY) { |
| 81 | NGLOG_DEBUG(Core_Timing, "Time very big, do rounding"); | 81 | LOG_DEBUG(Core_Timing, "Time very big, do rounding"); |
| 82 | return BASE_CLOCK_RATE * (us / 1000000); | 82 | return BASE_CLOCK_RATE * (us / 1000000); |
| 83 | } | 83 | } |
| 84 | return (BASE_CLOCK_RATE * us) / 1000000; | 84 | return (BASE_CLOCK_RATE * us) / 1000000; |
| @@ -86,11 +86,11 @@ s64 usToCycles(s64 us) { | |||
| 86 | 86 | ||
| 87 | s64 usToCycles(u64 us) { | 87 | s64 usToCycles(u64 us) { |
| 88 | if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) { | 88 | if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) { |
| 89 | NGLOG_ERROR(Core_Timing, "Integer overflow, use max value"); | 89 | LOG_ERROR(Core_Timing, "Integer overflow, use max value"); |
| 90 | return std::numeric_limits<s64>::max(); | 90 | return std::numeric_limits<s64>::max(); |
| 91 | } | 91 | } |
| 92 | if (us > MAX_VALUE_TO_MULTIPLY) { | 92 | if (us > MAX_VALUE_TO_MULTIPLY) { |
| 93 | NGLOG_DEBUG(Core_Timing, "Time very big, do rounding"); | 93 | LOG_DEBUG(Core_Timing, "Time very big, do rounding"); |
| 94 | return BASE_CLOCK_RATE * static_cast<s64>(us / 1000000); | 94 | return BASE_CLOCK_RATE * static_cast<s64>(us / 1000000); |
| 95 | } | 95 | } |
| 96 | return (BASE_CLOCK_RATE * static_cast<s64>(us)) / 1000000; | 96 | return (BASE_CLOCK_RATE * static_cast<s64>(us)) / 1000000; |
| @@ -98,11 +98,11 @@ s64 usToCycles(u64 us) { | |||
| 98 | 98 | ||
| 99 | s64 nsToCycles(s64 ns) { | 99 | s64 nsToCycles(s64 ns) { |
| 100 | if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) { | 100 | if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) { |
| 101 | NGLOG_ERROR(Core_Timing, "Integer overflow, use max value"); | 101 | LOG_ERROR(Core_Timing, "Integer overflow, use max value"); |
| 102 | return std::numeric_limits<s64>::max(); | 102 | return std::numeric_limits<s64>::max(); |
| 103 | } | 103 | } |
| 104 | if (ns > MAX_VALUE_TO_MULTIPLY) { | 104 | if (ns > MAX_VALUE_TO_MULTIPLY) { |
| 105 | NGLOG_DEBUG(Core_Timing, "Time very big, do rounding"); | 105 | LOG_DEBUG(Core_Timing, "Time very big, do rounding"); |
| 106 | return BASE_CLOCK_RATE * (ns / 1000000000); | 106 | return BASE_CLOCK_RATE * (ns / 1000000000); |
| 107 | } | 107 | } |
| 108 | return (BASE_CLOCK_RATE * ns) / 1000000000; | 108 | return (BASE_CLOCK_RATE * ns) / 1000000000; |
| @@ -110,11 +110,11 @@ s64 nsToCycles(s64 ns) { | |||
| 110 | 110 | ||
| 111 | s64 nsToCycles(u64 ns) { | 111 | s64 nsToCycles(u64 ns) { |
| 112 | if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) { | 112 | if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) { |
| 113 | NGLOG_ERROR(Core_Timing, "Integer overflow, use max value"); | 113 | LOG_ERROR(Core_Timing, "Integer overflow, use max value"); |
| 114 | return std::numeric_limits<s64>::max(); | 114 | return std::numeric_limits<s64>::max(); |
| 115 | } | 115 | } |
| 116 | if (ns > MAX_VALUE_TO_MULTIPLY) { | 116 | if (ns > MAX_VALUE_TO_MULTIPLY) { |
| 117 | NGLOG_DEBUG(Core_Timing, "Time very big, do rounding"); | 117 | LOG_DEBUG(Core_Timing, "Time very big, do rounding"); |
| 118 | return BASE_CLOCK_RATE * (static_cast<s64>(ns) / 1000000000); | 118 | return BASE_CLOCK_RATE * (static_cast<s64>(ns) / 1000000000); |
| 119 | } | 119 | } |
| 120 | return (BASE_CLOCK_RATE * static_cast<s64>(ns)) / 1000000000; | 120 | return (BASE_CLOCK_RATE * static_cast<s64>(ns)) / 1000000000; |
diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp index 8aa0e0aa4..8c6f15bb5 100644 --- a/src/core/file_sys/disk_filesystem.cpp +++ b/src/core/file_sys/disk_filesystem.cpp | |||
| @@ -80,19 +80,19 @@ ResultCode Disk_FileSystem::RenameFile(const std::string& src_path, | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | ResultCode Disk_FileSystem::DeleteDirectory(const Path& path) const { | 82 | ResultCode Disk_FileSystem::DeleteDirectory(const Path& path) const { |
| 83 | NGLOG_WARNING(Service_FS, "(STUBBED) called"); | 83 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 84 | // TODO(wwylele): Use correct error code | 84 | // TODO(wwylele): Use correct error code |
| 85 | return ResultCode(-1); | 85 | return ResultCode(-1); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | ResultCode Disk_FileSystem::DeleteDirectoryRecursively(const Path& path) const { | 88 | ResultCode Disk_FileSystem::DeleteDirectoryRecursively(const Path& path) const { |
| 89 | NGLOG_WARNING(Service_FS, "(STUBBED) called"); | 89 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 90 | // TODO(wwylele): Use correct error code | 90 | // TODO(wwylele): Use correct error code |
| 91 | return ResultCode(-1); | 91 | return ResultCode(-1); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const { | 94 | ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const { |
| 95 | NGLOG_WARNING(Service_FS, "(STUBBED) called"); | 95 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 96 | 96 | ||
| 97 | std::string full_path = base_directory + path; | 97 | std::string full_path = base_directory + path; |
| 98 | if (size == 0) { | 98 | if (size == 0) { |
| @@ -107,7 +107,7 @@ ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const | |||
| 107 | return RESULT_SUCCESS; | 107 | return RESULT_SUCCESS; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | NGLOG_ERROR(Service_FS, "Too large file"); | 110 | LOG_ERROR(Service_FS, "Too large file"); |
| 111 | // TODO(Subv): Find out the correct error code | 111 | // TODO(Subv): Find out the correct error code |
| 112 | return ResultCode(-1); | 112 | return ResultCode(-1); |
| 113 | } | 113 | } |
| @@ -120,13 +120,13 @@ ResultCode Disk_FileSystem::CreateDirectory(const std::string& path) const { | |||
| 120 | return RESULT_SUCCESS; | 120 | return RESULT_SUCCESS; |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | NGLOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating {}", full_path); | 123 | LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating {}", full_path); |
| 124 | // TODO(wwylele): Use correct error code | 124 | // TODO(wwylele): Use correct error code |
| 125 | return ResultCode(-1); | 125 | return ResultCode(-1); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const { | 128 | ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const { |
| 129 | NGLOG_WARNING(Service_FS, "(STUBBED) called"); | 129 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 130 | // TODO(wwylele): Use correct error code | 130 | // TODO(wwylele): Use correct error code |
| 131 | return ResultCode(-1); | 131 | return ResultCode(-1); |
| 132 | } | 132 | } |
| @@ -146,7 +146,7 @@ ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory( | |||
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | u64 Disk_FileSystem::GetFreeSpaceSize() const { | 148 | u64 Disk_FileSystem::GetFreeSpaceSize() const { |
| 149 | NGLOG_WARNING(Service_FS, "(STUBBED) called"); | 149 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 150 | return 0; | 150 | return 0; |
| 151 | } | 151 | } |
| 152 | 152 | ||
| @@ -163,14 +163,14 @@ ResultVal<FileSys::EntryType> Disk_FileSystem::GetEntryType(const std::string& p | |||
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { | 165 | ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { |
| 166 | NGLOG_TRACE(Service_FS, "called offset={}, length={}", offset, length); | 166 | LOG_TRACE(Service_FS, "called offset={}, length={}", offset, length); |
| 167 | file->Seek(offset, SEEK_SET); | 167 | file->Seek(offset, SEEK_SET); |
| 168 | return MakeResult<size_t>(file->ReadBytes(buffer, length)); | 168 | return MakeResult<size_t>(file->ReadBytes(buffer, length)); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | ResultVal<size_t> Disk_Storage::Write(const u64 offset, const size_t length, const bool flush, | 171 | ResultVal<size_t> Disk_Storage::Write(const u64 offset, const size_t length, const bool flush, |
| 172 | const u8* buffer) const { | 172 | const u8* buffer) const { |
| 173 | NGLOG_WARNING(Service_FS, "(STUBBED) called"); | 173 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 174 | file->Seek(offset, SEEK_SET); | 174 | file->Seek(offset, SEEK_SET); |
| 175 | size_t written = file->WriteBytes(buffer, length); | 175 | size_t written = file->WriteBytes(buffer, length); |
| 176 | if (flush) { | 176 | if (flush) { |
| @@ -204,7 +204,7 @@ u64 Disk_Directory::Read(const u64 count, Entry* entries) { | |||
| 204 | const std::string& filename = file.virtualName; | 204 | const std::string& filename = file.virtualName; |
| 205 | Entry& entry = entries[entries_read]; | 205 | Entry& entry = entries[entries_read]; |
| 206 | 206 | ||
| 207 | NGLOG_TRACE(Service_FS, "File {}: size={} dir={}", filename, file.size, file.isDirectory); | 207 | LOG_TRACE(Service_FS, "File {}: size={} dir={}", filename, file.size, file.isDirectory); |
| 208 | 208 | ||
| 209 | // TODO(Link Mauve): use a proper conversion to UTF-16. | 209 | // TODO(Link Mauve): use a proper conversion to UTF-16. |
| 210 | for (size_t j = 0; j < FILENAME_LENGTH; ++j) { | 210 | for (size_t j = 0; j < FILENAME_LENGTH; ++j) { |
diff --git a/src/core/file_sys/filesystem.cpp b/src/core/file_sys/filesystem.cpp index 87083878b..82fdb3c46 100644 --- a/src/core/file_sys/filesystem.cpp +++ b/src/core/file_sys/filesystem.cpp | |||
| @@ -71,7 +71,7 @@ std::string Path::AsString() const { | |||
| 71 | case Binary: | 71 | case Binary: |
| 72 | default: | 72 | default: |
| 73 | // TODO(yuriks): Add assert | 73 | // TODO(yuriks): Add assert |
| 74 | NGLOG_ERROR(Service_FS, "LowPathType cannot be converted to string!"); | 74 | LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!"); |
| 75 | return {}; | 75 | return {}; |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| @@ -87,7 +87,7 @@ std::u16string Path::AsU16Str() const { | |||
| 87 | case Invalid: | 87 | case Invalid: |
| 88 | case Binary: | 88 | case Binary: |
| 89 | // TODO(yuriks): Add assert | 89 | // TODO(yuriks): Add assert |
| 90 | NGLOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!"); | 90 | LOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!"); |
| 91 | return {}; | 91 | return {}; |
| 92 | } | 92 | } |
| 93 | 93 | ||
| @@ -115,7 +115,7 @@ std::vector<u8> Path::AsBinary() const { | |||
| 115 | case Invalid: | 115 | case Invalid: |
| 116 | default: | 116 | default: |
| 117 | // TODO(yuriks): Add assert | 117 | // TODO(yuriks): Add assert |
| 118 | NGLOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!"); | 118 | LOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!"); |
| 119 | return {}; | 119 | return {}; |
| 120 | } | 120 | } |
| 121 | } | 121 | } |
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index 808254ecc..46d438aca 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp | |||
| @@ -19,13 +19,20 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::string& file_path, siz | |||
| 19 | if (file.GetSize() < sizeof(Header)) | 19 | if (file.GetSize() < sizeof(Header)) |
| 20 | return Loader::ResultStatus::Error; | 20 | return Loader::ResultStatus::Error; |
| 21 | 21 | ||
| 22 | file.Seek(offset, SEEK_SET); | ||
| 22 | // For cartridges, HFSs can get very large, so we need to calculate the size up to | 23 | // For cartridges, HFSs can get very large, so we need to calculate the size up to |
| 23 | // the actual content itself instead of just blindly reading in the entire file. | 24 | // the actual content itself instead of just blindly reading in the entire file. |
| 24 | Header pfs_header; | 25 | Header pfs_header; |
| 25 | if (!file.ReadBytes(&pfs_header, sizeof(Header))) | 26 | if (!file.ReadBytes(&pfs_header, sizeof(Header))) |
| 26 | return Loader::ResultStatus::Error; | 27 | return Loader::ResultStatus::Error; |
| 27 | 28 | ||
| 28 | bool is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0); | 29 | if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') && |
| 30 | pfs_header.magic != Common::MakeMagic('P', 'F', 'S', '0')) { | ||
| 31 | return Loader::ResultStatus::ErrorInvalidFormat; | ||
| 32 | } | ||
| 33 | |||
| 34 | bool is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0'); | ||
| 35 | |||
| 29 | size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); | 36 | size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); |
| 30 | size_t metadata_size = | 37 | size_t metadata_size = |
| 31 | sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size; | 38 | sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size; |
| @@ -39,7 +46,7 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::string& file_path, siz | |||
| 39 | 46 | ||
| 40 | Loader::ResultStatus result = Load(file_data); | 47 | Loader::ResultStatus result = Load(file_data); |
| 41 | if (result != Loader::ResultStatus::Success) | 48 | if (result != Loader::ResultStatus::Success) |
| 42 | NGLOG_ERROR(Service_FS, "Failed to load PFS from file {}!", file_path); | 49 | LOG_ERROR(Service_FS, "Failed to load PFS from file {}!", file_path); |
| 43 | 50 | ||
| 44 | return result; | 51 | return result; |
| 45 | } | 52 | } |
| @@ -50,7 +57,12 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::vector<u8>& file_data, | |||
| 50 | return Loader::ResultStatus::Error; | 57 | return Loader::ResultStatus::Error; |
| 51 | 58 | ||
| 52 | memcpy(&pfs_header, &file_data[offset], sizeof(Header)); | 59 | memcpy(&pfs_header, &file_data[offset], sizeof(Header)); |
| 53 | is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0); | 60 | if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') && |
| 61 | pfs_header.magic != Common::MakeMagic('P', 'F', 'S', '0')) { | ||
| 62 | return Loader::ResultStatus::ErrorInvalidFormat; | ||
| 63 | } | ||
| 64 | |||
| 65 | is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0'); | ||
| 54 | 66 | ||
| 55 | size_t entries_offset = offset + sizeof(Header); | 67 | size_t entries_offset = offset + sizeof(Header); |
| 56 | size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); | 68 | size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); |
| @@ -73,21 +85,21 @@ u32 PartitionFilesystem::GetNumEntries() const { | |||
| 73 | return pfs_header.num_entries; | 85 | return pfs_header.num_entries; |
| 74 | } | 86 | } |
| 75 | 87 | ||
| 76 | u64 PartitionFilesystem::GetEntryOffset(int index) const { | 88 | u64 PartitionFilesystem::GetEntryOffset(u32 index) const { |
| 77 | if (index > GetNumEntries()) | 89 | if (index > GetNumEntries()) |
| 78 | return 0; | 90 | return 0; |
| 79 | 91 | ||
| 80 | return content_offset + pfs_entries[index].fs_entry.offset; | 92 | return content_offset + pfs_entries[index].fs_entry.offset; |
| 81 | } | 93 | } |
| 82 | 94 | ||
| 83 | u64 PartitionFilesystem::GetEntrySize(int index) const { | 95 | u64 PartitionFilesystem::GetEntrySize(u32 index) const { |
| 84 | if (index > GetNumEntries()) | 96 | if (index > GetNumEntries()) |
| 85 | return 0; | 97 | return 0; |
| 86 | 98 | ||
| 87 | return pfs_entries[index].fs_entry.size; | 99 | return pfs_entries[index].fs_entry.size; |
| 88 | } | 100 | } |
| 89 | 101 | ||
| 90 | std::string PartitionFilesystem::GetEntryName(int index) const { | 102 | std::string PartitionFilesystem::GetEntryName(u32 index) const { |
| 91 | if (index > GetNumEntries()) | 103 | if (index > GetNumEntries()) |
| 92 | return ""; | 104 | return ""; |
| 93 | 105 | ||
| @@ -113,12 +125,12 @@ u64 PartitionFilesystem::GetFileSize(const std::string& name) const { | |||
| 113 | } | 125 | } |
| 114 | 126 | ||
| 115 | void PartitionFilesystem::Print() const { | 127 | void PartitionFilesystem::Print() const { |
| 116 | NGLOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic.data()); | 128 | LOG_DEBUG(Service_FS, "Magic: {}", pfs_header.magic); |
| 117 | NGLOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries); | 129 | LOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries); |
| 118 | for (u32 i = 0; i < pfs_header.num_entries; i++) { | 130 | for (u32 i = 0; i < pfs_header.num_entries; i++) { |
| 119 | NGLOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i, | 131 | LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i, |
| 120 | pfs_entries[i].name.c_str(), pfs_entries[i].fs_entry.size, | 132 | pfs_entries[i].name.c_str(), pfs_entries[i].fs_entry.size, |
| 121 | GetFileOffset(pfs_entries[i].name)); | 133 | GetFileOffset(pfs_entries[i].name)); |
| 122 | } | 134 | } |
| 123 | } | 135 | } |
| 124 | } // namespace FileSys | 136 | } // namespace FileSys |
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h index 573c90057..9c5810cf1 100644 --- a/src/core/file_sys/partition_filesystem.h +++ b/src/core/file_sys/partition_filesystem.h | |||
| @@ -27,9 +27,9 @@ public: | |||
| 27 | Loader::ResultStatus Load(const std::vector<u8>& file_data, size_t offset = 0); | 27 | Loader::ResultStatus Load(const std::vector<u8>& file_data, size_t offset = 0); |
| 28 | 28 | ||
| 29 | u32 GetNumEntries() const; | 29 | u32 GetNumEntries() const; |
| 30 | u64 GetEntryOffset(int index) const; | 30 | u64 GetEntryOffset(u32 index) const; |
| 31 | u64 GetEntrySize(int index) const; | 31 | u64 GetEntrySize(u32 index) const; |
| 32 | std::string GetEntryName(int index) const; | 32 | std::string GetEntryName(u32 index) const; |
| 33 | u64 GetFileOffset(const std::string& name) const; | 33 | u64 GetFileOffset(const std::string& name) const; |
| 34 | u64 GetFileSize(const std::string& name) const; | 34 | u64 GetFileSize(const std::string& name) const; |
| 35 | 35 | ||
| @@ -37,7 +37,7 @@ public: | |||
| 37 | 37 | ||
| 38 | private: | 38 | private: |
| 39 | struct Header { | 39 | struct Header { |
| 40 | std::array<char, 4> magic; | 40 | u32_le magic; |
| 41 | u32_le num_entries; | 41 | u32_le num_entries; |
| 42 | u32_le strtab_size; | 42 | u32_le strtab_size; |
| 43 | INSERT_PADDING_BYTES(0x4); | 43 | INSERT_PADDING_BYTES(0x4); |
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 25a822891..226811115 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp | |||
| @@ -21,7 +21,7 @@ Loader::ResultStatus ProgramMetadata::Load(const std::string& file_path) { | |||
| 21 | 21 | ||
| 22 | Loader::ResultStatus result = Load(file_data); | 22 | Loader::ResultStatus result = Load(file_data); |
| 23 | if (result != Loader::ResultStatus::Success) | 23 | if (result != Loader::ResultStatus::Success) |
| 24 | NGLOG_ERROR(Service_FS, "Failed to load NPDM from file {}!", file_path); | 24 | LOG_ERROR(Service_FS, "Failed to load NPDM from file {}!", file_path); |
| 25 | 25 | ||
| 26 | return result; | 26 | return result; |
| 27 | } | 27 | } |
| @@ -76,14 +76,14 @@ u64 ProgramMetadata::GetFilesystemPermissions() const { | |||
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | void ProgramMetadata::Print() const { | 78 | void ProgramMetadata::Print() const { |
| 79 | NGLOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data()); | 79 | LOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data()); |
| 80 | NGLOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority); | 80 | LOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority); |
| 81 | NGLOG_DEBUG(Service_FS, "Main thread core: {}", npdm_header.main_thread_cpu); | 81 | LOG_DEBUG(Service_FS, "Main thread core: {}", npdm_header.main_thread_cpu); |
| 82 | NGLOG_DEBUG(Service_FS, "Main thread stack size: 0x{:X} bytes", npdm_header.main_stack_size); | 82 | LOG_DEBUG(Service_FS, "Main thread stack size: 0x{:X} bytes", npdm_header.main_stack_size); |
| 83 | NGLOG_DEBUG(Service_FS, "Process category: {}", npdm_header.process_category); | 83 | LOG_DEBUG(Service_FS, "Process category: {}", npdm_header.process_category); |
| 84 | NGLOG_DEBUG(Service_FS, "Flags: 0x{:02X}", npdm_header.flags); | 84 | LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", npdm_header.flags); |
| 85 | NGLOG_DEBUG(Service_FS, " > 64-bit instructions: {}", | 85 | LOG_DEBUG(Service_FS, " > 64-bit instructions: {}", |
| 86 | npdm_header.has_64_bit_instructions ? "YES" : "NO"); | 86 | npdm_header.has_64_bit_instructions ? "YES" : "NO"); |
| 87 | 87 | ||
| 88 | auto address_space = "Unknown"; | 88 | auto address_space = "Unknown"; |
| 89 | switch (npdm_header.address_space_type) { | 89 | switch (npdm_header.address_space_type) { |
| @@ -95,19 +95,19 @@ void ProgramMetadata::Print() const { | |||
| 95 | break; | 95 | break; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | NGLOG_DEBUG(Service_FS, " > Address space: {}\n", address_space); | 98 | LOG_DEBUG(Service_FS, " > Address space: {}\n", address_space); |
| 99 | 99 | ||
| 100 | // Begin ACID printing (potential perms, signed) | 100 | // Begin ACID printing (potential perms, signed) |
| 101 | NGLOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data()); | 101 | LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data()); |
| 102 | NGLOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags); | 102 | LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags); |
| 103 | NGLOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO"); | 103 | LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO"); |
| 104 | NGLOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min); | 104 | LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min); |
| 105 | NGLOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max); | 105 | LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max); |
| 106 | NGLOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions); | 106 | LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions); |
| 107 | 107 | ||
| 108 | // Begin ACI0 printing (actual perms, unsigned) | 108 | // Begin ACI0 printing (actual perms, unsigned) |
| 109 | NGLOG_DEBUG(Service_FS, "Magic: {:.4}", aci_header.magic.data()); | 109 | LOG_DEBUG(Service_FS, "Magic: {:.4}", aci_header.magic.data()); |
| 110 | NGLOG_DEBUG(Service_FS, "Title ID: 0x{:016X}", aci_header.title_id); | 110 | LOG_DEBUG(Service_FS, "Title ID: 0x{:016X}", aci_header.title_id); |
| 111 | NGLOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", aci_file_access.permissions); | 111 | LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", aci_file_access.permissions); |
| 112 | } | 112 | } |
| 113 | } // namespace FileSys | 113 | } // namespace FileSys |
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index dc7591aca..84ae0d99b 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp | |||
| @@ -14,7 +14,7 @@ namespace FileSys { | |||
| 14 | RomFS_Factory::RomFS_Factory(Loader::AppLoader& app_loader) { | 14 | RomFS_Factory::RomFS_Factory(Loader::AppLoader& app_loader) { |
| 15 | // Load the RomFS from the app | 15 | // Load the RomFS from the app |
| 16 | if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) { | 16 | if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) { |
| 17 | NGLOG_ERROR(Service_FS, "Unable to read RomFS!"); | 17 | LOG_ERROR(Service_FS, "Unable to read RomFS!"); |
| 18 | } | 18 | } |
| 19 | } | 19 | } |
| 20 | 20 | ||
| @@ -24,13 +24,13 @@ ResultVal<std::unique_ptr<FileSystemBackend>> RomFS_Factory::Open(const Path& pa | |||
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | ResultCode RomFS_Factory::Format(const Path& path) { | 26 | ResultCode RomFS_Factory::Format(const Path& path) { |
| 27 | NGLOG_ERROR(Service_FS, "Unimplemented Format archive {}", GetName()); | 27 | LOG_ERROR(Service_FS, "Unimplemented Format archive {}", GetName()); |
| 28 | // TODO(bunnei): Find the right error code for this | 28 | // TODO(bunnei): Find the right error code for this |
| 29 | return ResultCode(-1); | 29 | return ResultCode(-1); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | ResultVal<ArchiveFormatInfo> RomFS_Factory::GetFormatInfo(const Path& path) const { | 32 | ResultVal<ArchiveFormatInfo> RomFS_Factory::GetFormatInfo(const Path& path) const { |
| 33 | NGLOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName()); | 33 | LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName()); |
| 34 | // TODO(bunnei): Find the right error code for this | 34 | // TODO(bunnei): Find the right error code for this |
| 35 | return ResultCode(-1); | 35 | return ResultCode(-1); |
| 36 | } | 36 | } |
diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp index 8e2bce687..83162622b 100644 --- a/src/core/file_sys/romfs_filesystem.cpp +++ b/src/core/file_sys/romfs_filesystem.cpp | |||
| @@ -21,72 +21,70 @@ ResultVal<std::unique_ptr<StorageBackend>> RomFS_FileSystem::OpenFile(const std: | |||
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | ResultCode RomFS_FileSystem::DeleteFile(const std::string& path) const { | 23 | ResultCode RomFS_FileSystem::DeleteFile(const std::string& path) const { |
| 24 | NGLOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive ({}).", GetName()); | 24 | LOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive ({}).", GetName()); |
| 25 | // TODO(bunnei): Use correct error code | 25 | // TODO(bunnei): Use correct error code |
| 26 | return ResultCode(-1); | 26 | return ResultCode(-1); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | ResultCode RomFS_FileSystem::RenameFile(const std::string& src_path, | 29 | ResultCode RomFS_FileSystem::RenameFile(const std::string& src_path, |
| 30 | const std::string& dest_path) const { | 30 | const std::string& dest_path) const { |
| 31 | NGLOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive ({}).", | 31 | LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive ({}).", GetName()); |
| 32 | GetName()); | ||
| 33 | // TODO(wwylele): Use correct error code | 32 | // TODO(wwylele): Use correct error code |
| 34 | return ResultCode(-1); | 33 | return ResultCode(-1); |
| 35 | } | 34 | } |
| 36 | 35 | ||
| 37 | ResultCode RomFS_FileSystem::DeleteDirectory(const Path& path) const { | 36 | ResultCode RomFS_FileSystem::DeleteDirectory(const Path& path) const { |
| 38 | NGLOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive ({}).", | 37 | LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive ({}).", |
| 39 | GetName()); | 38 | GetName()); |
| 40 | // TODO(wwylele): Use correct error code | 39 | // TODO(wwylele): Use correct error code |
| 41 | return ResultCode(-1); | 40 | return ResultCode(-1); |
| 42 | } | 41 | } |
| 43 | 42 | ||
| 44 | ResultCode RomFS_FileSystem::DeleteDirectoryRecursively(const Path& path) const { | 43 | ResultCode RomFS_FileSystem::DeleteDirectoryRecursively(const Path& path) const { |
| 45 | NGLOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive ({}).", | 44 | LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive ({}).", |
| 46 | GetName()); | 45 | GetName()); |
| 47 | // TODO(wwylele): Use correct error code | 46 | // TODO(wwylele): Use correct error code |
| 48 | return ResultCode(-1); | 47 | return ResultCode(-1); |
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const { | 50 | ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const { |
| 52 | NGLOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive ({}).", GetName()); | 51 | LOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive ({}).", GetName()); |
| 53 | // TODO(bunnei): Use correct error code | 52 | // TODO(bunnei): Use correct error code |
| 54 | return ResultCode(-1); | 53 | return ResultCode(-1); |
| 55 | } | 54 | } |
| 56 | 55 | ||
| 57 | ResultCode RomFS_FileSystem::CreateDirectory(const std::string& path) const { | 56 | ResultCode RomFS_FileSystem::CreateDirectory(const std::string& path) const { |
| 58 | NGLOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive ({}).", | 57 | LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive ({}).", |
| 59 | GetName()); | 58 | GetName()); |
| 60 | // TODO(wwylele): Use correct error code | 59 | // TODO(wwylele): Use correct error code |
| 61 | return ResultCode(-1); | 60 | return ResultCode(-1); |
| 62 | } | 61 | } |
| 63 | 62 | ||
| 64 | ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const { | 63 | ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const { |
| 65 | NGLOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive ({}).", | 64 | LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive ({}).", GetName()); |
| 66 | GetName()); | ||
| 67 | // TODO(wwylele): Use correct error code | 65 | // TODO(wwylele): Use correct error code |
| 68 | return ResultCode(-1); | 66 | return ResultCode(-1); |
| 69 | } | 67 | } |
| 70 | 68 | ||
| 71 | ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory( | 69 | ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory( |
| 72 | const std::string& path) const { | 70 | const std::string& path) const { |
| 73 | NGLOG_WARNING(Service_FS, "Opening Directory in a ROMFS archive"); | 71 | LOG_WARNING(Service_FS, "Opening Directory in a ROMFS archive"); |
| 74 | return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>()); | 72 | return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>()); |
| 75 | } | 73 | } |
| 76 | 74 | ||
| 77 | u64 RomFS_FileSystem::GetFreeSpaceSize() const { | 75 | u64 RomFS_FileSystem::GetFreeSpaceSize() const { |
| 78 | NGLOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive"); | 76 | LOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive"); |
| 79 | return 0; | 77 | return 0; |
| 80 | } | 78 | } |
| 81 | 79 | ||
| 82 | ResultVal<FileSys::EntryType> RomFS_FileSystem::GetEntryType(const std::string& path) const { | 80 | ResultVal<FileSys::EntryType> RomFS_FileSystem::GetEntryType(const std::string& path) const { |
| 83 | NGLOG_CRITICAL(Service_FS, "Called within an ROMFS archive (path {}).", path); | 81 | LOG_CRITICAL(Service_FS, "Called within an ROMFS archive (path {}).", path); |
| 84 | // TODO(wwylele): Use correct error code | 82 | // TODO(wwylele): Use correct error code |
| 85 | return ResultCode(-1); | 83 | return ResultCode(-1); |
| 86 | } | 84 | } |
| 87 | 85 | ||
| 88 | ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { | 86 | ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { |
| 89 | NGLOG_TRACE(Service_FS, "called offset={}, length={}", offset, length); | 87 | LOG_TRACE(Service_FS, "called offset={}, length={}", offset, length); |
| 90 | romfs_file->Seek(data_offset + offset, SEEK_SET); | 88 | romfs_file->Seek(data_offset + offset, SEEK_SET); |
| 91 | size_t read_length = (size_t)std::min((u64)length, data_size - offset); | 89 | size_t read_length = (size_t)std::min((u64)length, data_size - offset); |
| 92 | 90 | ||
| @@ -95,7 +93,7 @@ ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8* | |||
| 95 | 93 | ||
| 96 | ResultVal<size_t> RomFS_Storage::Write(const u64 offset, const size_t length, const bool flush, | 94 | ResultVal<size_t> RomFS_Storage::Write(const u64 offset, const size_t length, const bool flush, |
| 97 | const u8* buffer) const { | 95 | const u8* buffer) const { |
| 98 | NGLOG_ERROR(Service_FS, "Attempted to write to ROMFS file"); | 96 | LOG_ERROR(Service_FS, "Attempted to write to ROMFS file"); |
| 99 | // TODO(Subv): Find error code | 97 | // TODO(Subv): Find error code |
| 100 | return MakeResult<size_t>(0); | 98 | return MakeResult<size_t>(0); |
| 101 | } | 99 | } |
| @@ -105,7 +103,7 @@ u64 RomFS_Storage::GetSize() const { | |||
| 105 | } | 103 | } |
| 106 | 104 | ||
| 107 | bool RomFS_Storage::SetSize(const u64 size) const { | 105 | bool RomFS_Storage::SetSize(const u64 size) const { |
| 108 | NGLOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file"); | 106 | LOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file"); |
| 109 | return false; | 107 | return false; |
| 110 | } | 108 | } |
| 111 | 109 | ||
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index c1be8fee4..f3aa213af 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -17,6 +17,15 @@ SaveData_Factory::SaveData_Factory(std::string nand_directory) | |||
| 17 | 17 | ||
| 18 | ResultVal<std::unique_ptr<FileSystemBackend>> SaveData_Factory::Open(const Path& path) { | 18 | ResultVal<std::unique_ptr<FileSystemBackend>> SaveData_Factory::Open(const Path& path) { |
| 19 | std::string save_directory = GetFullPath(); | 19 | std::string save_directory = GetFullPath(); |
| 20 | |||
| 21 | if (!FileUtil::Exists(save_directory)) { | ||
| 22 | // TODO(bunnei): This is a work-around to always create a save data directory if it does not | ||
| 23 | // already exist. This is a hack, as we do not understand yet how this works on hardware. | ||
| 24 | // Without a save data directory, many games will assert on boot. This should not have any | ||
| 25 | // bad side-effects. | ||
| 26 | FileUtil::CreateFullPath(save_directory); | ||
| 27 | } | ||
| 28 | |||
| 20 | // Return an error if the save data doesn't actually exist. | 29 | // Return an error if the save data doesn't actually exist. |
| 21 | if (!FileUtil::IsDirectory(save_directory)) { | 30 | if (!FileUtil::IsDirectory(save_directory)) { |
| 22 | // TODO(Subv): Find out correct error code. | 31 | // TODO(Subv): Find out correct error code. |
| @@ -28,7 +37,7 @@ ResultVal<std::unique_ptr<FileSystemBackend>> SaveData_Factory::Open(const Path& | |||
| 28 | } | 37 | } |
| 29 | 38 | ||
| 30 | ResultCode SaveData_Factory::Format(const Path& path) { | 39 | ResultCode SaveData_Factory::Format(const Path& path) { |
| 31 | NGLOG_WARNING(Service_FS, "Format archive {}", GetName()); | 40 | LOG_WARNING(Service_FS, "Format archive {}", GetName()); |
| 32 | // Create the save data directory. | 41 | // Create the save data directory. |
| 33 | if (!FileUtil::CreateFullPath(GetFullPath())) { | 42 | if (!FileUtil::CreateFullPath(GetFullPath())) { |
| 34 | // TODO(Subv): Find the correct error code. | 43 | // TODO(Subv): Find the correct error code. |
| @@ -39,7 +48,7 @@ ResultCode SaveData_Factory::Format(const Path& path) { | |||
| 39 | } | 48 | } |
| 40 | 49 | ||
| 41 | ResultVal<ArchiveFormatInfo> SaveData_Factory::GetFormatInfo(const Path& path) const { | 50 | ResultVal<ArchiveFormatInfo> SaveData_Factory::GetFormatInfo(const Path& path) const { |
| 42 | NGLOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName()); | 51 | LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName()); |
| 43 | // TODO(bunnei): Find the right error code for this | 52 | // TODO(bunnei): Find the right error code for this |
| 44 | return ResultCode(-1); | 53 | return ResultCode(-1); |
| 45 | } | 54 | } |
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp index 59ac3e0be..2e5ffb764 100644 --- a/src/core/file_sys/sdmc_factory.cpp +++ b/src/core/file_sys/sdmc_factory.cpp | |||
| @@ -25,13 +25,13 @@ ResultVal<std::unique_ptr<FileSystemBackend>> SDMC_Factory::Open(const Path& pat | |||
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | ResultCode SDMC_Factory::Format(const Path& path) { | 27 | ResultCode SDMC_Factory::Format(const Path& path) { |
| 28 | NGLOG_ERROR(Service_FS, "Unimplemented Format archive {}", GetName()); | 28 | LOG_ERROR(Service_FS, "Unimplemented Format archive {}", GetName()); |
| 29 | // TODO(Subv): Find the right error code for this | 29 | // TODO(Subv): Find the right error code for this |
| 30 | return ResultCode(-1); | 30 | return ResultCode(-1); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | ResultVal<ArchiveFormatInfo> SDMC_Factory::GetFormatInfo(const Path& path) const { | 33 | ResultVal<ArchiveFormatInfo> SDMC_Factory::GetFormatInfo(const Path& path) const { |
| 34 | NGLOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName()); | 34 | LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName()); |
| 35 | // TODO(bunnei): Find the right error code for this | 35 | // TODO(bunnei): Find the right error code for this |
| 36 | return ResultCode(-1); | 36 | return ResultCode(-1); |
| 37 | } | 37 | } |
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 79e52488f..39bdf4e21 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -59,7 +59,7 @@ template <typename InputDeviceType> | |||
| 59 | void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) { | 59 | void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) { |
| 60 | auto pair = std::make_pair(name, std::move(factory)); | 60 | auto pair = std::make_pair(name, std::move(factory)); |
| 61 | if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) { | 61 | if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) { |
| 62 | NGLOG_ERROR(Input, "Factory '{}' already registered", name); | 62 | LOG_ERROR(Input, "Factory '{}' already registered", name); |
| 63 | } | 63 | } |
| 64 | } | 64 | } |
| 65 | 65 | ||
| @@ -71,7 +71,7 @@ void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDevic | |||
| 71 | template <typename InputDeviceType> | 71 | template <typename InputDeviceType> |
| 72 | void UnregisterFactory(const std::string& name) { | 72 | void UnregisterFactory(const std::string& name) { |
| 73 | if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) { | 73 | if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) { |
| 74 | NGLOG_ERROR(Input, "Factory '{}' not registered", name); | 74 | LOG_ERROR(Input, "Factory '{}' not registered", name); |
| 75 | } | 75 | } |
| 76 | } | 76 | } |
| 77 | 77 | ||
| @@ -88,7 +88,7 @@ std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) { | |||
| 88 | const auto pair = factory_list.find(engine); | 88 | const auto pair = factory_list.find(engine); |
| 89 | if (pair == factory_list.end()) { | 89 | if (pair == factory_list.end()) { |
| 90 | if (engine != "null") { | 90 | if (engine != "null") { |
| 91 | NGLOG_ERROR(Input, "Unknown engine name: {}", engine); | 91 | LOG_ERROR(Input, "Unknown engine name: {}", engine); |
| 92 | } | 92 | } |
| 93 | return std::make_unique<InputDeviceType>(); | 93 | return std::make_unique<InputDeviceType>(); |
| 94 | } | 94 | } |
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 2603192fe..938852a1a 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -232,7 +232,7 @@ static u8 HexCharToValue(u8 hex) { | |||
| 232 | return hex - 'A' + 0xA; | 232 | return hex - 'A' + 0xA; |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | NGLOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex); | 235 | LOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex); |
| 236 | return 0; | 236 | return 0; |
| 237 | } | 237 | } |
| 238 | 238 | ||
| @@ -372,7 +372,7 @@ static u8 ReadByte() { | |||
| 372 | u8 c; | 372 | u8 c; |
| 373 | size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL); | 373 | size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL); |
| 374 | if (received_size != 1) { | 374 | if (received_size != 1) { |
| 375 | NGLOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size); | 375 | LOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size); |
| 376 | Shutdown(); | 376 | Shutdown(); |
| 377 | } | 377 | } |
| 378 | 378 | ||
| @@ -413,8 +413,8 @@ static void RemoveBreakpoint(BreakpointType type, PAddr addr) { | |||
| 413 | 413 | ||
| 414 | auto bp = p.find(static_cast<u64>(addr)); | 414 | auto bp = p.find(static_cast<u64>(addr)); |
| 415 | if (bp != p.end()) { | 415 | if (bp != p.end()) { |
| 416 | NGLOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", | 416 | LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", |
| 417 | bp->second.len, bp->second.addr, static_cast<int>(type)); | 417 | bp->second.len, bp->second.addr, static_cast<int>(type)); |
| 418 | p.erase(static_cast<u64>(addr)); | 418 | p.erase(static_cast<u64>(addr)); |
| 419 | } | 419 | } |
| 420 | } | 420 | } |
| @@ -459,10 +459,10 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) { | |||
| 459 | } | 459 | } |
| 460 | 460 | ||
| 461 | if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) { | 461 | if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) { |
| 462 | NGLOG_DEBUG(Debug_GDBStub, | 462 | LOG_DEBUG(Debug_GDBStub, |
| 463 | "Found breakpoint type {} @ {:016X}, range: {:016X}" | 463 | "Found breakpoint type {} @ {:016X}, range: {:016X}" |
| 464 | " - {:016X} ({:X} bytes)", | 464 | " - {:016X} ({:X} bytes)", |
| 465 | static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len); | 465 | static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len); |
| 466 | return true; | 466 | return true; |
| 467 | } | 467 | } |
| 468 | } | 468 | } |
| @@ -478,7 +478,7 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) { | |||
| 478 | static void SendPacket(const char packet) { | 478 | static void SendPacket(const char packet) { |
| 479 | size_t sent_size = send(gdbserver_socket, &packet, 1, 0); | 479 | size_t sent_size = send(gdbserver_socket, &packet, 1, 0); |
| 480 | if (sent_size != 1) { | 480 | if (sent_size != 1) { |
| 481 | NGLOG_ERROR(Debug_GDBStub, "send failed"); | 481 | LOG_ERROR(Debug_GDBStub, "send failed"); |
| 482 | } | 482 | } |
| 483 | } | 483 | } |
| 484 | 484 | ||
| @@ -492,13 +492,13 @@ static void SendReply(const char* reply) { | |||
| 492 | return; | 492 | return; |
| 493 | } | 493 | } |
| 494 | 494 | ||
| 495 | NGLOG_DEBUG(Debug_GDBStub, "Reply: {}", reply); | 495 | LOG_DEBUG(Debug_GDBStub, "Reply: {}", reply); |
| 496 | 496 | ||
| 497 | memset(command_buffer, 0, sizeof(command_buffer)); | 497 | memset(command_buffer, 0, sizeof(command_buffer)); |
| 498 | 498 | ||
| 499 | command_length = static_cast<u32>(strlen(reply)); | 499 | command_length = static_cast<u32>(strlen(reply)); |
| 500 | if (command_length + 4 > sizeof(command_buffer)) { | 500 | if (command_length + 4 > sizeof(command_buffer)) { |
| 501 | NGLOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply"); | 501 | LOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply"); |
| 502 | return; | 502 | return; |
| 503 | } | 503 | } |
| 504 | 504 | ||
| @@ -515,7 +515,7 @@ static void SendReply(const char* reply) { | |||
| 515 | while (left > 0) { | 515 | while (left > 0) { |
| 516 | int sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0); | 516 | int sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0); |
| 517 | if (sent_size < 0) { | 517 | if (sent_size < 0) { |
| 518 | NGLOG_ERROR(Debug_GDBStub, "gdb: send failed"); | 518 | LOG_ERROR(Debug_GDBStub, "gdb: send failed"); |
| 519 | return Shutdown(); | 519 | return Shutdown(); |
| 520 | } | 520 | } |
| 521 | 521 | ||
| @@ -526,7 +526,7 @@ static void SendReply(const char* reply) { | |||
| 526 | 526 | ||
| 527 | /// Handle query command from gdb client. | 527 | /// Handle query command from gdb client. |
| 528 | static void HandleQuery() { | 528 | static void HandleQuery() { |
| 529 | NGLOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); | 529 | LOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); |
| 530 | 530 | ||
| 531 | const char* query = reinterpret_cast<const char*>(command_buffer + 1); | 531 | const char* query = reinterpret_cast<const char*>(command_buffer + 1); |
| 532 | 532 | ||
| @@ -634,18 +634,18 @@ static void ReadCommand() { | |||
| 634 | // ignore ack | 634 | // ignore ack |
| 635 | return; | 635 | return; |
| 636 | } else if (c == 0x03) { | 636 | } else if (c == 0x03) { |
| 637 | NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); | 637 | LOG_INFO(Debug_GDBStub, "gdb: found break command"); |
| 638 | halt_loop = true; | 638 | halt_loop = true; |
| 639 | SendSignal(current_thread, SIGTRAP); | 639 | SendSignal(current_thread, SIGTRAP); |
| 640 | return; | 640 | return; |
| 641 | } else if (c != GDB_STUB_START) { | 641 | } else if (c != GDB_STUB_START) { |
| 642 | NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); | 642 | LOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); |
| 643 | return; | 643 | return; |
| 644 | } | 644 | } |
| 645 | 645 | ||
| 646 | while ((c = ReadByte()) != GDB_STUB_END) { | 646 | while ((c = ReadByte()) != GDB_STUB_END) { |
| 647 | if (command_length >= sizeof(command_buffer)) { | 647 | if (command_length >= sizeof(command_buffer)) { |
| 648 | NGLOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow"); | 648 | LOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow"); |
| 649 | SendPacket(GDB_STUB_NACK); | 649 | SendPacket(GDB_STUB_NACK); |
| 650 | return; | 650 | return; |
| 651 | } | 651 | } |
| @@ -658,10 +658,9 @@ static void ReadCommand() { | |||
| 658 | u8 checksum_calculated = CalculateChecksum(command_buffer, command_length); | 658 | u8 checksum_calculated = CalculateChecksum(command_buffer, command_length); |
| 659 | 659 | ||
| 660 | if (checksum_received != checksum_calculated) { | 660 | if (checksum_received != checksum_calculated) { |
| 661 | NGLOG_ERROR( | 661 | LOG_ERROR(Debug_GDBStub, |
| 662 | Debug_GDBStub, | 662 | "gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})", |
| 663 | "gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})", | 663 | checksum_calculated, checksum_received, command_buffer, command_length); |
| 664 | checksum_calculated, checksum_received, command_buffer, command_length); | ||
| 665 | 664 | ||
| 666 | command_length = 0; | 665 | command_length = 0; |
| 667 | 666 | ||
| @@ -688,7 +687,7 @@ static bool IsDataAvailable() { | |||
| 688 | t.tv_usec = 0; | 687 | t.tv_usec = 0; |
| 689 | 688 | ||
| 690 | if (select(gdbserver_socket + 1, &fd_socket, nullptr, nullptr, &t) < 0) { | 689 | if (select(gdbserver_socket + 1, &fd_socket, nullptr, nullptr, &t) < 0) { |
| 691 | NGLOG_ERROR(Debug_GDBStub, "select failed"); | 690 | LOG_ERROR(Debug_GDBStub, "select failed"); |
| 692 | return false; | 691 | return false; |
| 693 | } | 692 | } |
| 694 | 693 | ||
| @@ -801,7 +800,7 @@ static void ReadMemory() { | |||
| 801 | u64 len = | 800 | u64 len = |
| 802 | HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset)); | 801 | HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset)); |
| 803 | 802 | ||
| 804 | NGLOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); | 803 | LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); |
| 805 | 804 | ||
| 806 | if (len * 2 > sizeof(reply)) { | 805 | if (len * 2 > sizeof(reply)) { |
| 807 | SendReply("E01"); | 806 | SendReply("E01"); |
| @@ -888,8 +887,8 @@ static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) { | |||
| 888 | breakpoint.len = len; | 887 | breakpoint.len = len; |
| 889 | p.insert({addr, breakpoint}); | 888 | p.insert({addr, breakpoint}); |
| 890 | 889 | ||
| 891 | NGLOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", | 890 | LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", |
| 892 | static_cast<int>(type), breakpoint.len, breakpoint.addr); | 891 | static_cast<int>(type), breakpoint.len, breakpoint.addr); |
| 893 | 892 | ||
| 894 | return true; | 893 | return true; |
| 895 | } | 894 | } |
| @@ -996,7 +995,7 @@ void HandlePacket() { | |||
| 996 | return; | 995 | return; |
| 997 | } | 996 | } |
| 998 | 997 | ||
| 999 | NGLOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer); | 998 | LOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer); |
| 1000 | 999 | ||
| 1001 | switch (command_buffer[0]) { | 1000 | switch (command_buffer[0]) { |
| 1002 | case 'q': | 1001 | case 'q': |
| @@ -1010,7 +1009,7 @@ void HandlePacket() { | |||
| 1010 | break; | 1009 | break; |
| 1011 | case 'k': | 1010 | case 'k': |
| 1012 | Shutdown(); | 1011 | Shutdown(); |
| 1013 | NGLOG_INFO(Debug_GDBStub, "killed by gdb"); | 1012 | LOG_INFO(Debug_GDBStub, "killed by gdb"); |
| 1014 | return; | 1013 | return; |
| 1015 | case 'g': | 1014 | case 'g': |
| 1016 | ReadRegisters(); | 1015 | ReadRegisters(); |
| @@ -1092,7 +1091,7 @@ static void Init(u16 port) { | |||
| 1092 | breakpoints_write.clear(); | 1091 | breakpoints_write.clear(); |
| 1093 | 1092 | ||
| 1094 | // Start gdb server | 1093 | // Start gdb server |
| 1095 | NGLOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); | 1094 | LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); |
| 1096 | 1095 | ||
| 1097 | sockaddr_in saddr_server = {}; | 1096 | sockaddr_in saddr_server = {}; |
| 1098 | saddr_server.sin_family = AF_INET; | 1097 | saddr_server.sin_family = AF_INET; |
| @@ -1105,28 +1104,28 @@ static void Init(u16 port) { | |||
| 1105 | 1104 | ||
| 1106 | int tmpsock = static_cast<int>(socket(PF_INET, SOCK_STREAM, 0)); | 1105 | int tmpsock = static_cast<int>(socket(PF_INET, SOCK_STREAM, 0)); |
| 1107 | if (tmpsock == -1) { | 1106 | if (tmpsock == -1) { |
| 1108 | NGLOG_ERROR(Debug_GDBStub, "Failed to create gdb socket"); | 1107 | LOG_ERROR(Debug_GDBStub, "Failed to create gdb socket"); |
| 1109 | } | 1108 | } |
| 1110 | 1109 | ||
| 1111 | // Set socket to SO_REUSEADDR so it can always bind on the same port | 1110 | // Set socket to SO_REUSEADDR so it can always bind on the same port |
| 1112 | int reuse_enabled = 1; | 1111 | int reuse_enabled = 1; |
| 1113 | if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled, | 1112 | if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled, |
| 1114 | sizeof(reuse_enabled)) < 0) { | 1113 | sizeof(reuse_enabled)) < 0) { |
| 1115 | NGLOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option"); | 1114 | LOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option"); |
| 1116 | } | 1115 | } |
| 1117 | 1116 | ||
| 1118 | const sockaddr* server_addr = reinterpret_cast<const sockaddr*>(&saddr_server); | 1117 | const sockaddr* server_addr = reinterpret_cast<const sockaddr*>(&saddr_server); |
| 1119 | socklen_t server_addrlen = sizeof(saddr_server); | 1118 | socklen_t server_addrlen = sizeof(saddr_server); |
| 1120 | if (bind(tmpsock, server_addr, server_addrlen) < 0) { | 1119 | if (bind(tmpsock, server_addr, server_addrlen) < 0) { |
| 1121 | NGLOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket"); | 1120 | LOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket"); |
| 1122 | } | 1121 | } |
| 1123 | 1122 | ||
| 1124 | if (listen(tmpsock, 1) < 0) { | 1123 | if (listen(tmpsock, 1) < 0) { |
| 1125 | NGLOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket"); | 1124 | LOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket"); |
| 1126 | } | 1125 | } |
| 1127 | 1126 | ||
| 1128 | // Wait for gdb to connect | 1127 | // Wait for gdb to connect |
| 1129 | NGLOG_INFO(Debug_GDBStub, "Waiting for gdb to connect..."); | 1128 | LOG_INFO(Debug_GDBStub, "Waiting for gdb to connect..."); |
| 1130 | sockaddr_in saddr_client; | 1129 | sockaddr_in saddr_client; |
| 1131 | sockaddr* client_addr = reinterpret_cast<sockaddr*>(&saddr_client); | 1130 | sockaddr* client_addr = reinterpret_cast<sockaddr*>(&saddr_client); |
| 1132 | socklen_t client_addrlen = sizeof(saddr_client); | 1131 | socklen_t client_addrlen = sizeof(saddr_client); |
| @@ -1137,9 +1136,9 @@ static void Init(u16 port) { | |||
| 1137 | halt_loop = false; | 1136 | halt_loop = false; |
| 1138 | step_loop = false; | 1137 | step_loop = false; |
| 1139 | 1138 | ||
| 1140 | NGLOG_ERROR(Debug_GDBStub, "Failed to accept gdb client"); | 1139 | LOG_ERROR(Debug_GDBStub, "Failed to accept gdb client"); |
| 1141 | } else { | 1140 | } else { |
| 1142 | NGLOG_INFO(Debug_GDBStub, "Client connected."); | 1141 | LOG_INFO(Debug_GDBStub, "Client connected."); |
| 1143 | saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); | 1142 | saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); |
| 1144 | } | 1143 | } |
| 1145 | 1144 | ||
| @@ -1158,7 +1157,7 @@ void Shutdown() { | |||
| 1158 | return; | 1157 | return; |
| 1159 | } | 1158 | } |
| 1160 | 1159 | ||
| 1161 | NGLOG_INFO(Debug_GDBStub, "Stopping GDB ..."); | 1160 | LOG_INFO(Debug_GDBStub, "Stopping GDB ..."); |
| 1162 | if (gdbserver_socket != -1) { | 1161 | if (gdbserver_socket != -1) { |
| 1163 | shutdown(gdbserver_socket, SHUT_RDWR); | 1162 | shutdown(gdbserver_socket, SHUT_RDWR); |
| 1164 | gdbserver_socket = -1; | 1163 | gdbserver_socket = -1; |
| @@ -1168,7 +1167,7 @@ void Shutdown() { | |||
| 1168 | WSACleanup(); | 1167 | WSACleanup(); |
| 1169 | #endif | 1168 | #endif |
| 1170 | 1169 | ||
| 1171 | NGLOG_INFO(Debug_GDBStub, "GDB stopped."); | 1170 | LOG_INFO(Debug_GDBStub, "GDB stopped."); |
| 1172 | } | 1171 | } |
| 1173 | 1172 | ||
| 1174 | bool IsServerEnabled() { | 1173 | bool IsServerEnabled() { |
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp new file mode 100644 index 000000000..e9c8369d7 --- /dev/null +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "common/common_funcs.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/core.h" | ||
| 9 | #include "core/hle/kernel/errors.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/process.h" | ||
| 12 | #include "core/hle/kernel/thread.h" | ||
| 13 | #include "core/hle/lock.h" | ||
| 14 | #include "core/memory.h" | ||
| 15 | |||
| 16 | namespace Kernel { | ||
| 17 | namespace AddressArbiter { | ||
| 18 | |||
| 19 | // Performs actual address waiting logic. | ||
| 20 | static ResultCode WaitForAddress(VAddr address, s64 timeout) { | ||
| 21 | SharedPtr<Thread> current_thread = GetCurrentThread(); | ||
| 22 | current_thread->arb_wait_address = address; | ||
| 23 | current_thread->status = THREADSTATUS_WAIT_ARB; | ||
| 24 | current_thread->wakeup_callback = nullptr; | ||
| 25 | |||
| 26 | current_thread->WakeAfterDelay(timeout); | ||
| 27 | |||
| 28 | Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); | ||
| 29 | return RESULT_TIMEOUT; | ||
| 30 | } | ||
| 31 | |||
| 32 | // Gets the threads waiting on an address. | ||
| 33 | static void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>>& waiting_threads, | ||
| 34 | VAddr address) { | ||
| 35 | auto RetrieveWaitingThreads = | ||
| 36 | [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) { | ||
| 37 | const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); | ||
| 38 | auto& thread_list = scheduler->GetThreadList(); | ||
| 39 | |||
| 40 | for (auto& thread : thread_list) { | ||
| 41 | if (thread->arb_wait_address == arb_addr) | ||
| 42 | waiting_threads.push_back(thread); | ||
| 43 | } | ||
| 44 | }; | ||
| 45 | |||
| 46 | // Retrieve a list of all threads that are waiting for this address. | ||
| 47 | RetrieveWaitingThreads(0, waiting_threads, address); | ||
| 48 | RetrieveWaitingThreads(1, waiting_threads, address); | ||
| 49 | RetrieveWaitingThreads(2, waiting_threads, address); | ||
| 50 | RetrieveWaitingThreads(3, waiting_threads, address); | ||
| 51 | // Sort them by priority, such that the highest priority ones come first. | ||
| 52 | std::sort(waiting_threads.begin(), waiting_threads.end(), | ||
| 53 | [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { | ||
| 54 | return lhs->current_priority < rhs->current_priority; | ||
| 55 | }); | ||
| 56 | } | ||
| 57 | |||
| 58 | // Wake up num_to_wake (or all) threads in a vector. | ||
| 59 | static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) { | ||
| 60 | // Only process up to 'target' threads, unless 'target' is <= 0, in which case process | ||
| 61 | // them all. | ||
| 62 | size_t last = waiting_threads.size(); | ||
| 63 | if (num_to_wake > 0) | ||
| 64 | last = num_to_wake; | ||
| 65 | |||
| 66 | // Signal the waiting threads. | ||
| 67 | for (size_t i = 0; i < last; i++) { | ||
| 68 | ASSERT(waiting_threads[i]->status = THREADSTATUS_WAIT_ARB); | ||
| 69 | waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 70 | waiting_threads[i]->arb_wait_address = 0; | ||
| 71 | waiting_threads[i]->ResumeFromWait(); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | // Signals an address being waited on. | ||
| 76 | ResultCode SignalToAddress(VAddr address, s32 num_to_wake) { | ||
| 77 | // Get threads waiting on the address. | ||
| 78 | std::vector<SharedPtr<Thread>> waiting_threads; | ||
| 79 | GetThreadsWaitingOnAddress(waiting_threads, address); | ||
| 80 | |||
| 81 | WakeThreads(waiting_threads, num_to_wake); | ||
| 82 | return RESULT_SUCCESS; | ||
| 83 | } | ||
| 84 | |||
| 85 | // Signals an address being waited on and increments its value if equal to the value argument. | ||
| 86 | ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { | ||
| 87 | // Ensure that we can write to the address. | ||
| 88 | if (!Memory::IsValidVirtualAddress(address)) { | ||
| 89 | return ERR_INVALID_ADDRESS_STATE; | ||
| 90 | } | ||
| 91 | |||
| 92 | if (static_cast<s32>(Memory::Read32(address)) == value) { | ||
| 93 | Memory::Write32(address, static_cast<u32>(value + 1)); | ||
| 94 | } else { | ||
| 95 | return ERR_INVALID_STATE; | ||
| 96 | } | ||
| 97 | |||
| 98 | return SignalToAddress(address, num_to_wake); | ||
| 99 | } | ||
| 100 | |||
| 101 | // Signals an address being waited on and modifies its value based on waiting thread count if equal | ||
| 102 | // to the value argument. | ||
| 103 | ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, | ||
| 104 | s32 num_to_wake) { | ||
| 105 | // Ensure that we can write to the address. | ||
| 106 | if (!Memory::IsValidVirtualAddress(address)) { | ||
| 107 | return ERR_INVALID_ADDRESS_STATE; | ||
| 108 | } | ||
| 109 | |||
| 110 | // Get threads waiting on the address. | ||
| 111 | std::vector<SharedPtr<Thread>> waiting_threads; | ||
| 112 | GetThreadsWaitingOnAddress(waiting_threads, address); | ||
| 113 | |||
| 114 | // Determine the modified value depending on the waiting count. | ||
| 115 | s32 updated_value; | ||
| 116 | if (waiting_threads.size() == 0) { | ||
| 117 | updated_value = value - 1; | ||
| 118 | } else if (num_to_wake <= 0 || waiting_threads.size() <= num_to_wake) { | ||
| 119 | updated_value = value + 1; | ||
| 120 | } else { | ||
| 121 | updated_value = value; | ||
| 122 | } | ||
| 123 | |||
| 124 | if (static_cast<s32>(Memory::Read32(address)) == value) { | ||
| 125 | Memory::Write32(address, static_cast<u32>(updated_value)); | ||
| 126 | } else { | ||
| 127 | return ERR_INVALID_STATE; | ||
| 128 | } | ||
| 129 | |||
| 130 | WakeThreads(waiting_threads, num_to_wake); | ||
| 131 | return RESULT_SUCCESS; | ||
| 132 | } | ||
| 133 | |||
| 134 | // Waits on an address if the value passed is less than the argument value, optionally decrementing. | ||
| 135 | ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { | ||
| 136 | // Ensure that we can read the address. | ||
| 137 | if (!Memory::IsValidVirtualAddress(address)) { | ||
| 138 | return ERR_INVALID_ADDRESS_STATE; | ||
| 139 | } | ||
| 140 | |||
| 141 | s32 cur_value = static_cast<s32>(Memory::Read32(address)); | ||
| 142 | if (cur_value < value) { | ||
| 143 | Memory::Write32(address, static_cast<u32>(cur_value - 1)); | ||
| 144 | } else { | ||
| 145 | return ERR_INVALID_STATE; | ||
| 146 | } | ||
| 147 | // Short-circuit without rescheduling, if timeout is zero. | ||
| 148 | if (timeout == 0) { | ||
| 149 | return RESULT_TIMEOUT; | ||
| 150 | } | ||
| 151 | |||
| 152 | return WaitForAddress(address, timeout); | ||
| 153 | } | ||
| 154 | |||
| 155 | // Waits on an address if the value passed is equal to the argument value. | ||
| 156 | ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { | ||
| 157 | // Ensure that we can read the address. | ||
| 158 | if (!Memory::IsValidVirtualAddress(address)) { | ||
| 159 | return ERR_INVALID_ADDRESS_STATE; | ||
| 160 | } | ||
| 161 | // Only wait for the address if equal. | ||
| 162 | if (static_cast<s32>(Memory::Read32(address)) != value) { | ||
| 163 | return ERR_INVALID_STATE; | ||
| 164 | } | ||
| 165 | // Short-circuit without rescheduling, if timeout is zero. | ||
| 166 | if (timeout == 0) { | ||
| 167 | return RESULT_TIMEOUT; | ||
| 168 | } | ||
| 169 | |||
| 170 | return WaitForAddress(address, timeout); | ||
| 171 | } | ||
| 172 | } // namespace AddressArbiter | ||
| 173 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h new file mode 100644 index 000000000..f20f3dbc0 --- /dev/null +++ b/src/core/hle/kernel/address_arbiter.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/result.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | namespace AddressArbiter { | ||
| 12 | enum class ArbitrationType { | ||
| 13 | WaitIfLessThan = 0, | ||
| 14 | DecrementAndWaitIfLessThan = 1, | ||
| 15 | WaitIfEqual = 2, | ||
| 16 | }; | ||
| 17 | |||
| 18 | enum class SignalType { | ||
| 19 | Signal = 0, | ||
| 20 | IncrementAndSignalIfEqual = 1, | ||
| 21 | ModifyByWaitingCountAndSignalIfEqual = 2, | ||
| 22 | }; | ||
| 23 | |||
| 24 | ResultCode SignalToAddress(VAddr address, s32 num_to_wake); | ||
| 25 | ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); | ||
| 26 | ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); | ||
| 27 | |||
| 28 | ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement); | ||
| 29 | ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); | ||
| 30 | } // namespace AddressArbiter | ||
| 31 | |||
| 32 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index e1b5430bf..221cb1bb5 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h | |||
| @@ -20,13 +20,16 @@ enum { | |||
| 20 | MaxConnectionsReached = 52, | 20 | MaxConnectionsReached = 52, |
| 21 | 21 | ||
| 22 | // Confirmed Switch OS error codes | 22 | // Confirmed Switch OS error codes |
| 23 | MisalignedAddress = 102, | 23 | InvalidAddress = 102, |
| 24 | InvalidMemoryState = 106, | ||
| 24 | InvalidProcessorId = 113, | 25 | InvalidProcessorId = 113, |
| 25 | InvalidHandle = 114, | 26 | InvalidHandle = 114, |
| 26 | InvalidCombination = 116, | 27 | InvalidCombination = 116, |
| 27 | Timeout = 117, | 28 | Timeout = 117, |
| 28 | SynchronizationCanceled = 118, | 29 | SynchronizationCanceled = 118, |
| 29 | TooLarge = 119, | 30 | TooLarge = 119, |
| 31 | InvalidEnumValue = 120, | ||
| 32 | InvalidState = 125, | ||
| 30 | }; | 33 | }; |
| 31 | } | 34 | } |
| 32 | 35 | ||
| @@ -39,14 +42,15 @@ constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1); | |||
| 39 | constexpr ResultCode ERR_PORT_NAME_TOO_LONG(-1); | 42 | constexpr ResultCode ERR_PORT_NAME_TOO_LONG(-1); |
| 40 | constexpr ResultCode ERR_WRONG_PERMISSION(-1); | 43 | constexpr ResultCode ERR_WRONG_PERMISSION(-1); |
| 41 | constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1); | 44 | constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1); |
| 42 | constexpr ResultCode ERR_INVALID_ENUM_VALUE(-1); | 45 | constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue); |
| 43 | constexpr ResultCode ERR_INVALID_ENUM_VALUE_FND(-1); | 46 | constexpr ResultCode ERR_INVALID_ENUM_VALUE_FND(-1); |
| 44 | constexpr ResultCode ERR_INVALID_COMBINATION(-1); | 47 | constexpr ResultCode ERR_INVALID_COMBINATION(-1); |
| 45 | constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(-1); | 48 | constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(-1); |
| 46 | constexpr ResultCode ERR_OUT_OF_MEMORY(-1); | 49 | constexpr ResultCode ERR_OUT_OF_MEMORY(-1); |
| 47 | constexpr ResultCode ERR_INVALID_ADDRESS(-1); | 50 | constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress); |
| 48 | constexpr ResultCode ERR_INVALID_ADDRESS_STATE(-1); | 51 | constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); |
| 49 | constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); | 52 | constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); |
| 53 | constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); | ||
| 50 | constexpr ResultCode ERR_INVALID_POINTER(-1); | 54 | constexpr ResultCode ERR_INVALID_POINTER(-1); |
| 51 | constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); | 55 | constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); |
| 52 | constexpr ResultCode ERR_NOT_AUTHORIZED(-1); | 56 | constexpr ResultCode ERR_NOT_AUTHORIZED(-1); |
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index f7a9920d8..7dd67f80f 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp | |||
| @@ -26,7 +26,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { | |||
| 26 | 26 | ||
| 27 | u16 slot = next_free_slot; | 27 | u16 slot = next_free_slot; |
| 28 | if (slot >= generations.size()) { | 28 | if (slot >= generations.size()) { |
| 29 | NGLOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); | 29 | LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); |
| 30 | return ERR_OUT_OF_HANDLES; | 30 | return ERR_OUT_OF_HANDLES; |
| 31 | } | 31 | } |
| 32 | next_free_slot = generations[slot]; | 32 | next_free_slot = generations[slot]; |
| @@ -48,7 +48,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { | |||
| 48 | ResultVal<Handle> HandleTable::Duplicate(Handle handle) { | 48 | ResultVal<Handle> HandleTable::Duplicate(Handle handle) { |
| 49 | SharedPtr<Object> object = GetGeneric(handle); | 49 | SharedPtr<Object> object = GetGeneric(handle); |
| 50 | if (object == nullptr) { | 50 | if (object == nullptr) { |
| 51 | NGLOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); | 51 | LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); |
| 52 | return ERR_INVALID_HANDLE; | 52 | return ERR_INVALID_HANDLE; |
| 53 | } | 53 | } |
| 54 | return Create(std::move(object)); | 54 | return Create(std::move(object)); |
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 01904467e..609cdbff2 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -120,7 +120,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { | |||
| 120 | std::make_shared<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>()); | 120 | std::make_shared<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>()); |
| 121 | } else { | 121 | } else { |
| 122 | if (Session()->IsDomain()) | 122 | if (Session()->IsDomain()) |
| 123 | NGLOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); | 123 | LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); |
| 124 | } | 124 | } |
| 125 | } | 125 | } |
| 126 | 126 | ||
| @@ -271,11 +271,16 @@ std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { | |||
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffer_index) const { | 273 | size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffer_index) const { |
| 274 | if (size == 0) { | ||
| 275 | LOG_WARNING(Core, "skip empty buffer write"); | ||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 274 | const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; | 279 | const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; |
| 275 | const size_t buffer_size{GetWriteBufferSize(buffer_index)}; | 280 | const size_t buffer_size{GetWriteBufferSize(buffer_index)}; |
| 276 | if (size > buffer_size) { | 281 | if (size > buffer_size) { |
| 277 | NGLOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, | 282 | LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, |
| 278 | buffer_size); | 283 | buffer_size); |
| 279 | size = buffer_size; // TODO(bunnei): This needs to be HW tested | 284 | size = buffer_size; // TODO(bunnei): This needs to be HW tested |
| 280 | } | 285 | } |
| 281 | 286 | ||
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index bc144f3de..65560226d 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -59,7 +59,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, | |||
| 59 | Handle requesting_thread_handle) { | 59 | Handle requesting_thread_handle) { |
| 60 | // The mutex address must be 4-byte aligned | 60 | // The mutex address must be 4-byte aligned |
| 61 | if ((address % sizeof(u32)) != 0) { | 61 | if ((address % sizeof(u32)) != 0) { |
| 62 | return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress); | 62 | return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle); | 65 | SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle); |
| @@ -97,7 +97,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, | |||
| 97 | ResultCode Mutex::Release(VAddr address) { | 97 | ResultCode Mutex::Release(VAddr address) { |
| 98 | // The mutex address must be 4-byte aligned | 98 | // The mutex address must be 4-byte aligned |
| 99 | if ((address % sizeof(u32)) != 0) { | 99 | if ((address % sizeof(u32)) != 0) { |
| 100 | return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress); | 100 | return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address); | 103 | auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address); |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 651d932d3..0c0506085 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -54,7 +54,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 54 | continue; | 54 | continue; |
| 55 | } else if ((type & 0xF00) == 0xE00) { // 0x0FFF | 55 | } else if ((type & 0xF00) == 0xE00) { // 0x0FFF |
| 56 | // Allowed interrupts list | 56 | // Allowed interrupts list |
| 57 | NGLOG_WARNING(Loader, "ExHeader allowed interrupts list ignored"); | 57 | LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored"); |
| 58 | } else if ((type & 0xF80) == 0xF00) { // 0x07FF | 58 | } else if ((type & 0xF80) == 0xF00) { // 0x07FF |
| 59 | // Allowed syscalls mask | 59 | // Allowed syscalls mask |
| 60 | unsigned int index = ((descriptor >> 24) & 7) * 24; | 60 | unsigned int index = ((descriptor >> 24) & 7) * 24; |
| @@ -74,7 +74,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 74 | } else if ((type & 0xFFE) == 0xFF8) { // 0x001F | 74 | } else if ((type & 0xFFE) == 0xFF8) { // 0x001F |
| 75 | // Mapped memory range | 75 | // Mapped memory range |
| 76 | if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) { | 76 | if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) { |
| 77 | NGLOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored."); | 77 | LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored."); |
| 78 | continue; | 78 | continue; |
| 79 | } | 79 | } |
| 80 | u32 end_desc = kernel_caps[i + 1]; | 80 | u32 end_desc = kernel_caps[i + 1]; |
| @@ -109,9 +109,9 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 109 | 109 | ||
| 110 | int minor = kernel_version & 0xFF; | 110 | int minor = kernel_version & 0xFF; |
| 111 | int major = (kernel_version >> 8) & 0xFF; | 111 | int major = (kernel_version >> 8) & 0xFF; |
| 112 | NGLOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor); | 112 | LOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor); |
| 113 | } else { | 113 | } else { |
| 114 | NGLOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x{:08X}", descriptor); | 114 | LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x{:08X}", descriptor); |
| 115 | } | 115 | } |
| 116 | } | 116 | } |
| 117 | } | 117 | } |
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index 0ef5fc57d..17a3e8a74 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp | |||
| @@ -29,7 +29,7 @@ SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory cat | |||
| 29 | case ResourceLimitCategory::OTHER: | 29 | case ResourceLimitCategory::OTHER: |
| 30 | return resource_limits[static_cast<u8>(category)]; | 30 | return resource_limits[static_cast<u8>(category)]; |
| 31 | default: | 31 | default: |
| 32 | NGLOG_CRITICAL(Kernel, "Unknown resource limit category"); | 32 | LOG_CRITICAL(Kernel, "Unknown resource limit category"); |
| 33 | UNREACHABLE(); | 33 | UNREACHABLE(); |
| 34 | } | 34 | } |
| 35 | } | 35 | } |
| @@ -55,7 +55,7 @@ s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { | |||
| 55 | case ResourceType::CPUTime: | 55 | case ResourceType::CPUTime: |
| 56 | return current_cpu_time; | 56 | return current_cpu_time; |
| 57 | default: | 57 | default: |
| 58 | NGLOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource)); | 58 | LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource)); |
| 59 | UNIMPLEMENTED(); | 59 | UNIMPLEMENTED(); |
| 60 | return 0; | 60 | return 0; |
| 61 | } | 61 | } |
| @@ -84,7 +84,7 @@ u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { | |||
| 84 | case ResourceType::CPUTime: | 84 | case ResourceType::CPUTime: |
| 85 | return max_cpu_time; | 85 | return max_cpu_time; |
| 86 | default: | 86 | default: |
| 87 | NGLOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource)); | 87 | LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource)); |
| 88 | UNIMPLEMENTED(); | 88 | UNIMPLEMENTED(); |
| 89 | return 0; | 89 | return 0; |
| 90 | } | 90 | } |
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 9cb9e0e5c..11c2cb69e 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp | |||
| @@ -99,11 +99,11 @@ void Scheduler::Reschedule() { | |||
| 99 | Thread* next = PopNextReadyThread(); | 99 | Thread* next = PopNextReadyThread(); |
| 100 | 100 | ||
| 101 | if (cur && next) { | 101 | if (cur && next) { |
| 102 | NGLOG_TRACE(Kernel, "context switch {} -> {}", cur->GetObjectId(), next->GetObjectId()); | 102 | LOG_TRACE(Kernel, "context switch {} -> {}", cur->GetObjectId(), next->GetObjectId()); |
| 103 | } else if (cur) { | 103 | } else if (cur) { |
| 104 | NGLOG_TRACE(Kernel, "context switch {} -> idle", cur->GetObjectId()); | 104 | LOG_TRACE(Kernel, "context switch {} -> idle", cur->GetObjectId()); |
| 105 | } else if (next) { | 105 | } else if (next) { |
| 106 | NGLOG_TRACE(Kernel, "context switch idle -> {}", next->GetObjectId()); | 106 | LOG_TRACE(Kernel, "context switch idle -> {}", next->GetObjectId()); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | SwitchContext(next); | 109 | SwitchContext(next); |
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index bf812c543..0d5cba1d9 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -71,7 +71,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con | |||
| 71 | return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); | 71 | return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); |
| 72 | 72 | ||
| 73 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { | 73 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { |
| 74 | NGLOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); | 74 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); |
| 75 | 75 | ||
| 76 | domain_request_handlers[object_id - 1] = nullptr; | 76 | domain_request_handlers[object_id - 1] = nullptr; |
| 77 | 77 | ||
| @@ -81,8 +81,8 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con | |||
| 81 | } | 81 | } |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | NGLOG_CRITICAL(IPC, "Unknown domain command={}", | 84 | LOG_CRITICAL(IPC, "Unknown domain command={}", |
| 85 | static_cast<int>(domain_message_header->command.Value())); | 85 | static_cast<int>(domain_message_header->command.Value())); |
| 86 | ASSERT(false); | 86 | ASSERT(false); |
| 87 | } | 87 | } |
| 88 | 88 | ||
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index ac4921298..93f7f2772 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -107,16 +107,16 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 107 | 107 | ||
| 108 | // Error out if the requested permissions don't match what the creator process allows. | 108 | // Error out if the requested permissions don't match what the creator process allows. |
| 109 | if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { | 109 | if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { |
| 110 | NGLOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match", | 110 | LOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match", |
| 111 | GetObjectId(), address, name); | 111 | GetObjectId(), address, name); |
| 112 | return ERR_INVALID_COMBINATION; | 112 | return ERR_INVALID_COMBINATION; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | // Error out if the provided permissions are not compatible with what the creator process needs. | 115 | // Error out if the provided permissions are not compatible with what the creator process needs. |
| 116 | if (other_permissions != MemoryPermission::DontCare && | 116 | if (other_permissions != MemoryPermission::DontCare && |
| 117 | static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { | 117 | static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { |
| 118 | NGLOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match", | 118 | LOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match", |
| 119 | GetObjectId(), address, name); | 119 | GetObjectId(), address, name); |
| 120 | return ERR_WRONG_PERMISSION; | 120 | return ERR_WRONG_PERMISSION; |
| 121 | } | 121 | } |
| 122 | 122 | ||
| @@ -131,7 +131,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 131 | auto result = target_process->vm_manager.MapMemoryBlock( | 131 | auto result = target_process->vm_manager.MapMemoryBlock( |
| 132 | target_address, backing_block, backing_block_offset, size, MemoryState::Shared); | 132 | target_address, backing_block, backing_block_offset, size, MemoryState::Shared); |
| 133 | if (result.Failed()) { | 133 | if (result.Failed()) { |
| 134 | NGLOG_ERROR( | 134 | LOG_ERROR( |
| 135 | Kernel, | 135 | Kernel, |
| 136 | "cannot map id={}, target_address=0x{:X} name={}, error mapping to virtual memory", | 136 | "cannot map id={}, target_address=0x{:X} name={}, error mapping to virtual memory", |
| 137 | GetObjectId(), target_address, name); | 137 | GetObjectId(), target_address, name); |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index ec3601e8b..5ad923fe7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "common/string_util.h" | 11 | #include "common/string_util.h" |
| 12 | #include "core/core.h" | 12 | #include "core/core.h" |
| 13 | #include "core/core_timing.h" | 13 | #include "core/core_timing.h" |
| 14 | #include "core/hle/kernel/address_arbiter.h" | ||
| 14 | #include "core/hle/kernel/client_port.h" | 15 | #include "core/hle/kernel/client_port.h" |
| 15 | #include "core/hle/kernel/client_session.h" | 16 | #include "core/hle/kernel/client_session.h" |
| 16 | #include "core/hle/kernel/event.h" | 17 | #include "core/hle/kernel/event.h" |
| @@ -31,7 +32,7 @@ namespace Kernel { | |||
| 31 | 32 | ||
| 32 | /// Set the process heap to a given Size. It can both extend and shrink the heap. | 33 | /// Set the process heap to a given Size. It can both extend and shrink the heap. |
| 33 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | 34 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { |
| 34 | NGLOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); | 35 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); |
| 35 | auto& process = *Core::CurrentProcess(); | 36 | auto& process = *Core::CurrentProcess(); |
| 36 | CASCADE_RESULT(*heap_addr, | 37 | CASCADE_RESULT(*heap_addr, |
| 37 | process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); | 38 | process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); |
| @@ -39,21 +40,21 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | |||
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) { | 42 | static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) { |
| 42 | NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, addr=0x{:X}", addr); | 43 | LOG_WARNING(Kernel_SVC, "(STUBBED) called, addr=0x{:X}", addr); |
| 43 | return RESULT_SUCCESS; | 44 | return RESULT_SUCCESS; |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | /// Maps a memory range into a different range. | 47 | /// Maps a memory range into a different range. |
| 47 | static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 48 | static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { |
| 48 | NGLOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, | 49 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, |
| 49 | src_addr, size); | 50 | src_addr, size); |
| 50 | return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); | 51 | return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | /// Unmaps a region that was previously mapped with svcMapMemory | 54 | /// Unmaps a region that was previously mapped with svcMapMemory |
| 54 | static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 55 | static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { |
| 55 | NGLOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, | 56 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, |
| 56 | src_addr, size); | 57 | src_addr, size); |
| 57 | return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); | 58 | return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); |
| 58 | } | 59 | } |
| 59 | 60 | ||
| @@ -68,11 +69,11 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address | |||
| 68 | if (port_name.size() > PortNameMaxLength) | 69 | if (port_name.size() > PortNameMaxLength) |
| 69 | return ERR_PORT_NAME_TOO_LONG; | 70 | return ERR_PORT_NAME_TOO_LONG; |
| 70 | 71 | ||
| 71 | NGLOG_TRACE(Kernel_SVC, "called port_name={}", port_name); | 72 | LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); |
| 72 | 73 | ||
| 73 | auto it = Service::g_kernel_named_ports.find(port_name); | 74 | auto it = Service::g_kernel_named_ports.find(port_name); |
| 74 | if (it == Service::g_kernel_named_ports.end()) { | 75 | if (it == Service::g_kernel_named_ports.end()) { |
| 75 | NGLOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); | 76 | LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); |
| 76 | return ERR_NOT_FOUND; | 77 | return ERR_NOT_FOUND; |
| 77 | } | 78 | } |
| 78 | 79 | ||
| @@ -90,11 +91,11 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address | |||
| 90 | static ResultCode SendSyncRequest(Handle handle) { | 91 | static ResultCode SendSyncRequest(Handle handle) { |
| 91 | SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle); | 92 | SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle); |
| 92 | if (!session) { | 93 | if (!session) { |
| 93 | NGLOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); | 94 | LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); |
| 94 | return ERR_INVALID_HANDLE; | 95 | return ERR_INVALID_HANDLE; |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | NGLOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); | 98 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); |
| 98 | 99 | ||
| 99 | Core::System::GetInstance().PrepareReschedule(); | 100 | Core::System::GetInstance().PrepareReschedule(); |
| 100 | 101 | ||
| @@ -105,7 +106,7 @@ static ResultCode SendSyncRequest(Handle handle) { | |||
| 105 | 106 | ||
| 106 | /// Get the ID for the specified thread. | 107 | /// Get the ID for the specified thread. |
| 107 | static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { | 108 | static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { |
| 108 | NGLOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); | 109 | LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); |
| 109 | 110 | ||
| 110 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); | 111 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); |
| 111 | if (!thread) { | 112 | if (!thread) { |
| @@ -118,7 +119,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { | |||
| 118 | 119 | ||
| 119 | /// Get the ID of the specified process | 120 | /// Get the ID of the specified process |
| 120 | static ResultCode GetProcessId(u32* process_id, Handle process_handle) { | 121 | static ResultCode GetProcessId(u32* process_id, Handle process_handle) { |
| 121 | NGLOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle); | 122 | LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle); |
| 122 | 123 | ||
| 123 | const SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle); | 124 | const SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle); |
| 124 | if (!process) { | 125 | if (!process) { |
| @@ -148,8 +149,8 @@ static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thr | |||
| 148 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 149 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 149 | static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count, | 150 | static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count, |
| 150 | s64 nano_seconds) { | 151 | s64 nano_seconds) { |
| 151 | NGLOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", | 152 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", |
| 152 | handles_address, handle_count, nano_seconds); | 153 | handles_address, handle_count, nano_seconds); |
| 153 | 154 | ||
| 154 | if (!Memory::IsValidVirtualAddress(handles_address)) | 155 | if (!Memory::IsValidVirtualAddress(handles_address)) |
| 155 | return ERR_INVALID_POINTER; | 156 | return ERR_INVALID_POINTER; |
| @@ -209,7 +210,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 | |||
| 209 | 210 | ||
| 210 | /// Resumes a thread waiting on WaitSynchronization | 211 | /// Resumes a thread waiting on WaitSynchronization |
| 211 | static ResultCode CancelSynchronization(Handle thread_handle) { | 212 | static ResultCode CancelSynchronization(Handle thread_handle) { |
| 212 | NGLOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); | 213 | LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); |
| 213 | 214 | ||
| 214 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); | 215 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); |
| 215 | if (!thread) { | 216 | if (!thread) { |
| @@ -226,24 +227,24 @@ static ResultCode CancelSynchronization(Handle thread_handle) { | |||
| 226 | /// Attempts to locks a mutex, creating it if it does not already exist | 227 | /// Attempts to locks a mutex, creating it if it does not already exist |
| 227 | static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, | 228 | static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, |
| 228 | Handle requesting_thread_handle) { | 229 | Handle requesting_thread_handle) { |
| 229 | NGLOG_TRACE(Kernel_SVC, | 230 | LOG_TRACE(Kernel_SVC, |
| 230 | "called holding_thread_handle=0x{:08X}, mutex_addr=0x{:X}, " | 231 | "called holding_thread_handle=0x{:08X}, mutex_addr=0x{:X}, " |
| 231 | "requesting_current_thread_handle=0x{:08X}", | 232 | "requesting_current_thread_handle=0x{:08X}", |
| 232 | holding_thread_handle, mutex_addr, requesting_thread_handle); | 233 | holding_thread_handle, mutex_addr, requesting_thread_handle); |
| 233 | 234 | ||
| 234 | return Mutex::TryAcquire(mutex_addr, holding_thread_handle, requesting_thread_handle); | 235 | return Mutex::TryAcquire(mutex_addr, holding_thread_handle, requesting_thread_handle); |
| 235 | } | 236 | } |
| 236 | 237 | ||
| 237 | /// Unlock a mutex | 238 | /// Unlock a mutex |
| 238 | static ResultCode ArbitrateUnlock(VAddr mutex_addr) { | 239 | static ResultCode ArbitrateUnlock(VAddr mutex_addr) { |
| 239 | NGLOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); | 240 | LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); |
| 240 | 241 | ||
| 241 | return Mutex::Release(mutex_addr); | 242 | return Mutex::Release(mutex_addr); |
| 242 | } | 243 | } |
| 243 | 244 | ||
| 244 | /// Break program execution | 245 | /// Break program execution |
| 245 | static void Break(u64 unk_0, u64 unk_1, u64 unk_2) { | 246 | static void Break(u64 unk_0, u64 unk_1, u64 unk_2) { |
| 246 | NGLOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); | 247 | LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); |
| 247 | ASSERT(false); | 248 | ASSERT(false); |
| 248 | } | 249 | } |
| 249 | 250 | ||
| @@ -251,13 +252,13 @@ static void Break(u64 unk_0, u64 unk_1, u64 unk_2) { | |||
| 251 | static void OutputDebugString(VAddr address, s32 len) { | 252 | static void OutputDebugString(VAddr address, s32 len) { |
| 252 | std::string str(len, '\0'); | 253 | std::string str(len, '\0'); |
| 253 | Memory::ReadBlock(address, str.data(), str.size()); | 254 | Memory::ReadBlock(address, str.data(), str.size()); |
| 254 | NGLOG_DEBUG(Debug_Emulated, "{}", str); | 255 | LOG_DEBUG(Debug_Emulated, "{}", str); |
| 255 | } | 256 | } |
| 256 | 257 | ||
| 257 | /// Gets system/memory information for the current process | 258 | /// Gets system/memory information for the current process |
| 258 | static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) { | 259 | static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) { |
| 259 | NGLOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, | 260 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, |
| 260 | info_sub_id, handle); | 261 | info_sub_id, handle); |
| 261 | 262 | ||
| 262 | auto& vm_manager = Core::CurrentProcess()->vm_manager; | 263 | auto& vm_manager = Core::CurrentProcess()->vm_manager; |
| 263 | 264 | ||
| @@ -308,12 +309,17 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 308 | *result = Core::CurrentProcess()->is_virtual_address_memory_enabled; | 309 | *result = Core::CurrentProcess()->is_virtual_address_memory_enabled; |
| 309 | break; | 310 | break; |
| 310 | case GetInfoType::TitleId: | 311 | case GetInfoType::TitleId: |
| 311 | NGLOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0"); | 312 | LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0"); |
| 312 | *result = 0; | 313 | *result = 0; |
| 313 | break; | 314 | break; |
| 314 | case GetInfoType::PrivilegedProcessId: | 315 | case GetInfoType::PrivilegedProcessId: |
| 315 | NGLOG_WARNING(Kernel_SVC, | 316 | LOG_WARNING(Kernel_SVC, |
| 316 | "(STUBBED) Attempted to query privileged process id bounds, returned 0"); | 317 | "(STUBBED) Attempted to query privileged process id bounds, returned 0"); |
| 318 | *result = 0; | ||
| 319 | break; | ||
| 320 | case GetInfoType::UserExceptionContextAddr: | ||
| 321 | LOG_WARNING(Kernel_SVC, | ||
| 322 | "(STUBBED) Attempted to query user exception context address, returned 0"); | ||
| 317 | *result = 0; | 323 | *result = 0; |
| 318 | break; | 324 | break; |
| 319 | default: | 325 | default: |
| @@ -325,14 +331,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 325 | 331 | ||
| 326 | /// Sets the thread activity | 332 | /// Sets the thread activity |
| 327 | static ResultCode SetThreadActivity(Handle handle, u32 unknown) { | 333 | static ResultCode SetThreadActivity(Handle handle, u32 unknown) { |
| 328 | NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, unknown=0x{:08X}", handle, | 334 | LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, unknown=0x{:08X}", handle, unknown); |
| 329 | unknown); | ||
| 330 | return RESULT_SUCCESS; | 335 | return RESULT_SUCCESS; |
| 331 | } | 336 | } |
| 332 | 337 | ||
| 333 | /// Gets the thread context | 338 | /// Gets the thread context |
| 334 | static ResultCode GetThreadContext(Handle handle, VAddr addr) { | 339 | static ResultCode GetThreadContext(Handle handle, VAddr addr) { |
| 335 | NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr); | 340 | LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr); |
| 336 | return RESULT_SUCCESS; | 341 | return RESULT_SUCCESS; |
| 337 | } | 342 | } |
| 338 | 343 | ||
| @@ -371,16 +376,15 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { | |||
| 371 | 376 | ||
| 372 | /// Get which CPU core is executing the current thread | 377 | /// Get which CPU core is executing the current thread |
| 373 | static u32 GetCurrentProcessorNumber() { | 378 | static u32 GetCurrentProcessorNumber() { |
| 374 | NGLOG_TRACE(Kernel_SVC, "called"); | 379 | LOG_TRACE(Kernel_SVC, "called"); |
| 375 | return GetCurrentThread()->processor_id; | 380 | return GetCurrentThread()->processor_id; |
| 376 | } | 381 | } |
| 377 | 382 | ||
| 378 | static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size, | 383 | static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size, |
| 379 | u32 permissions) { | 384 | u32 permissions) { |
| 380 | NGLOG_TRACE( | 385 | LOG_TRACE(Kernel_SVC, |
| 381 | Kernel_SVC, | 386 | "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", |
| 382 | "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", | 387 | shared_memory_handle, addr, size, permissions); |
| 383 | shared_memory_handle, addr, size, permissions); | ||
| 384 | 388 | ||
| 385 | SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); | 389 | SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); |
| 386 | if (!shared_memory) { | 390 | if (!shared_memory) { |
| @@ -400,15 +404,15 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s | |||
| 400 | return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, | 404 | return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, |
| 401 | MemoryPermission::DontCare); | 405 | MemoryPermission::DontCare); |
| 402 | default: | 406 | default: |
| 403 | NGLOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions); | 407 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions); |
| 404 | } | 408 | } |
| 405 | 409 | ||
| 406 | return RESULT_SUCCESS; | 410 | return RESULT_SUCCESS; |
| 407 | } | 411 | } |
| 408 | 412 | ||
| 409 | static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { | 413 | static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { |
| 410 | NGLOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", | 414 | LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", |
| 411 | shared_memory_handle, addr, size); | 415 | shared_memory_handle, addr, size); |
| 412 | 416 | ||
| 413 | SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); | 417 | SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); |
| 414 | 418 | ||
| @@ -436,19 +440,19 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i | |||
| 436 | memory_info->type = static_cast<u32>(vma->second.meminfo_state); | 440 | memory_info->type = static_cast<u32>(vma->second.meminfo_state); |
| 437 | } | 441 | } |
| 438 | 442 | ||
| 439 | NGLOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr); | 443 | LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr); |
| 440 | return RESULT_SUCCESS; | 444 | return RESULT_SUCCESS; |
| 441 | } | 445 | } |
| 442 | 446 | ||
| 443 | /// Query memory | 447 | /// Query memory |
| 444 | static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) { | 448 | static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) { |
| 445 | NGLOG_TRACE(Kernel_SVC, "called, addr={:X}", addr); | 449 | LOG_TRACE(Kernel_SVC, "called, addr={:X}", addr); |
| 446 | return QueryProcessMemory(memory_info, page_info, CurrentProcess, addr); | 450 | return QueryProcessMemory(memory_info, page_info, CurrentProcess, addr); |
| 447 | } | 451 | } |
| 448 | 452 | ||
| 449 | /// Exits the current process | 453 | /// Exits the current process |
| 450 | static void ExitProcess() { | 454 | static void ExitProcess() { |
| 451 | NGLOG_INFO(Kernel_SVC, "Process {} exiting", Core::CurrentProcess()->process_id); | 455 | LOG_INFO(Kernel_SVC, "Process {} exiting", Core::CurrentProcess()->process_id); |
| 452 | 456 | ||
| 453 | ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running, | 457 | ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running, |
| 454 | "Process has already exited"); | 458 | "Process has already exited"); |
| @@ -524,17 +528,17 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 524 | Core::System::GetInstance().PrepareReschedule(); | 528 | Core::System::GetInstance().PrepareReschedule(); |
| 525 | Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule(); | 529 | Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule(); |
| 526 | 530 | ||
| 527 | NGLOG_TRACE(Kernel_SVC, | 531 | LOG_TRACE(Kernel_SVC, |
| 528 | "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, " | 532 | "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, " |
| 529 | "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", | 533 | "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", |
| 530 | entry_point, name, arg, stack_top, priority, processor_id, *out_handle); | 534 | entry_point, name, arg, stack_top, priority, processor_id, *out_handle); |
| 531 | 535 | ||
| 532 | return RESULT_SUCCESS; | 536 | return RESULT_SUCCESS; |
| 533 | } | 537 | } |
| 534 | 538 | ||
| 535 | /// Starts the thread for the provided handle | 539 | /// Starts the thread for the provided handle |
| 536 | static ResultCode StartThread(Handle thread_handle) { | 540 | static ResultCode StartThread(Handle thread_handle) { |
| 537 | NGLOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); | 541 | LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); |
| 538 | 542 | ||
| 539 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); | 543 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); |
| 540 | if (!thread) { | 544 | if (!thread) { |
| @@ -551,7 +555,7 @@ static ResultCode StartThread(Handle thread_handle) { | |||
| 551 | 555 | ||
| 552 | /// Called when a thread exits | 556 | /// Called when a thread exits |
| 553 | static void ExitThread() { | 557 | static void ExitThread() { |
| 554 | NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC()); | 558 | LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC()); |
| 555 | 559 | ||
| 556 | ExitCurrentThread(); | 560 | ExitCurrentThread(); |
| 557 | Core::System::GetInstance().PrepareReschedule(); | 561 | Core::System::GetInstance().PrepareReschedule(); |
| @@ -559,7 +563,7 @@ static void ExitThread() { | |||
| 559 | 563 | ||
| 560 | /// Sleep the current thread | 564 | /// Sleep the current thread |
| 561 | static void SleepThread(s64 nanoseconds) { | 565 | static void SleepThread(s64 nanoseconds) { |
| 562 | NGLOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); | 566 | LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); |
| 563 | 567 | ||
| 564 | // Don't attempt to yield execution if there are no available threads to run, | 568 | // Don't attempt to yield execution if there are no available threads to run, |
| 565 | // this way we avoid a useless reschedule to the idle thread. | 569 | // this way we avoid a useless reschedule to the idle thread. |
| @@ -575,10 +579,10 @@ static void SleepThread(s64 nanoseconds) { | |||
| 575 | Core::System::GetInstance().PrepareReschedule(); | 579 | Core::System::GetInstance().PrepareReschedule(); |
| 576 | } | 580 | } |
| 577 | 581 | ||
| 578 | /// Signal process wide key atomic | 582 | /// Wait process wide key atomic |
| 579 | static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr, | 583 | static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr, |
| 580 | Handle thread_handle, s64 nano_seconds) { | 584 | Handle thread_handle, s64 nano_seconds) { |
| 581 | NGLOG_TRACE( | 585 | LOG_TRACE( |
| 582 | Kernel_SVC, | 586 | Kernel_SVC, |
| 583 | "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", | 587 | "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", |
| 584 | mutex_addr, condition_variable_addr, thread_handle, nano_seconds); | 588 | mutex_addr, condition_variable_addr, thread_handle, nano_seconds); |
| @@ -605,8 +609,8 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var | |||
| 605 | 609 | ||
| 606 | /// Signal process wide key | 610 | /// Signal process wide key |
| 607 | static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) { | 611 | static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) { |
| 608 | NGLOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", | 612 | LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", |
| 609 | condition_variable_addr, target); | 613 | condition_variable_addr, target); |
| 610 | 614 | ||
| 611 | auto RetrieveWaitingThreads = | 615 | auto RetrieveWaitingThreads = |
| 612 | [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr condvar_addr) { | 616 | [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr condvar_addr) { |
| @@ -684,6 +688,57 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target | |||
| 684 | return RESULT_SUCCESS; | 688 | return RESULT_SUCCESS; |
| 685 | } | 689 | } |
| 686 | 690 | ||
| 691 | // Wait for an address (via Address Arbiter) | ||
| 692 | static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout) { | ||
| 693 | LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", | ||
| 694 | address, type, value, timeout); | ||
| 695 | // If the passed address is a kernel virtual address, return invalid memory state. | ||
| 696 | if (Memory::IsKernelVirtualAddress(address)) { | ||
| 697 | return ERR_INVALID_ADDRESS_STATE; | ||
| 698 | } | ||
| 699 | // If the address is not properly aligned to 4 bytes, return invalid address. | ||
| 700 | if (address % sizeof(u32) != 0) { | ||
| 701 | return ERR_INVALID_ADDRESS; | ||
| 702 | } | ||
| 703 | |||
| 704 | switch (static_cast<AddressArbiter::ArbitrationType>(type)) { | ||
| 705 | case AddressArbiter::ArbitrationType::WaitIfLessThan: | ||
| 706 | return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, false); | ||
| 707 | case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan: | ||
| 708 | return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, true); | ||
| 709 | case AddressArbiter::ArbitrationType::WaitIfEqual: | ||
| 710 | return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); | ||
| 711 | default: | ||
| 712 | return ERR_INVALID_ENUM_VALUE; | ||
| 713 | } | ||
| 714 | } | ||
| 715 | |||
| 716 | // Signals to an address (via Address Arbiter) | ||
| 717 | static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to_wake) { | ||
| 718 | LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", | ||
| 719 | address, type, value, num_to_wake); | ||
| 720 | // If the passed address is a kernel virtual address, return invalid memory state. | ||
| 721 | if (Memory::IsKernelVirtualAddress(address)) { | ||
| 722 | return ERR_INVALID_ADDRESS_STATE; | ||
| 723 | } | ||
| 724 | // If the address is not properly aligned to 4 bytes, return invalid address. | ||
| 725 | if (address % sizeof(u32) != 0) { | ||
| 726 | return ERR_INVALID_ADDRESS; | ||
| 727 | } | ||
| 728 | |||
| 729 | switch (static_cast<AddressArbiter::SignalType>(type)) { | ||
| 730 | case AddressArbiter::SignalType::Signal: | ||
| 731 | return AddressArbiter::SignalToAddress(address, num_to_wake); | ||
| 732 | case AddressArbiter::SignalType::IncrementAndSignalIfEqual: | ||
| 733 | return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); | ||
| 734 | case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: | ||
| 735 | return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, | ||
| 736 | num_to_wake); | ||
| 737 | default: | ||
| 738 | return ERR_INVALID_ENUM_VALUE; | ||
| 739 | } | ||
| 740 | } | ||
| 741 | |||
| 687 | /// This returns the total CPU ticks elapsed since the CPU was powered-on | 742 | /// This returns the total CPU ticks elapsed since the CPU was powered-on |
| 688 | static u64 GetSystemTick() { | 743 | static u64 GetSystemTick() { |
| 689 | const u64 result{CoreTiming::GetTicks()}; | 744 | const u64 result{CoreTiming::GetTicks()}; |
| @@ -696,13 +751,13 @@ static u64 GetSystemTick() { | |||
| 696 | 751 | ||
| 697 | /// Close a handle | 752 | /// Close a handle |
| 698 | static ResultCode CloseHandle(Handle handle) { | 753 | static ResultCode CloseHandle(Handle handle) { |
| 699 | NGLOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); | 754 | LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); |
| 700 | return g_handle_table.Close(handle); | 755 | return g_handle_table.Close(handle); |
| 701 | } | 756 | } |
| 702 | 757 | ||
| 703 | /// Reset an event | 758 | /// Reset an event |
| 704 | static ResultCode ResetSignal(Handle handle) { | 759 | static ResultCode ResetSignal(Handle handle) { |
| 705 | NGLOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle); | 760 | LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle); |
| 706 | auto event = g_handle_table.Get<Event>(handle); | 761 | auto event = g_handle_table.Get<Event>(handle); |
| 707 | ASSERT(event != nullptr); | 762 | ASSERT(event != nullptr); |
| 708 | event->Clear(); | 763 | event->Clear(); |
| @@ -711,14 +766,14 @@ static ResultCode ResetSignal(Handle handle) { | |||
| 711 | 766 | ||
| 712 | /// Creates a TransferMemory object | 767 | /// Creates a TransferMemory object |
| 713 | static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { | 768 | static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { |
| 714 | NGLOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, | 769 | LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, |
| 715 | size, permissions); | 770 | permissions); |
| 716 | *handle = 0; | 771 | *handle = 0; |
| 717 | return RESULT_SUCCESS; | 772 | return RESULT_SUCCESS; |
| 718 | } | 773 | } |
| 719 | 774 | ||
| 720 | static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) { | 775 | static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) { |
| 721 | NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); | 776 | LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); |
| 722 | 777 | ||
| 723 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); | 778 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); |
| 724 | if (!thread) { | 779 | if (!thread) { |
| @@ -732,8 +787,8 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) | |||
| 732 | } | 787 | } |
| 733 | 788 | ||
| 734 | static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | 789 | static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { |
| 735 | NGLOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle, | 790 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle, |
| 736 | mask, core); | 791 | mask, core); |
| 737 | 792 | ||
| 738 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); | 793 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); |
| 739 | if (!thread) { | 794 | if (!thread) { |
| @@ -744,7 +799,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | |||
| 744 | ASSERT(thread->owner_process->ideal_processor != THREADPROCESSORID_DEFAULT); | 799 | ASSERT(thread->owner_process->ideal_processor != THREADPROCESSORID_DEFAULT); |
| 745 | // Set the target CPU to the one specified in the process' exheader. | 800 | // Set the target CPU to the one specified in the process' exheader. |
| 746 | core = thread->owner_process->ideal_processor; | 801 | core = thread->owner_process->ideal_processor; |
| 747 | mask = 1 << core; | 802 | mask = 1ull << core; |
| 748 | } | 803 | } |
| 749 | 804 | ||
| 750 | if (mask == 0) { | 805 | if (mask == 0) { |
| @@ -761,7 +816,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | |||
| 761 | } | 816 | } |
| 762 | 817 | ||
| 763 | // Error out if the input core isn't enabled in the input mask. | 818 | // Error out if the input core isn't enabled in the input mask. |
| 764 | if (core < Core::NUM_CPU_CORES && (mask & (1 << core)) == 0) { | 819 | if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) { |
| 765 | return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); | 820 | return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); |
| 766 | } | 821 | } |
| 767 | 822 | ||
| @@ -772,8 +827,8 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | |||
| 772 | 827 | ||
| 773 | static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions, | 828 | static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions, |
| 774 | u32 remote_permissions) { | 829 | u32 remote_permissions) { |
| 775 | NGLOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, | 830 | LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, |
| 776 | local_permissions, remote_permissions); | 831 | local_permissions, remote_permissions); |
| 777 | auto sharedMemHandle = | 832 | auto sharedMemHandle = |
| 778 | SharedMemory::Create(g_handle_table.Get<Process>(KernelHandle::CurrentProcess), size, | 833 | SharedMemory::Create(g_handle_table.Get<Process>(KernelHandle::CurrentProcess), size, |
| 779 | static_cast<MemoryPermission>(local_permissions), | 834 | static_cast<MemoryPermission>(local_permissions), |
| @@ -784,7 +839,7 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss | |||
| 784 | } | 839 | } |
| 785 | 840 | ||
| 786 | static ResultCode ClearEvent(Handle handle) { | 841 | static ResultCode ClearEvent(Handle handle) { |
| 787 | NGLOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); | 842 | LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); |
| 788 | 843 | ||
| 789 | SharedPtr<Event> evt = g_handle_table.Get<Event>(handle); | 844 | SharedPtr<Event> evt = g_handle_table.Get<Event>(handle); |
| 790 | if (evt == nullptr) | 845 | if (evt == nullptr) |
| @@ -856,8 +911,8 @@ static const FunctionDef SVC_Table[] = { | |||
| 856 | {0x31, nullptr, "GetResourceLimitCurrentValue"}, | 911 | {0x31, nullptr, "GetResourceLimitCurrentValue"}, |
| 857 | {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, | 912 | {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, |
| 858 | {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, | 913 | {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, |
| 859 | {0x34, nullptr, "WaitForAddress"}, | 914 | {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, |
| 860 | {0x35, nullptr, "SignalToAddress"}, | 915 | {0x35, SvcWrap<SignalToAddress>, "SignalToAddress"}, |
| 861 | {0x36, nullptr, "Unknown"}, | 916 | {0x36, nullptr, "Unknown"}, |
| 862 | {0x37, nullptr, "Unknown"}, | 917 | {0x37, nullptr, "Unknown"}, |
| 863 | {0x38, nullptr, "Unknown"}, | 918 | {0x38, nullptr, "Unknown"}, |
| @@ -936,7 +991,7 @@ static const FunctionDef SVC_Table[] = { | |||
| 936 | 991 | ||
| 937 | static const FunctionDef* GetSVCInfo(u32 func_num) { | 992 | static const FunctionDef* GetSVCInfo(u32 func_num) { |
| 938 | if (func_num >= std::size(SVC_Table)) { | 993 | if (func_num >= std::size(SVC_Table)) { |
| 939 | NGLOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num); | 994 | LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num); |
| 940 | return nullptr; | 995 | return nullptr; |
| 941 | } | 996 | } |
| 942 | return &SVC_Table[func_num]; | 997 | return &SVC_Table[func_num]; |
| @@ -955,10 +1010,10 @@ void CallSVC(u32 immediate) { | |||
| 955 | if (info->func) { | 1010 | if (info->func) { |
| 956 | info->func(); | 1011 | info->func(); |
| 957 | } else { | 1012 | } else { |
| 958 | NGLOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name); | 1013 | LOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name); |
| 959 | } | 1014 | } |
| 960 | } else { | 1015 | } else { |
| 961 | NGLOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); | 1016 | LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); |
| 962 | } | 1017 | } |
| 963 | } | 1018 | } |
| 964 | 1019 | ||
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 40aa88cc1..79c3fe31b 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -179,6 +179,20 @@ void SvcWrap() { | |||
| 179 | FuncReturn(retval); | 179 | FuncReturn(retval); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | template <ResultCode func(u64, u32, s32, s64)> | ||
| 183 | void SvcWrap() { | ||
| 184 | FuncReturn( | ||
| 185 | func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3)) | ||
| 186 | .raw); | ||
| 187 | } | ||
| 188 | |||
| 189 | template <ResultCode func(u64, u32, s32, s32)> | ||
| 190 | void SvcWrap() { | ||
| 191 | FuncReturn(func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), | ||
| 192 | (s32)(PARAM(3) & 0xFFFFFFFF)) | ||
| 193 | .raw); | ||
| 194 | } | ||
| 195 | |||
| 182 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 196 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 183 | // Function wrappers that return type u32 | 197 | // Function wrappers that return type u32 |
| 184 | 198 | ||
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index cffa7ca83..9a9746585 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -104,7 +104,7 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 104 | const auto proper_handle = static_cast<Handle>(thread_handle); | 104 | const auto proper_handle = static_cast<Handle>(thread_handle); |
| 105 | SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>(proper_handle); | 105 | SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>(proper_handle); |
| 106 | if (thread == nullptr) { | 106 | if (thread == nullptr) { |
| 107 | NGLOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); | 107 | LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); |
| 108 | return; | 108 | return; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| @@ -140,6 +140,11 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 140 | } | 140 | } |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | if (thread->arb_wait_address != 0) { | ||
| 144 | ASSERT(thread->status == THREADSTATUS_WAIT_ARB); | ||
| 145 | thread->arb_wait_address = 0; | ||
| 146 | } | ||
| 147 | |||
| 143 | if (resume) | 148 | if (resume) |
| 144 | thread->ResumeFromWait(); | 149 | thread->ResumeFromWait(); |
| 145 | } | 150 | } |
| @@ -179,6 +184,7 @@ void Thread::ResumeFromWait() { | |||
| 179 | case THREADSTATUS_WAIT_SLEEP: | 184 | case THREADSTATUS_WAIT_SLEEP: |
| 180 | case THREADSTATUS_WAIT_IPC: | 185 | case THREADSTATUS_WAIT_IPC: |
| 181 | case THREADSTATUS_WAIT_MUTEX: | 186 | case THREADSTATUS_WAIT_MUTEX: |
| 187 | case THREADSTATUS_WAIT_ARB: | ||
| 182 | break; | 188 | break; |
| 183 | 189 | ||
| 184 | case THREADSTATUS_READY: | 190 | case THREADSTATUS_READY: |
| @@ -284,19 +290,19 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 284 | SharedPtr<Process> owner_process) { | 290 | SharedPtr<Process> owner_process) { |
| 285 | // Check if priority is in ranged. Lowest priority -> highest priority id. | 291 | // Check if priority is in ranged. Lowest priority -> highest priority id. |
| 286 | if (priority > THREADPRIO_LOWEST) { | 292 | if (priority > THREADPRIO_LOWEST) { |
| 287 | NGLOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); | 293 | LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); |
| 288 | return ERR_OUT_OF_RANGE; | 294 | return ERR_OUT_OF_RANGE; |
| 289 | } | 295 | } |
| 290 | 296 | ||
| 291 | if (processor_id > THREADPROCESSORID_MAX) { | 297 | if (processor_id > THREADPROCESSORID_MAX) { |
| 292 | NGLOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); | 298 | LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); |
| 293 | return ERR_OUT_OF_RANGE_KERNEL; | 299 | return ERR_OUT_OF_RANGE_KERNEL; |
| 294 | } | 300 | } |
| 295 | 301 | ||
| 296 | // TODO(yuriks): Other checks, returning 0xD9001BEA | 302 | // TODO(yuriks): Other checks, returning 0xD9001BEA |
| 297 | 303 | ||
| 298 | if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) { | 304 | if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) { |
| 299 | NGLOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); | 305 | LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); |
| 300 | // TODO (bunnei): Find the correct error code to use here | 306 | // TODO (bunnei): Find the correct error code to use here |
| 301 | return ResultCode(-1); | 307 | return ResultCode(-1); |
| 302 | } | 308 | } |
| @@ -337,8 +343,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 337 | auto& linheap_memory = memory_region->linear_heap_memory; | 343 | auto& linheap_memory = memory_region->linear_heap_memory; |
| 338 | 344 | ||
| 339 | if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) { | 345 | if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) { |
| 340 | NGLOG_ERROR(Kernel_SVC, | 346 | LOG_ERROR(Kernel_SVC, |
| 341 | "Not enough space in region to allocate a new TLS page for thread"); | 347 | "Not enough space in region to allocate a new TLS page for thread"); |
| 342 | return ERR_OUT_OF_MEMORY; | 348 | return ERR_OUT_OF_MEMORY; |
| 343 | } | 349 | } |
| 344 | 350 | ||
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 1d2da6d50..f1e759802 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -45,6 +45,7 @@ enum ThreadStatus { | |||
| 45 | THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false | 45 | THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false |
| 46 | THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true | 46 | THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true |
| 47 | THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc | 47 | THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc |
| 48 | THREADSTATUS_WAIT_ARB, ///< Waiting due to a SignalToAddress/WaitForAddress svc | ||
| 48 | THREADSTATUS_DORMANT, ///< Created but not yet made ready | 49 | THREADSTATUS_DORMANT, ///< Created but not yet made ready |
| 49 | THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated | 50 | THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated |
| 50 | }; | 51 | }; |
| @@ -230,6 +231,9 @@ public: | |||
| 230 | VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address | 231 | VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address |
| 231 | Handle wait_handle; ///< The handle used to wait for the mutex. | 232 | Handle wait_handle; ///< The handle used to wait for the mutex. |
| 232 | 233 | ||
| 234 | // If waiting for an AddressArbiter, this is the address being waited on. | ||
| 235 | VAddr arb_wait_address{0}; | ||
| 236 | |||
| 233 | std::string name; | 237 | std::string name; |
| 234 | 238 | ||
| 235 | /// Handle used by guest emulated application to access this thread | 239 | /// Handle used by guest emulated application to access this thread |
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 661356a97..0141125e4 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -78,7 +78,7 @@ void Timer::WakeupAllWaitingThreads() { | |||
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | void Timer::Signal(int cycles_late) { | 80 | void Timer::Signal(int cycles_late) { |
| 81 | NGLOG_TRACE(Kernel, "Timer {} fired", GetObjectId()); | 81 | LOG_TRACE(Kernel, "Timer {} fired", GetObjectId()); |
| 82 | 82 | ||
| 83 | signaled = true; | 83 | signaled = true; |
| 84 | 84 | ||
| @@ -98,7 +98,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | |||
| 98 | timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle)); | 98 | timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle)); |
| 99 | 99 | ||
| 100 | if (timer == nullptr) { | 100 | if (timer == nullptr) { |
| 101 | NGLOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle); | 101 | LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle); |
| 102 | return; | 102 | return; |
| 103 | } | 103 | } |
| 104 | 104 | ||
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 676e5b282..034dd490e 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -242,12 +242,12 @@ void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) { | |||
| 242 | void VMManager::LogLayout() const { | 242 | void VMManager::LogLayout() const { |
| 243 | for (const auto& p : vma_map) { | 243 | for (const auto& p : vma_map) { |
| 244 | const VirtualMemoryArea& vma = p.second; | 244 | const VirtualMemoryArea& vma = p.second; |
| 245 | NGLOG_DEBUG(Kernel, "{:016X} - {:016X} size: {:016X} {}{}{} {}", vma.base, | 245 | LOG_DEBUG(Kernel, "{:016X} - {:016X} size: {:016X} {}{}{} {}", vma.base, |
| 246 | vma.base + vma.size, vma.size, | 246 | vma.base + vma.size, vma.size, |
| 247 | (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-', | 247 | (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-', |
| 248 | (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-', | 248 | (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-', |
| 249 | (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-', | 249 | (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-', |
| 250 | GetMemoryStateName(vma.meminfo_state)); | 250 | GetMemoryStateName(vma.meminfo_state)); |
| 251 | } | 251 | } |
| 252 | } | 252 | } |
| 253 | 253 | ||
| @@ -392,22 +392,22 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { | |||
| 392 | } | 392 | } |
| 393 | 393 | ||
| 394 | u64 VMManager::GetTotalMemoryUsage() { | 394 | u64 VMManager::GetTotalMemoryUsage() { |
| 395 | NGLOG_WARNING(Kernel, "(STUBBED) called"); | 395 | LOG_WARNING(Kernel, "(STUBBED) called"); |
| 396 | return 0xF8000000; | 396 | return 0xF8000000; |
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | u64 VMManager::GetTotalHeapUsage() { | 399 | u64 VMManager::GetTotalHeapUsage() { |
| 400 | NGLOG_WARNING(Kernel, "(STUBBED) called"); | 400 | LOG_WARNING(Kernel, "(STUBBED) called"); |
| 401 | return 0x0; | 401 | return 0x0; |
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | VAddr VMManager::GetAddressSpaceBaseAddr() { | 404 | VAddr VMManager::GetAddressSpaceBaseAddr() { |
| 405 | NGLOG_WARNING(Kernel, "(STUBBED) called"); | 405 | LOG_WARNING(Kernel, "(STUBBED) called"); |
| 406 | return 0x8000000; | 406 | return 0x8000000; |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | u64 VMManager::GetAddressSpaceSize() { | 409 | u64 VMManager::GetAddressSpaceSize() { |
| 410 | NGLOG_WARNING(Kernel, "(STUBBED) called"); | 410 | LOG_WARNING(Kernel, "(STUBBED) called"); |
| 411 | return MAX_ADDRESS; | 411 | return MAX_ADDRESS; |
| 412 | } | 412 | } |
| 413 | 413 | ||
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index f2fffa760..6bafb2dce 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -47,7 +47,7 @@ public: | |||
| 47 | 47 | ||
| 48 | private: | 48 | private: |
| 49 | void GetBase(Kernel::HLERequestContext& ctx) { | 49 | void GetBase(Kernel::HLERequestContext& ctx) { |
| 50 | NGLOG_WARNING(Service_ACC, "(STUBBED) called"); | 50 | LOG_WARNING(Service_ACC, "(STUBBED) called"); |
| 51 | ProfileBase profile_base{}; | 51 | ProfileBase profile_base{}; |
| 52 | IPC::ResponseBuilder rb{ctx, 16}; | 52 | IPC::ResponseBuilder rb{ctx, 16}; |
| 53 | rb.Push(RESULT_SUCCESS); | 53 | rb.Push(RESULT_SUCCESS); |
| @@ -72,14 +72,14 @@ public: | |||
| 72 | 72 | ||
| 73 | private: | 73 | private: |
| 74 | void CheckAvailability(Kernel::HLERequestContext& ctx) { | 74 | void CheckAvailability(Kernel::HLERequestContext& ctx) { |
| 75 | NGLOG_WARNING(Service_ACC, "(STUBBED) called"); | 75 | LOG_WARNING(Service_ACC, "(STUBBED) called"); |
| 76 | IPC::ResponseBuilder rb{ctx, 3}; | 76 | IPC::ResponseBuilder rb{ctx, 3}; |
| 77 | rb.Push(RESULT_SUCCESS); | 77 | rb.Push(RESULT_SUCCESS); |
| 78 | rb.Push(true); // TODO: Check when this is supposed to return true and when not | 78 | rb.Push(true); // TODO: Check when this is supposed to return true and when not |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | void GetAccountId(Kernel::HLERequestContext& ctx) { | 81 | void GetAccountId(Kernel::HLERequestContext& ctx) { |
| 82 | NGLOG_WARNING(Service_ACC, "(STUBBED) called"); | 82 | LOG_WARNING(Service_ACC, "(STUBBED) called"); |
| 83 | IPC::ResponseBuilder rb{ctx, 4}; | 83 | IPC::ResponseBuilder rb{ctx, 4}; |
| 84 | rb.Push(RESULT_SUCCESS); | 84 | rb.Push(RESULT_SUCCESS); |
| 85 | rb.Push<u64>(0x12345678ABCDEF); | 85 | rb.Push<u64>(0x12345678ABCDEF); |
| @@ -87,14 +87,14 @@ private: | |||
| 87 | }; | 87 | }; |
| 88 | 88 | ||
| 89 | void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { | 89 | void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { |
| 90 | NGLOG_WARNING(Service_ACC, "(STUBBED) called"); | 90 | LOG_WARNING(Service_ACC, "(STUBBED) called"); |
| 91 | IPC::ResponseBuilder rb{ctx, 3}; | 91 | IPC::ResponseBuilder rb{ctx, 3}; |
| 92 | rb.Push(RESULT_SUCCESS); | 92 | rb.Push(RESULT_SUCCESS); |
| 93 | rb.Push(true); // TODO: Check when this is supposed to return true and when not | 93 | rb.Push(true); // TODO: Check when this is supposed to return true and when not |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { | 96 | void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { |
| 97 | NGLOG_WARNING(Service_ACC, "(STUBBED) called"); | 97 | LOG_WARNING(Service_ACC, "(STUBBED) called"); |
| 98 | constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; | 98 | constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; |
| 99 | ctx.WriteBuffer(user_ids.data(), user_ids.size()); | 99 | ctx.WriteBuffer(user_ids.data(), user_ids.size()); |
| 100 | IPC::ResponseBuilder rb{ctx, 2}; | 100 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -102,7 +102,7 @@ void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { | |||
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) { | 104 | void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) { |
| 105 | NGLOG_WARNING(Service_ACC, "(STUBBED) called"); | 105 | LOG_WARNING(Service_ACC, "(STUBBED) called"); |
| 106 | constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; | 106 | constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; |
| 107 | ctx.WriteBuffer(user_ids.data(), user_ids.size()); | 107 | ctx.WriteBuffer(user_ids.data(), user_ids.size()); |
| 108 | IPC::ResponseBuilder rb{ctx, 2}; | 108 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -113,11 +113,11 @@ void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { | |||
| 113 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 113 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 114 | rb.Push(RESULT_SUCCESS); | 114 | rb.Push(RESULT_SUCCESS); |
| 115 | rb.PushIpcInterface<IProfile>(); | 115 | rb.PushIpcInterface<IProfile>(); |
| 116 | NGLOG_DEBUG(Service_ACC, "called"); | 116 | LOG_DEBUG(Service_ACC, "called"); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) { | 119 | void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) { |
| 120 | NGLOG_WARNING(Service_ACC, "(STUBBED) called"); | 120 | LOG_WARNING(Service_ACC, "(STUBBED) called"); |
| 121 | IPC::ResponseBuilder rb{ctx, 2}; | 121 | IPC::ResponseBuilder rb{ctx, 2}; |
| 122 | rb.Push(RESULT_SUCCESS); | 122 | rb.Push(RESULT_SUCCESS); |
| 123 | } | 123 | } |
| @@ -126,11 +126,11 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo | |||
| 126 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 126 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 127 | rb.Push(RESULT_SUCCESS); | 127 | rb.Push(RESULT_SUCCESS); |
| 128 | rb.PushIpcInterface<IManagerForApplication>(); | 128 | rb.PushIpcInterface<IManagerForApplication>(); |
| 129 | NGLOG_DEBUG(Service_ACC, "called"); | 129 | LOG_DEBUG(Service_ACC, "called"); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { | 132 | void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { |
| 133 | NGLOG_WARNING(Service_ACC, "(STUBBED) called"); | 133 | LOG_WARNING(Service_ACC, "(STUBBED) called"); |
| 134 | IPC::ResponseBuilder rb{ctx, 6}; | 134 | IPC::ResponseBuilder rb{ctx, 6}; |
| 135 | rb.Push(RESULT_SUCCESS); | 135 | rb.Push(RESULT_SUCCESS); |
| 136 | rb.PushRaw(DEFAULT_USER_ID); | 136 | rb.PushRaw(DEFAULT_USER_ID); |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index b8d6b8d4d..a871b3eaa 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -30,14 +30,14 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") { | |||
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) { | 32 | void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) { |
| 33 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 33 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 34 | IPC::ResponseBuilder rb{ctx, 4}; | 34 | IPC::ResponseBuilder rb{ctx, 4}; |
| 35 | rb.Push(RESULT_SUCCESS); | 35 | rb.Push(RESULT_SUCCESS); |
| 36 | rb.Push<u64>(0); | 36 | rb.Push<u64>(0); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) { | 39 | void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) { |
| 40 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 40 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 41 | IPC::ResponseBuilder rb{ctx, 2}; | 41 | IPC::ResponseBuilder rb{ctx, 2}; |
| 42 | rb.Push(RESULT_SUCCESS); | 42 | rb.Push(RESULT_SUCCESS); |
| 43 | } | 43 | } |
| @@ -56,20 +56,20 @@ IAudioController::IAudioController() : ServiceFramework("IAudioController") { | |||
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) { | 58 | void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) { |
| 59 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 59 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 60 | IPC::ResponseBuilder rb{ctx, 2}; | 60 | IPC::ResponseBuilder rb{ctx, 2}; |
| 61 | rb.Push(RESULT_SUCCESS); | 61 | rb.Push(RESULT_SUCCESS); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | void IAudioController::GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) { | 64 | void IAudioController::GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) { |
| 65 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 65 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 66 | IPC::ResponseBuilder rb{ctx, 3}; | 66 | IPC::ResponseBuilder rb{ctx, 3}; |
| 67 | rb.Push(RESULT_SUCCESS); | 67 | rb.Push(RESULT_SUCCESS); |
| 68 | rb.Push(volume); | 68 | rb.Push(volume); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | void IAudioController::GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) { | 71 | void IAudioController::GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) { |
| 72 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 72 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 73 | IPC::ResponseBuilder rb{ctx, 3}; | 73 | IPC::ResponseBuilder rb{ctx, 3}; |
| 74 | rb.Push(RESULT_SUCCESS); | 74 | rb.Push(RESULT_SUCCESS); |
| 75 | rb.Push(volume); | 75 | rb.Push(volume); |
| @@ -174,14 +174,14 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { | |||
| 174 | IPC::ResponseBuilder rb{ctx, 2}; | 174 | IPC::ResponseBuilder rb{ctx, 2}; |
| 175 | rb.Push(RESULT_SUCCESS); | 175 | rb.Push(RESULT_SUCCESS); |
| 176 | 176 | ||
| 177 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 177 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { | 180 | void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { |
| 181 | IPC::ResponseBuilder rb{ctx, 2}; | 181 | IPC::ResponseBuilder rb{ctx, 2}; |
| 182 | rb.Push(RESULT_SUCCESS); | 182 | rb.Push(RESULT_SUCCESS); |
| 183 | 183 | ||
| 184 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 184 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { | 187 | void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { |
| @@ -192,14 +192,14 @@ void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestCo | |||
| 192 | IPC::ResponseBuilder rb{ctx, 2}; | 192 | IPC::ResponseBuilder rb{ctx, 2}; |
| 193 | rb.Push(RESULT_SUCCESS); | 193 | rb.Push(RESULT_SUCCESS); |
| 194 | 194 | ||
| 195 | NGLOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); | 195 | LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { | 198 | void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { |
| 199 | IPC::ResponseBuilder rb{ctx, 2}; | 199 | IPC::ResponseBuilder rb{ctx, 2}; |
| 200 | rb.Push(RESULT_SUCCESS); | 200 | rb.Push(RESULT_SUCCESS); |
| 201 | 201 | ||
| 202 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 202 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { | 205 | void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { |
| @@ -210,7 +210,7 @@ void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestCont | |||
| 210 | IPC::ResponseBuilder rb{ctx, 2}; | 210 | IPC::ResponseBuilder rb{ctx, 2}; |
| 211 | rb.Push(RESULT_SUCCESS); | 211 | rb.Push(RESULT_SUCCESS); |
| 212 | 212 | ||
| 213 | NGLOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); | 213 | LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { | 216 | void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { |
| @@ -223,21 +223,21 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& | |||
| 223 | IPC::ResponseBuilder rb{ctx, 2}; | 223 | IPC::ResponseBuilder rb{ctx, 2}; |
| 224 | rb.Push(RESULT_SUCCESS); | 224 | rb.Push(RESULT_SUCCESS); |
| 225 | 225 | ||
| 226 | NGLOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); | 226 | LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { | 229 | void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { |
| 230 | IPC::ResponseBuilder rb{ctx, 2}; | 230 | IPC::ResponseBuilder rb{ctx, 2}; |
| 231 | rb.Push(RESULT_SUCCESS); | 231 | rb.Push(RESULT_SUCCESS); |
| 232 | 232 | ||
| 233 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 233 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { | 236 | void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { |
| 237 | IPC::ResponseBuilder rb{ctx, 2}; | 237 | IPC::ResponseBuilder rb{ctx, 2}; |
| 238 | rb.Push(RESULT_SUCCESS); | 238 | rb.Push(RESULT_SUCCESS); |
| 239 | 239 | ||
| 240 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 240 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { | 243 | void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { |
| @@ -247,7 +247,7 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& | |||
| 247 | rb.Push(RESULT_SUCCESS); | 247 | rb.Push(RESULT_SUCCESS); |
| 248 | rb.PushCopyObjects(launchable_event); | 248 | rb.PushCopyObjects(launchable_event); |
| 249 | 249 | ||
| 250 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 250 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { | 253 | void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { |
| @@ -260,14 +260,14 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) | |||
| 260 | rb.Push(RESULT_SUCCESS); | 260 | rb.Push(RESULT_SUCCESS); |
| 261 | rb.Push(layer_id); | 261 | rb.Push(layer_id); |
| 262 | 262 | ||
| 263 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 263 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { | 266 | void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { |
| 267 | IPC::ResponseBuilder rb{ctx, 2}; | 267 | IPC::ResponseBuilder rb{ctx, 2}; |
| 268 | rb.Push(RESULT_SUCCESS); | 268 | rb.Push(RESULT_SUCCESS); |
| 269 | 269 | ||
| 270 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 270 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") { | 273 | ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") { |
| @@ -311,7 +311,7 @@ void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { | |||
| 311 | rb.Push(RESULT_SUCCESS); | 311 | rb.Push(RESULT_SUCCESS); |
| 312 | rb.PushCopyObjects(event); | 312 | rb.PushCopyObjects(event); |
| 313 | 313 | ||
| 314 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 314 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { | 317 | void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { |
| @@ -319,7 +319,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { | |||
| 319 | rb.Push(RESULT_SUCCESS); | 319 | rb.Push(RESULT_SUCCESS); |
| 320 | rb.Push<u32>(15); | 320 | rb.Push<u32>(15); |
| 321 | 321 | ||
| 322 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 322 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { | 325 | void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { |
| @@ -327,7 +327,7 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { | |||
| 327 | rb.Push(RESULT_SUCCESS); | 327 | rb.Push(RESULT_SUCCESS); |
| 328 | rb.Push(static_cast<u8>(FocusState::InFocus)); | 328 | rb.Push(static_cast<u8>(FocusState::InFocus)); |
| 329 | 329 | ||
| 330 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 330 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { | 333 | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { |
| @@ -336,7 +336,7 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { | |||
| 336 | rb.Push(RESULT_SUCCESS); | 336 | rb.Push(RESULT_SUCCESS); |
| 337 | rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); | 337 | rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); |
| 338 | 338 | ||
| 339 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 339 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { | 342 | void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { |
| @@ -346,7 +346,7 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { | |||
| 346 | rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked | 346 | rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked |
| 347 | : APM::PerformanceMode::Handheld)); | 347 | : APM::PerformanceMode::Handheld)); |
| 348 | 348 | ||
| 349 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 349 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { | 352 | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { |
| @@ -370,7 +370,7 @@ private: | |||
| 370 | rb.Push(RESULT_SUCCESS); | 370 | rb.Push(RESULT_SUCCESS); |
| 371 | rb.Push(static_cast<u64>(buffer.size())); | 371 | rb.Push(static_cast<u64>(buffer.size())); |
| 372 | 372 | ||
| 373 | NGLOG_DEBUG(Service_AM, "called"); | 373 | LOG_DEBUG(Service_AM, "called"); |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | void Write(Kernel::HLERequestContext& ctx) { | 376 | void Write(Kernel::HLERequestContext& ctx) { |
| @@ -386,7 +386,7 @@ private: | |||
| 386 | IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; | 386 | IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; |
| 387 | rb.Push(RESULT_SUCCESS); | 387 | rb.Push(RESULT_SUCCESS); |
| 388 | 388 | ||
| 389 | NGLOG_DEBUG(Service_AM, "called, offset={}", offset); | 389 | LOG_DEBUG(Service_AM, "called, offset={}", offset); |
| 390 | } | 390 | } |
| 391 | 391 | ||
| 392 | void Read(Kernel::HLERequestContext& ctx) { | 392 | void Read(Kernel::HLERequestContext& ctx) { |
| @@ -402,7 +402,7 @@ private: | |||
| 402 | IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; | 402 | IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; |
| 403 | rb.Push(RESULT_SUCCESS); | 403 | rb.Push(RESULT_SUCCESS); |
| 404 | 404 | ||
| 405 | NGLOG_DEBUG(Service_AM, "called, offset={}", offset); | 405 | LOG_DEBUG(Service_AM, "called, offset={}", offset); |
| 406 | } | 406 | } |
| 407 | }; | 407 | }; |
| 408 | 408 | ||
| @@ -426,7 +426,7 @@ private: | |||
| 426 | rb.Push(RESULT_SUCCESS); | 426 | rb.Push(RESULT_SUCCESS); |
| 427 | rb.PushIpcInterface<AM::IStorageAccessor>(buffer); | 427 | rb.PushIpcInterface<AM::IStorageAccessor>(buffer); |
| 428 | 428 | ||
| 429 | NGLOG_DEBUG(Service_AM, "called"); | 429 | LOG_DEBUG(Service_AM, "called"); |
| 430 | } | 430 | } |
| 431 | }; | 431 | }; |
| 432 | 432 | ||
| @@ -467,21 +467,21 @@ private: | |||
| 467 | rb.Push(RESULT_SUCCESS); | 467 | rb.Push(RESULT_SUCCESS); |
| 468 | rb.PushCopyObjects(state_changed_event); | 468 | rb.PushCopyObjects(state_changed_event); |
| 469 | 469 | ||
| 470 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 470 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 471 | } | 471 | } |
| 472 | 472 | ||
| 473 | void GetResult(Kernel::HLERequestContext& ctx) { | 473 | void GetResult(Kernel::HLERequestContext& ctx) { |
| 474 | IPC::ResponseBuilder rb{ctx, 2}; | 474 | IPC::ResponseBuilder rb{ctx, 2}; |
| 475 | rb.Push(RESULT_SUCCESS); | 475 | rb.Push(RESULT_SUCCESS); |
| 476 | 476 | ||
| 477 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 477 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 478 | } | 478 | } |
| 479 | 479 | ||
| 480 | void Start(Kernel::HLERequestContext& ctx) { | 480 | void Start(Kernel::HLERequestContext& ctx) { |
| 481 | IPC::ResponseBuilder rb{ctx, 2}; | 481 | IPC::ResponseBuilder rb{ctx, 2}; |
| 482 | rb.Push(RESULT_SUCCESS); | 482 | rb.Push(RESULT_SUCCESS); |
| 483 | 483 | ||
| 484 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 484 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 485 | } | 485 | } |
| 486 | 486 | ||
| 487 | void PushInData(Kernel::HLERequestContext& ctx) { | 487 | void PushInData(Kernel::HLERequestContext& ctx) { |
| @@ -491,7 +491,7 @@ private: | |||
| 491 | IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; | 491 | IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; |
| 492 | rb.Push(RESULT_SUCCESS); | 492 | rb.Push(RESULT_SUCCESS); |
| 493 | 493 | ||
| 494 | NGLOG_DEBUG(Service_AM, "called"); | 494 | LOG_DEBUG(Service_AM, "called"); |
| 495 | } | 495 | } |
| 496 | 496 | ||
| 497 | void PopOutData(Kernel::HLERequestContext& ctx) { | 497 | void PopOutData(Kernel::HLERequestContext& ctx) { |
| @@ -501,7 +501,7 @@ private: | |||
| 501 | 501 | ||
| 502 | storage_stack.pop(); | 502 | storage_stack.pop(); |
| 503 | 503 | ||
| 504 | NGLOG_DEBUG(Service_AM, "called"); | 504 | LOG_DEBUG(Service_AM, "called"); |
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | std::stack<std::shared_ptr<AM::IStorage>> storage_stack; | 507 | std::stack<std::shared_ptr<AM::IStorage>> storage_stack; |
| @@ -526,7 +526,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) | |||
| 526 | rb.Push(RESULT_SUCCESS); | 526 | rb.Push(RESULT_SUCCESS); |
| 527 | rb.PushIpcInterface<AM::ILibraryAppletAccessor>(); | 527 | rb.PushIpcInterface<AM::ILibraryAppletAccessor>(); |
| 528 | 528 | ||
| 529 | NGLOG_DEBUG(Service_AM, "called"); | 529 | LOG_DEBUG(Service_AM, "called"); |
| 530 | } | 530 | } |
| 531 | 531 | ||
| 532 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { | 532 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { |
| @@ -538,7 +538,7 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { | |||
| 538 | rb.Push(RESULT_SUCCESS); | 538 | rb.Push(RESULT_SUCCESS); |
| 539 | rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); | 539 | rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); |
| 540 | 540 | ||
| 541 | NGLOG_DEBUG(Service_AM, "called, size={}", size); | 541 | LOG_DEBUG(Service_AM, "called, size={}", size); |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { | 544 | IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { |
| @@ -602,21 +602,21 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | |||
| 602 | rb.Push(RESULT_SUCCESS); | 602 | rb.Push(RESULT_SUCCESS); |
| 603 | rb.PushIpcInterface<AM::IStorage>(buffer); | 603 | rb.PushIpcInterface<AM::IStorage>(buffer); |
| 604 | 604 | ||
| 605 | NGLOG_DEBUG(Service_AM, "called"); | 605 | LOG_DEBUG(Service_AM, "called"); |
| 606 | } | 606 | } |
| 607 | 607 | ||
| 608 | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( | 608 | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( |
| 609 | Kernel::HLERequestContext& ctx) { | 609 | Kernel::HLERequestContext& ctx) { |
| 610 | IPC::ResponseBuilder rb{ctx, 2}; | 610 | IPC::ResponseBuilder rb{ctx, 2}; |
| 611 | rb.Push(RESULT_SUCCESS); | 611 | rb.Push(RESULT_SUCCESS); |
| 612 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 612 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 613 | } | 613 | } |
| 614 | 614 | ||
| 615 | void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { | 615 | void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { |
| 616 | IPC::RequestParser rp{ctx}; | 616 | IPC::RequestParser rp{ctx}; |
| 617 | u128 uid = rp.PopRaw<u128>(); | 617 | u128 uid = rp.PopRaw<u128>(); |
| 618 | 618 | ||
| 619 | NGLOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); | 619 | LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); |
| 620 | 620 | ||
| 621 | IPC::ResponseBuilder rb{ctx, 4}; | 621 | IPC::ResponseBuilder rb{ctx, 4}; |
| 622 | 622 | ||
| @@ -644,7 +644,7 @@ void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { | |||
| 644 | IPC::ResponseBuilder rb{ctx, 2}; | 644 | IPC::ResponseBuilder rb{ctx, 2}; |
| 645 | rb.Push(RESULT_SUCCESS); | 645 | rb.Push(RESULT_SUCCESS); |
| 646 | 646 | ||
| 647 | NGLOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); | 647 | LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); |
| 648 | } | 648 | } |
| 649 | 649 | ||
| 650 | void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { | 650 | void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { |
| @@ -652,7 +652,7 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { | |||
| 652 | rb.Push(RESULT_SUCCESS); | 652 | rb.Push(RESULT_SUCCESS); |
| 653 | rb.Push<u64>(1); | 653 | rb.Push<u64>(1); |
| 654 | rb.Push<u64>(0); | 654 | rb.Push<u64>(0); |
| 655 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 655 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 656 | } | 656 | } |
| 657 | 657 | ||
| 658 | void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { | 658 | void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { |
| @@ -660,20 +660,20 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { | |||
| 660 | IPC::ResponseBuilder rb{ctx, 4}; | 660 | IPC::ResponseBuilder rb{ctx, 4}; |
| 661 | rb.Push(RESULT_SUCCESS); | 661 | rb.Push(RESULT_SUCCESS); |
| 662 | rb.Push(static_cast<u64>(Service::Set::LanguageCode::EN_US)); | 662 | rb.Push(static_cast<u64>(Service::Set::LanguageCode::EN_US)); |
| 663 | NGLOG_DEBUG(Service_AM, "called"); | 663 | LOG_DEBUG(Service_AM, "called"); |
| 664 | } | 664 | } |
| 665 | 665 | ||
| 666 | void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { | 666 | void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { |
| 667 | IPC::ResponseBuilder rb{ctx, 2}; | 667 | IPC::ResponseBuilder rb{ctx, 2}; |
| 668 | rb.Push(RESULT_SUCCESS); | 668 | rb.Push(RESULT_SUCCESS); |
| 669 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 669 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 670 | } | 670 | } |
| 671 | 671 | ||
| 672 | void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { | 672 | void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { |
| 673 | IPC::ResponseBuilder rb{ctx, 2}; | 673 | IPC::ResponseBuilder rb{ctx, 2}; |
| 674 | rb.Push(RESULT_SUCCESS); | 674 | rb.Push(RESULT_SUCCESS); |
| 675 | 675 | ||
| 676 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 676 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 677 | } | 677 | } |
| 678 | 678 | ||
| 679 | void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { | 679 | void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { |
| @@ -681,7 +681,7 @@ void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { | |||
| 681 | rb.Push(RESULT_SUCCESS); | 681 | rb.Push(RESULT_SUCCESS); |
| 682 | rb.Push<u8>(0); // Unknown, seems to be ignored by official processes | 682 | rb.Push<u8>(0); // Unknown, seems to be ignored by official processes |
| 683 | 683 | ||
| 684 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 684 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { | 687 | void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { |
| @@ -692,7 +692,7 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { | |||
| 692 | rb.Push<u64>(0); | 692 | rb.Push<u64>(0); |
| 693 | rb.Push<u64>(0); | 693 | rb.Push<u64>(0); |
| 694 | 694 | ||
| 695 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 695 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | void InstallInterfaces(SM::ServiceManager& service_manager, | 698 | void InstallInterfaces(SM::ServiceManager& service_manager, |
| @@ -717,7 +717,7 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions" | |||
| 717 | void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { | 717 | void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { |
| 718 | IPC::ResponseBuilder rb{ctx, 2}; | 718 | IPC::ResponseBuilder rb{ctx, 2}; |
| 719 | rb.Push(RESULT_SUCCESS); | 719 | rb.Push(RESULT_SUCCESS); |
| 720 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 720 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 721 | } | 721 | } |
| 722 | 722 | ||
| 723 | IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { | 723 | IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { |
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index 7ce551de3..180057ec2 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp | |||
| @@ -33,63 +33,63 @@ private: | |||
| 33 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 33 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 34 | rb.Push(RESULT_SUCCESS); | 34 | rb.Push(RESULT_SUCCESS); |
| 35 | rb.PushIpcInterface<ICommonStateGetter>(); | 35 | rb.PushIpcInterface<ICommonStateGetter>(); |
| 36 | NGLOG_DEBUG(Service_AM, "called"); | 36 | LOG_DEBUG(Service_AM, "called"); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | void GetSelfController(Kernel::HLERequestContext& ctx) { | 39 | void GetSelfController(Kernel::HLERequestContext& ctx) { |
| 40 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 40 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 41 | rb.Push(RESULT_SUCCESS); | 41 | rb.Push(RESULT_SUCCESS); |
| 42 | rb.PushIpcInterface<ISelfController>(nvflinger); | 42 | rb.PushIpcInterface<ISelfController>(nvflinger); |
| 43 | NGLOG_DEBUG(Service_AM, "called"); | 43 | LOG_DEBUG(Service_AM, "called"); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void GetWindowController(Kernel::HLERequestContext& ctx) { | 46 | void GetWindowController(Kernel::HLERequestContext& ctx) { |
| 47 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 47 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 48 | rb.Push(RESULT_SUCCESS); | 48 | rb.Push(RESULT_SUCCESS); |
| 49 | rb.PushIpcInterface<IWindowController>(); | 49 | rb.PushIpcInterface<IWindowController>(); |
| 50 | NGLOG_DEBUG(Service_AM, "called"); | 50 | LOG_DEBUG(Service_AM, "called"); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | void GetAudioController(Kernel::HLERequestContext& ctx) { | 53 | void GetAudioController(Kernel::HLERequestContext& ctx) { |
| 54 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 54 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 55 | rb.Push(RESULT_SUCCESS); | 55 | rb.Push(RESULT_SUCCESS); |
| 56 | rb.PushIpcInterface<IAudioController>(); | 56 | rb.PushIpcInterface<IAudioController>(); |
| 57 | NGLOG_DEBUG(Service_AM, "called"); | 57 | LOG_DEBUG(Service_AM, "called"); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 60 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| 61 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 61 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 62 | rb.Push(RESULT_SUCCESS); | 62 | rb.Push(RESULT_SUCCESS); |
| 63 | rb.PushIpcInterface<IDisplayController>(); | 63 | rb.PushIpcInterface<IDisplayController>(); |
| 64 | NGLOG_DEBUG(Service_AM, "called"); | 64 | LOG_DEBUG(Service_AM, "called"); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void GetProcessWindingController(Kernel::HLERequestContext& ctx) { | 67 | void GetProcessWindingController(Kernel::HLERequestContext& ctx) { |
| 68 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 68 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 69 | rb.Push(RESULT_SUCCESS); | 69 | rb.Push(RESULT_SUCCESS); |
| 70 | rb.PushIpcInterface<IProcessWindingController>(); | 70 | rb.PushIpcInterface<IProcessWindingController>(); |
| 71 | NGLOG_DEBUG(Service_AM, "called"); | 71 | LOG_DEBUG(Service_AM, "called"); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 74 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| 75 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 75 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 76 | rb.Push(RESULT_SUCCESS); | 76 | rb.Push(RESULT_SUCCESS); |
| 77 | rb.PushIpcInterface<IDebugFunctions>(); | 77 | rb.PushIpcInterface<IDebugFunctions>(); |
| 78 | NGLOG_DEBUG(Service_AM, "called"); | 78 | LOG_DEBUG(Service_AM, "called"); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 81 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| 82 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 82 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 83 | rb.Push(RESULT_SUCCESS); | 83 | rb.Push(RESULT_SUCCESS); |
| 84 | rb.PushIpcInterface<ILibraryAppletCreator>(); | 84 | rb.PushIpcInterface<ILibraryAppletCreator>(); |
| 85 | NGLOG_DEBUG(Service_AM, "called"); | 85 | LOG_DEBUG(Service_AM, "called"); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { | 88 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { |
| 89 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 89 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 90 | rb.Push(RESULT_SUCCESS); | 90 | rb.Push(RESULT_SUCCESS); |
| 91 | rb.PushIpcInterface<IApplicationFunctions>(); | 91 | rb.PushIpcInterface<IApplicationFunctions>(); |
| 92 | NGLOG_DEBUG(Service_AM, "called"); | 92 | LOG_DEBUG(Service_AM, "called"); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 95 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| @@ -120,70 +120,70 @@ private: | |||
| 120 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 120 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 121 | rb.Push(RESULT_SUCCESS); | 121 | rb.Push(RESULT_SUCCESS); |
| 122 | rb.PushIpcInterface<ICommonStateGetter>(); | 122 | rb.PushIpcInterface<ICommonStateGetter>(); |
| 123 | NGLOG_DEBUG(Service_AM, "called"); | 123 | LOG_DEBUG(Service_AM, "called"); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | void GetSelfController(Kernel::HLERequestContext& ctx) { | 126 | void GetSelfController(Kernel::HLERequestContext& ctx) { |
| 127 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 127 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 128 | rb.Push(RESULT_SUCCESS); | 128 | rb.Push(RESULT_SUCCESS); |
| 129 | rb.PushIpcInterface<ISelfController>(nvflinger); | 129 | rb.PushIpcInterface<ISelfController>(nvflinger); |
| 130 | NGLOG_DEBUG(Service_AM, "called"); | 130 | LOG_DEBUG(Service_AM, "called"); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | void GetWindowController(Kernel::HLERequestContext& ctx) { | 133 | void GetWindowController(Kernel::HLERequestContext& ctx) { |
| 134 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 134 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 135 | rb.Push(RESULT_SUCCESS); | 135 | rb.Push(RESULT_SUCCESS); |
| 136 | rb.PushIpcInterface<IWindowController>(); | 136 | rb.PushIpcInterface<IWindowController>(); |
| 137 | NGLOG_DEBUG(Service_AM, "called"); | 137 | LOG_DEBUG(Service_AM, "called"); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | void GetAudioController(Kernel::HLERequestContext& ctx) { | 140 | void GetAudioController(Kernel::HLERequestContext& ctx) { |
| 141 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 141 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 142 | rb.Push(RESULT_SUCCESS); | 142 | rb.Push(RESULT_SUCCESS); |
| 143 | rb.PushIpcInterface<IAudioController>(); | 143 | rb.PushIpcInterface<IAudioController>(); |
| 144 | NGLOG_DEBUG(Service_AM, "called"); | 144 | LOG_DEBUG(Service_AM, "called"); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 147 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| 148 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 148 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 149 | rb.Push(RESULT_SUCCESS); | 149 | rb.Push(RESULT_SUCCESS); |
| 150 | rb.PushIpcInterface<IDisplayController>(); | 150 | rb.PushIpcInterface<IDisplayController>(); |
| 151 | NGLOG_DEBUG(Service_AM, "called"); | 151 | LOG_DEBUG(Service_AM, "called"); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 154 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| 155 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 155 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 156 | rb.Push(RESULT_SUCCESS); | 156 | rb.Push(RESULT_SUCCESS); |
| 157 | rb.PushIpcInterface<IDebugFunctions>(); | 157 | rb.PushIpcInterface<IDebugFunctions>(); |
| 158 | NGLOG_DEBUG(Service_AM, "called"); | 158 | LOG_DEBUG(Service_AM, "called"); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 161 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| 162 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 162 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 163 | rb.Push(RESULT_SUCCESS); | 163 | rb.Push(RESULT_SUCCESS); |
| 164 | rb.PushIpcInterface<ILibraryAppletCreator>(); | 164 | rb.PushIpcInterface<ILibraryAppletCreator>(); |
| 165 | NGLOG_DEBUG(Service_AM, "called"); | 165 | LOG_DEBUG(Service_AM, "called"); |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { | 168 | void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { |
| 169 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 169 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 170 | rb.Push(RESULT_SUCCESS); | 170 | rb.Push(RESULT_SUCCESS); |
| 171 | rb.PushIpcInterface<IHomeMenuFunctions>(); | 171 | rb.PushIpcInterface<IHomeMenuFunctions>(); |
| 172 | NGLOG_DEBUG(Service_AM, "called"); | 172 | LOG_DEBUG(Service_AM, "called"); |
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | void GetGlobalStateController(Kernel::HLERequestContext& ctx) { | 175 | void GetGlobalStateController(Kernel::HLERequestContext& ctx) { |
| 176 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 176 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 177 | rb.Push(RESULT_SUCCESS); | 177 | rb.Push(RESULT_SUCCESS); |
| 178 | rb.PushIpcInterface<IGlobalStateController>(); | 178 | rb.PushIpcInterface<IGlobalStateController>(); |
| 179 | NGLOG_DEBUG(Service_AM, "called"); | 179 | LOG_DEBUG(Service_AM, "called"); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | void GetApplicationCreator(Kernel::HLERequestContext& ctx) { | 182 | void GetApplicationCreator(Kernel::HLERequestContext& ctx) { |
| 183 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 183 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 184 | rb.Push(RESULT_SUCCESS); | 184 | rb.Push(RESULT_SUCCESS); |
| 185 | rb.PushIpcInterface<IApplicationCreator>(); | 185 | rb.PushIpcInterface<IApplicationCreator>(); |
| 186 | NGLOG_DEBUG(Service_AM, "called"); | 186 | LOG_DEBUG(Service_AM, "called"); |
| 187 | } | 187 | } |
| 188 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 188 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| 189 | }; | 189 | }; |
| @@ -192,21 +192,21 @@ void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { | |||
| 192 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 192 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 193 | rb.Push(RESULT_SUCCESS); | 193 | rb.Push(RESULT_SUCCESS); |
| 194 | rb.PushIpcInterface<ISystemAppletProxy>(nvflinger); | 194 | rb.PushIpcInterface<ISystemAppletProxy>(nvflinger); |
| 195 | NGLOG_DEBUG(Service_AM, "called"); | 195 | LOG_DEBUG(Service_AM, "called"); |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { | 198 | void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { |
| 199 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 199 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 200 | rb.Push(RESULT_SUCCESS); | 200 | rb.Push(RESULT_SUCCESS); |
| 201 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger); | 201 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger); |
| 202 | NGLOG_DEBUG(Service_AM, "called"); | 202 | LOG_DEBUG(Service_AM, "called"); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { | 205 | void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { |
| 206 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 206 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 207 | rb.Push(RESULT_SUCCESS); | 207 | rb.Push(RESULT_SUCCESS); |
| 208 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger); | 208 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger); |
| 209 | NGLOG_DEBUG(Service_AM, "called"); | 209 | LOG_DEBUG(Service_AM, "called"); |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) | 212 | AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) |
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index 587a922fe..278259eda 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp | |||
| @@ -33,56 +33,56 @@ private: | |||
| 33 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 33 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 34 | rb.Push(RESULT_SUCCESS); | 34 | rb.Push(RESULT_SUCCESS); |
| 35 | rb.PushIpcInterface<IAudioController>(); | 35 | rb.PushIpcInterface<IAudioController>(); |
| 36 | NGLOG_DEBUG(Service_AM, "called"); | 36 | LOG_DEBUG(Service_AM, "called"); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 39 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| 40 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 40 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 41 | rb.Push(RESULT_SUCCESS); | 41 | rb.Push(RESULT_SUCCESS); |
| 42 | rb.PushIpcInterface<IDisplayController>(); | 42 | rb.PushIpcInterface<IDisplayController>(); |
| 43 | NGLOG_DEBUG(Service_AM, "called"); | 43 | LOG_DEBUG(Service_AM, "called"); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 46 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| 47 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 47 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 48 | rb.Push(RESULT_SUCCESS); | 48 | rb.Push(RESULT_SUCCESS); |
| 49 | rb.PushIpcInterface<IDebugFunctions>(); | 49 | rb.PushIpcInterface<IDebugFunctions>(); |
| 50 | NGLOG_DEBUG(Service_AM, "called"); | 50 | LOG_DEBUG(Service_AM, "called"); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | void GetWindowController(Kernel::HLERequestContext& ctx) { | 53 | void GetWindowController(Kernel::HLERequestContext& ctx) { |
| 54 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 54 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 55 | rb.Push(RESULT_SUCCESS); | 55 | rb.Push(RESULT_SUCCESS); |
| 56 | rb.PushIpcInterface<IWindowController>(); | 56 | rb.PushIpcInterface<IWindowController>(); |
| 57 | NGLOG_DEBUG(Service_AM, "called"); | 57 | LOG_DEBUG(Service_AM, "called"); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | void GetSelfController(Kernel::HLERequestContext& ctx) { | 60 | void GetSelfController(Kernel::HLERequestContext& ctx) { |
| 61 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 61 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 62 | rb.Push(RESULT_SUCCESS); | 62 | rb.Push(RESULT_SUCCESS); |
| 63 | rb.PushIpcInterface<ISelfController>(nvflinger); | 63 | rb.PushIpcInterface<ISelfController>(nvflinger); |
| 64 | NGLOG_DEBUG(Service_AM, "called"); | 64 | LOG_DEBUG(Service_AM, "called"); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { | 67 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { |
| 68 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 68 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 69 | rb.Push(RESULT_SUCCESS); | 69 | rb.Push(RESULT_SUCCESS); |
| 70 | rb.PushIpcInterface<ICommonStateGetter>(); | 70 | rb.PushIpcInterface<ICommonStateGetter>(); |
| 71 | NGLOG_DEBUG(Service_AM, "called"); | 71 | LOG_DEBUG(Service_AM, "called"); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 74 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| 75 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 75 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 76 | rb.Push(RESULT_SUCCESS); | 76 | rb.Push(RESULT_SUCCESS); |
| 77 | rb.PushIpcInterface<ILibraryAppletCreator>(); | 77 | rb.PushIpcInterface<ILibraryAppletCreator>(); |
| 78 | NGLOG_DEBUG(Service_AM, "called"); | 78 | LOG_DEBUG(Service_AM, "called"); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { | 81 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { |
| 82 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 82 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 83 | rb.Push(RESULT_SUCCESS); | 83 | rb.Push(RESULT_SUCCESS); |
| 84 | rb.PushIpcInterface<IApplicationFunctions>(); | 84 | rb.PushIpcInterface<IApplicationFunctions>(); |
| 85 | NGLOG_DEBUG(Service_AM, "called"); | 85 | LOG_DEBUG(Service_AM, "called"); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 88 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| @@ -92,7 +92,7 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { | |||
| 92 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 92 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 93 | rb.Push(RESULT_SUCCESS); | 93 | rb.Push(RESULT_SUCCESS); |
| 94 | rb.PushIpcInterface<IApplicationProxy>(nvflinger); | 94 | rb.PushIpcInterface<IApplicationProxy>(nvflinger); |
| 95 | NGLOG_DEBUG(Service_AM, "called"); | 95 | LOG_DEBUG(Service_AM, "called"); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) | 98 | AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) |
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 5b6dfb48f..6e7438580 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp | |||
| @@ -27,14 +27,14 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { | |||
| 27 | IPC::ResponseBuilder rb{ctx, 4}; | 27 | IPC::ResponseBuilder rb{ctx, 4}; |
| 28 | rb.Push(RESULT_SUCCESS); | 28 | rb.Push(RESULT_SUCCESS); |
| 29 | rb.Push<u64>(0); | 29 | rb.Push<u64>(0); |
| 30 | NGLOG_WARNING(Service_AOC, "(STUBBED) called"); | 30 | LOG_WARNING(Service_AOC, "(STUBBED) called"); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { | 33 | void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { |
| 34 | IPC::ResponseBuilder rb{ctx, 4}; | 34 | IPC::ResponseBuilder rb{ctx, 4}; |
| 35 | rb.Push(RESULT_SUCCESS); | 35 | rb.Push(RESULT_SUCCESS); |
| 36 | rb.Push<u64>(0); | 36 | rb.Push<u64>(0); |
| 37 | NGLOG_WARNING(Service_AOC, "(STUBBED) called"); | 37 | LOG_WARNING(Service_AOC, "(STUBBED) called"); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 40 | void InstallInterfaces(SM::ServiceManager& service_manager) { |
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index 3a03188ce..751d73f8d 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp | |||
| @@ -29,8 +29,8 @@ private: | |||
| 29 | IPC::ResponseBuilder rb{ctx, 2}; | 29 | IPC::ResponseBuilder rb{ctx, 2}; |
| 30 | rb.Push(RESULT_SUCCESS); | 30 | rb.Push(RESULT_SUCCESS); |
| 31 | 31 | ||
| 32 | NGLOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode), | 32 | LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode), |
| 33 | config); | 33 | config); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { | 36 | void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { |
| @@ -42,7 +42,7 @@ private: | |||
| 42 | rb.Push(RESULT_SUCCESS); | 42 | rb.Push(RESULT_SUCCESS); |
| 43 | rb.Push<u32>(0); // Performance configuration | 43 | rb.Push<u32>(0); // Performance configuration |
| 44 | 44 | ||
| 45 | NGLOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode)); | 45 | LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode)); |
| 46 | } | 46 | } |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp index 92f910b5f..d231e91e1 100644 --- a/src/core/hle/service/audio/audio.cpp +++ b/src/core/hle/service/audio/audio.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "core/hle/service/audio/audrec_u.h" | 8 | #include "core/hle/service/audio/audrec_u.h" |
| 9 | #include "core/hle/service/audio/audren_u.h" | 9 | #include "core/hle/service/audio/audren_u.h" |
| 10 | #include "core/hle/service/audio/codecctl.h" | 10 | #include "core/hle/service/audio/codecctl.h" |
| 11 | #include "core/hle/service/audio/hwopus.h" | ||
| 11 | 12 | ||
| 12 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 13 | 14 | ||
| @@ -17,6 +18,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) { | |||
| 17 | std::make_shared<AudRecU>()->InstallAsService(service_manager); | 18 | std::make_shared<AudRecU>()->InstallAsService(service_manager); |
| 18 | std::make_shared<AudRenU>()->InstallAsService(service_manager); | 19 | std::make_shared<AudRenU>()->InstallAsService(service_manager); |
| 19 | std::make_shared<CodecCtl>()->InstallAsService(service_manager); | 20 | std::make_shared<CodecCtl>()->InstallAsService(service_manager); |
| 21 | std::make_shared<HwOpus>()->InstallAsService(service_manager); | ||
| 20 | } | 22 | } |
| 21 | 23 | ||
| 22 | } // namespace Service::Audio | 24 | } // namespace Service::Audio |
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 402eaa306..1b4b649d8 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -60,14 +60,14 @@ public: | |||
| 60 | 60 | ||
| 61 | private: | 61 | private: |
| 62 | void GetAudioOutState(Kernel::HLERequestContext& ctx) { | 62 | void GetAudioOutState(Kernel::HLERequestContext& ctx) { |
| 63 | NGLOG_DEBUG(Service_Audio, "called"); | 63 | LOG_DEBUG(Service_Audio, "called"); |
| 64 | IPC::ResponseBuilder rb{ctx, 3}; | 64 | IPC::ResponseBuilder rb{ctx, 3}; |
| 65 | rb.Push(RESULT_SUCCESS); | 65 | rb.Push(RESULT_SUCCESS); |
| 66 | rb.Push(static_cast<u32>(audio_out_state)); | 66 | rb.Push(static_cast<u32>(audio_out_state)); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | void StartAudioOut(Kernel::HLERequestContext& ctx) { | 69 | void StartAudioOut(Kernel::HLERequestContext& ctx) { |
| 70 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 70 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 71 | 71 | ||
| 72 | // Start audio | 72 | // Start audio |
| 73 | audio_out_state = AudioState::Started; | 73 | audio_out_state = AudioState::Started; |
| @@ -77,7 +77,7 @@ private: | |||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | void StopAudioOut(Kernel::HLERequestContext& ctx) { | 79 | void StopAudioOut(Kernel::HLERequestContext& ctx) { |
| 80 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 80 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 81 | 81 | ||
| 82 | // Stop audio | 82 | // Stop audio |
| 83 | audio_out_state = AudioState::Stopped; | 83 | audio_out_state = AudioState::Stopped; |
| @@ -89,7 +89,7 @@ private: | |||
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | void RegisterBufferEvent(Kernel::HLERequestContext& ctx) { | 91 | void RegisterBufferEvent(Kernel::HLERequestContext& ctx) { |
| 92 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 92 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 93 | 93 | ||
| 94 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 94 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 95 | rb.Push(RESULT_SUCCESS); | 95 | rb.Push(RESULT_SUCCESS); |
| @@ -97,7 +97,7 @@ private: | |||
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | void AppendAudioOutBuffer(Kernel::HLERequestContext& ctx) { | 99 | void AppendAudioOutBuffer(Kernel::HLERequestContext& ctx) { |
| 100 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 100 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 101 | IPC::RequestParser rp{ctx}; | 101 | IPC::RequestParser rp{ctx}; |
| 102 | 102 | ||
| 103 | const u64 key{rp.Pop<u64>()}; | 103 | const u64 key{rp.Pop<u64>()}; |
| @@ -108,7 +108,7 @@ private: | |||
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | void GetReleasedAudioOutBuffer(Kernel::HLERequestContext& ctx) { | 110 | void GetReleasedAudioOutBuffer(Kernel::HLERequestContext& ctx) { |
| 111 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 111 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 112 | 112 | ||
| 113 | // TODO(st4rk): This is how libtransistor currently implements the | 113 | // TODO(st4rk): This is how libtransistor currently implements the |
| 114 | // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address | 114 | // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address |
| @@ -164,7 +164,7 @@ private: | |||
| 164 | }; | 164 | }; |
| 165 | 165 | ||
| 166 | void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) { | 166 | void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) { |
| 167 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 167 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 168 | IPC::RequestParser rp{ctx}; | 168 | IPC::RequestParser rp{ctx}; |
| 169 | 169 | ||
| 170 | const std::string audio_interface = "AudioInterface"; | 170 | const std::string audio_interface = "AudioInterface"; |
| @@ -180,7 +180,7 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) { | |||
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) { | 182 | void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) { |
| 183 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 183 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 184 | 184 | ||
| 185 | if (!audio_out_interface) { | 185 | if (!audio_out_interface) { |
| 186 | audio_out_interface = std::make_shared<IAudioOut>(); | 186 | audio_out_interface = std::make_shared<IAudioOut>(); |
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 6e8002bc9..2da936b27 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -17,7 +17,8 @@ constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)}; | |||
| 17 | 17 | ||
| 18 | class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { | 18 | class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { |
| 19 | public: | 19 | public: |
| 20 | IAudioRenderer() : ServiceFramework("IAudioRenderer") { | 20 | IAudioRenderer(AudioRendererParameter audren_params) |
| 21 | : ServiceFramework("IAudioRenderer"), worker_params(audren_params) { | ||
| 21 | static const FunctionInfo functions[] = { | 22 | static const FunctionInfo functions[] = { |
| 22 | {0, nullptr, "GetAudioRendererSampleRate"}, | 23 | {0, nullptr, "GetAudioRendererSampleRate"}, |
| 23 | {1, nullptr, "GetAudioRendererSampleCount"}, | 24 | {1, nullptr, "GetAudioRendererSampleCount"}, |
| @@ -46,6 +47,7 @@ public: | |||
| 46 | 47 | ||
| 47 | // Start the audio event | 48 | // Start the audio event |
| 48 | CoreTiming::ScheduleEvent(audio_ticks, audio_event); | 49 | CoreTiming::ScheduleEvent(audio_ticks, audio_event); |
| 50 | voice_status_list.reserve(worker_params.voice_count); | ||
| 49 | } | 51 | } |
| 50 | ~IAudioRenderer() { | 52 | ~IAudioRenderer() { |
| 51 | CoreTiming::UnscheduleEvent(audio_event, 0); | 53 | CoreTiming::UnscheduleEvent(audio_event, 0); |
| @@ -57,30 +59,63 @@ private: | |||
| 57 | } | 59 | } |
| 58 | 60 | ||
| 59 | void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) { | 61 | void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) { |
| 60 | NGLOG_DEBUG(Service_Audio, "{}", ctx.Description()); | 62 | UpdateDataHeader config{}; |
| 61 | AudioRendererResponseData response_data{}; | 63 | auto buf = ctx.ReadBuffer(); |
| 62 | 64 | std::memcpy(&config, buf.data(), sizeof(UpdateDataHeader)); | |
| 63 | response_data.section_0_size = | 65 | u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4); |
| 64 | static_cast<u32>(response_data.state_entries.size() * sizeof(AudioRendererStateEntry)); | 66 | |
| 65 | response_data.section_1_size = static_cast<u32>(response_data.section_1.size()); | 67 | std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count); |
| 66 | response_data.section_2_size = static_cast<u32>(response_data.section_2.size()); | 68 | std::memcpy(mem_pool_info.data(), |
| 67 | response_data.section_3_size = static_cast<u32>(response_data.section_3.size()); | 69 | buf.data() + sizeof(UpdateDataHeader) + config.behavior_size, |
| 68 | response_data.section_4_size = static_cast<u32>(response_data.section_4.size()); | 70 | memory_pool_count * sizeof(MemoryPoolInfo)); |
| 69 | response_data.section_5_size = static_cast<u32>(response_data.section_5.size()); | 71 | |
| 70 | response_data.total_size = sizeof(AudioRendererResponseData); | 72 | std::vector<VoiceInfo> voice_info(worker_params.voice_count); |
| 71 | 73 | std::memcpy(voice_info.data(), | |
| 72 | for (unsigned i = 0; i < response_data.state_entries.size(); i++) { | 74 | buf.data() + sizeof(UpdateDataHeader) + config.behavior_size + |
| 73 | // 4 = Busy and 5 = Ready? | 75 | config.memory_pools_size + config.voice_resource_size, |
| 74 | response_data.state_entries[i].state = 5; | 76 | worker_params.voice_count * sizeof(VoiceInfo)); |
| 77 | |||
| 78 | UpdateDataHeader response_data{worker_params}; | ||
| 79 | |||
| 80 | ASSERT(ctx.GetWriteBufferSize() == response_data.total_size); | ||
| 81 | |||
| 82 | std::vector<u8> output(response_data.total_size); | ||
| 83 | std::memcpy(output.data(), &response_data, sizeof(UpdateDataHeader)); | ||
| 84 | std::vector<MemoryPoolEntry> memory_pool(memory_pool_count); | ||
| 85 | for (unsigned i = 0; i < memory_pool.size(); i++) { | ||
| 86 | if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestAttach) | ||
| 87 | memory_pool[i].state = MemoryPoolStates::Attached; | ||
| 88 | else if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestDetach) | ||
| 89 | memory_pool[i].state = MemoryPoolStates::Detached; | ||
| 90 | else | ||
| 91 | memory_pool[i].state = mem_pool_info[i].pool_state; | ||
| 75 | } | 92 | } |
| 93 | std::memcpy(output.data() + sizeof(UpdateDataHeader), memory_pool.data(), | ||
| 94 | response_data.memory_pools_size); | ||
| 95 | |||
| 96 | for (unsigned i = 0; i < voice_info.size(); i++) { | ||
| 97 | if (voice_info[i].is_new) { | ||
| 98 | voice_status_list[i].played_sample_count = 0; | ||
| 99 | voice_status_list[i].wave_buffer_consumed = 0; | ||
| 100 | } else if (voice_info[i].play_state == (u8)PlayStates::Started) { | ||
| 101 | for (u32 buff_idx = 0; buff_idx < voice_info[i].wave_buffer_count; buff_idx++) { | ||
| 102 | voice_status_list[i].played_sample_count += | ||
| 103 | (voice_info[i].wave_buffer[buff_idx].end_sample_offset - | ||
| 104 | voice_info[i].wave_buffer[buff_idx].start_sample_offset) / | ||
| 105 | 2; | ||
| 106 | voice_status_list[i].wave_buffer_consumed++; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } | ||
| 110 | std::memcpy(output.data() + sizeof(UpdateDataHeader) + response_data.memory_pools_size, | ||
| 111 | voice_status_list.data(), response_data.voices_size); | ||
| 76 | 112 | ||
| 77 | ctx.WriteBuffer(&response_data, response_data.total_size); | 113 | ctx.WriteBuffer(output); |
| 78 | 114 | ||
| 79 | IPC::ResponseBuilder rb{ctx, 2}; | 115 | IPC::ResponseBuilder rb{ctx, 2}; |
| 80 | |||
| 81 | rb.Push(RESULT_SUCCESS); | 116 | rb.Push(RESULT_SUCCESS); |
| 82 | 117 | ||
| 83 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 118 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 84 | } | 119 | } |
| 85 | 120 | ||
| 86 | void StartAudioRenderer(Kernel::HLERequestContext& ctx) { | 121 | void StartAudioRenderer(Kernel::HLERequestContext& ctx) { |
| @@ -88,7 +123,7 @@ private: | |||
| 88 | 123 | ||
| 89 | rb.Push(RESULT_SUCCESS); | 124 | rb.Push(RESULT_SUCCESS); |
| 90 | 125 | ||
| 91 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 126 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 92 | } | 127 | } |
| 93 | 128 | ||
| 94 | void StopAudioRenderer(Kernel::HLERequestContext& ctx) { | 129 | void StopAudioRenderer(Kernel::HLERequestContext& ctx) { |
| @@ -96,7 +131,7 @@ private: | |||
| 96 | 131 | ||
| 97 | rb.Push(RESULT_SUCCESS); | 132 | rb.Push(RESULT_SUCCESS); |
| 98 | 133 | ||
| 99 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 134 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 100 | } | 135 | } |
| 101 | 136 | ||
| 102 | void QuerySystemEvent(Kernel::HLERequestContext& ctx) { | 137 | void QuerySystemEvent(Kernel::HLERequestContext& ctx) { |
| @@ -106,51 +141,132 @@ private: | |||
| 106 | rb.Push(RESULT_SUCCESS); | 141 | rb.Push(RESULT_SUCCESS); |
| 107 | rb.PushCopyObjects(system_event); | 142 | rb.PushCopyObjects(system_event); |
| 108 | 143 | ||
| 109 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 144 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 110 | } | 145 | } |
| 111 | 146 | ||
| 112 | struct AudioRendererStateEntry { | 147 | enum class MemoryPoolStates : u32 { // Should be LE |
| 113 | u32_le state; | 148 | Invalid = 0x0, |
| 149 | Unknown = 0x1, | ||
| 150 | RequestDetach = 0x2, | ||
| 151 | Detached = 0x3, | ||
| 152 | RequestAttach = 0x4, | ||
| 153 | Attached = 0x5, | ||
| 154 | Released = 0x6, | ||
| 155 | }; | ||
| 156 | |||
| 157 | enum class PlayStates : u8 { | ||
| 158 | Started = 0, | ||
| 159 | Stopped = 1, | ||
| 160 | }; | ||
| 161 | |||
| 162 | struct MemoryPoolEntry { | ||
| 163 | MemoryPoolStates state; | ||
| 114 | u32_le unknown_4; | 164 | u32_le unknown_4; |
| 115 | u32_le unknown_8; | 165 | u32_le unknown_8; |
| 116 | u32_le unknown_c; | 166 | u32_le unknown_c; |
| 117 | }; | 167 | }; |
| 118 | static_assert(sizeof(AudioRendererStateEntry) == 0x10, | 168 | static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size"); |
| 119 | "AudioRendererStateEntry has wrong size"); | 169 | |
| 120 | 170 | struct MemoryPoolInfo { | |
| 121 | struct AudioRendererResponseData { | 171 | u64_le pool_address; |
| 122 | u32_le unknown_0; | 172 | u64_le pool_size; |
| 123 | u32_le section_5_size; | 173 | MemoryPoolStates pool_state; |
| 124 | u32_le section_0_size; | 174 | INSERT_PADDING_WORDS(3); // Unknown |
| 125 | u32_le section_1_size; | 175 | }; |
| 126 | u32_le unknown_10; | 176 | static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size"); |
| 127 | u32_le section_2_size; | 177 | |
| 128 | u32_le unknown_18; | 178 | struct UpdateDataHeader { |
| 129 | u32_le section_3_size; | 179 | UpdateDataHeader() {} |
| 130 | u32_le section_4_size; | 180 | |
| 131 | u32_le unknown_24; | 181 | UpdateDataHeader(const AudioRendererParameter& config) { |
| 132 | u32_le unknown_28; | 182 | revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision |
| 133 | u32_le unknown_2c; | 183 | behavior_size = 0xb0; |
| 134 | u32_le unknown_30; | 184 | memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10; |
| 135 | u32_le unknown_34; | 185 | voices_size = config.voice_count * 0x10; |
| 136 | u32_le unknown_38; | 186 | effects_size = config.effect_count * 0x10; |
| 187 | sinks_size = config.sink_count * 0x20; | ||
| 188 | performance_manager_size = 0x10; | ||
| 189 | total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size + | ||
| 190 | voices_size + effects_size + sinks_size + performance_manager_size; | ||
| 191 | } | ||
| 192 | |||
| 193 | u32_le revision; | ||
| 194 | u32_le behavior_size; | ||
| 195 | u32_le memory_pools_size; | ||
| 196 | u32_le voices_size; | ||
| 197 | u32_le voice_resource_size; | ||
| 198 | u32_le effects_size; | ||
| 199 | u32_le mixes_size; | ||
| 200 | u32_le sinks_size; | ||
| 201 | u32_le performance_manager_size; | ||
| 202 | INSERT_PADDING_WORDS(6); | ||
| 137 | u32_le total_size; | 203 | u32_le total_size; |
| 204 | }; | ||
| 205 | static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size"); | ||
| 138 | 206 | ||
| 139 | std::array<AudioRendererStateEntry, 0x18e> state_entries; | 207 | struct BiquadFilter { |
| 208 | u8 enable; | ||
| 209 | INSERT_PADDING_BYTES(1); | ||
| 210 | s16_le numerator[3]; | ||
| 211 | s16_le denominator[2]; | ||
| 212 | }; | ||
| 213 | static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size"); | ||
| 214 | |||
| 215 | struct WaveBuffer { | ||
| 216 | u64_le buffer_addr; | ||
| 217 | u64_le buffer_sz; | ||
| 218 | s32_le start_sample_offset; | ||
| 219 | s32_le end_sample_offset; | ||
| 220 | u8 loop; | ||
| 221 | u8 end_of_stream; | ||
| 222 | u8 sent_to_server; | ||
| 223 | INSERT_PADDING_BYTES(5); | ||
| 224 | u64 context_addr; | ||
| 225 | u64 context_sz; | ||
| 226 | INSERT_PADDING_BYTES(8); | ||
| 227 | }; | ||
| 228 | static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size"); | ||
| 229 | |||
| 230 | struct VoiceInfo { | ||
| 231 | u32_le id; | ||
| 232 | u32_le node_id; | ||
| 233 | u8 is_new; | ||
| 234 | u8 is_in_use; | ||
| 235 | u8 play_state; | ||
| 236 | u8 sample_format; | ||
| 237 | u32_le sample_rate; | ||
| 238 | u32_le priority; | ||
| 239 | u32_le sorting_order; | ||
| 240 | u32_le channel_count; | ||
| 241 | float_le pitch; | ||
| 242 | float_le volume; | ||
| 243 | BiquadFilter biquad_filter[2]; | ||
| 244 | u32_le wave_buffer_count; | ||
| 245 | u16_le wave_buffer_head; | ||
| 246 | INSERT_PADDING_BYTES(6); | ||
| 247 | u64_le additional_params_addr; | ||
| 248 | u64_le additional_params_sz; | ||
| 249 | u32_le mix_id; | ||
| 250 | u32_le splitter_info_id; | ||
| 251 | WaveBuffer wave_buffer[4]; | ||
| 252 | u32_le voice_channel_resource_ids[6]; | ||
| 253 | INSERT_PADDING_BYTES(24); | ||
| 254 | }; | ||
| 255 | static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size"); | ||
| 140 | 256 | ||
| 141 | std::array<u8, 0x600> section_1; | 257 | struct VoiceOutStatus { |
| 142 | std::array<u8, 0xe0> section_2; | 258 | u64_le played_sample_count; |
| 143 | std::array<u8, 0x20> section_3; | 259 | u32_le wave_buffer_consumed; |
| 144 | std::array<u8, 0x10> section_4; | 260 | INSERT_PADDING_WORDS(1); |
| 145 | std::array<u8, 0xb0> section_5; | ||
| 146 | }; | 261 | }; |
| 147 | static_assert(sizeof(AudioRendererResponseData) == 0x20e0, | 262 | static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size"); |
| 148 | "AudioRendererResponseData has wrong size"); | ||
| 149 | 263 | ||
| 150 | /// This is used to trigger the audio event callback. | 264 | /// This is used to trigger the audio event callback. |
| 151 | CoreTiming::EventType* audio_event; | 265 | CoreTiming::EventType* audio_event; |
| 152 | 266 | ||
| 153 | Kernel::SharedPtr<Kernel::Event> system_event; | 267 | Kernel::SharedPtr<Kernel::Event> system_event; |
| 268 | AudioRendererParameter worker_params; | ||
| 269 | std::vector<VoiceOutStatus> voice_status_list; | ||
| 154 | }; | 270 | }; |
| 155 | 271 | ||
| 156 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { | 272 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { |
| @@ -179,7 +295,7 @@ public: | |||
| 179 | 295 | ||
| 180 | private: | 296 | private: |
| 181 | void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { | 297 | void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { |
| 182 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 298 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 183 | IPC::RequestParser rp{ctx}; | 299 | IPC::RequestParser rp{ctx}; |
| 184 | 300 | ||
| 185 | const std::string audio_interface = "AudioInterface"; | 301 | const std::string audio_interface = "AudioInterface"; |
| @@ -191,7 +307,7 @@ private: | |||
| 191 | } | 307 | } |
| 192 | 308 | ||
| 193 | void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { | 309 | void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { |
| 194 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 310 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 195 | 311 | ||
| 196 | IPC::RequestParser rp{ctx}; | 312 | IPC::RequestParser rp{ctx}; |
| 197 | f32 volume = static_cast<f32>(rp.Pop<u32>()); | 313 | f32 volume = static_cast<f32>(rp.Pop<u32>()); |
| @@ -204,7 +320,7 @@ private: | |||
| 204 | } | 320 | } |
| 205 | 321 | ||
| 206 | void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) { | 322 | void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) { |
| 207 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 323 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 208 | IPC::RequestParser rp{ctx}; | 324 | IPC::RequestParser rp{ctx}; |
| 209 | 325 | ||
| 210 | const std::string audio_interface = "AudioDevice"; | 326 | const std::string audio_interface = "AudioDevice"; |
| @@ -216,7 +332,7 @@ private: | |||
| 216 | } | 332 | } |
| 217 | 333 | ||
| 218 | void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { | 334 | void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { |
| 219 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 335 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 220 | 336 | ||
| 221 | buffer_event->Signal(); | 337 | buffer_event->Signal(); |
| 222 | 338 | ||
| @@ -226,7 +342,7 @@ private: | |||
| 226 | } | 342 | } |
| 227 | 343 | ||
| 228 | void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { | 344 | void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { |
| 229 | NGLOG_WARNING(Service_Audio, "(STUBBED) called"); | 345 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 230 | IPC::ResponseBuilder rb{ctx, 3}; | 346 | IPC::ResponseBuilder rb{ctx, 3}; |
| 231 | rb.Push(RESULT_SUCCESS); | 347 | rb.Push(RESULT_SUCCESS); |
| 232 | rb.Push<u32>(1); | 348 | rb.Push<u32>(1); |
| @@ -248,31 +364,33 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") { | |||
| 248 | } | 364 | } |
| 249 | 365 | ||
| 250 | void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { | 366 | void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { |
| 367 | IPC::RequestParser rp{ctx}; | ||
| 368 | auto params = rp.PopRaw<AudioRendererParameter>(); | ||
| 251 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 369 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 252 | 370 | ||
| 253 | rb.Push(RESULT_SUCCESS); | 371 | rb.Push(RESULT_SUCCESS); |
| 254 | rb.PushIpcInterface<Audio::IAudioRenderer>(); | 372 | rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params)); |
| 255 | 373 | ||
| 256 | NGLOG_DEBUG(Service_Audio, "called"); | 374 | LOG_DEBUG(Service_Audio, "called"); |
| 257 | } | 375 | } |
| 258 | 376 | ||
| 259 | void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | 377 | void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { |
| 260 | IPC::RequestParser rp{ctx}; | 378 | IPC::RequestParser rp{ctx}; |
| 261 | auto params = rp.PopRaw<WorkerBufferParameters>(); | 379 | auto params = rp.PopRaw<AudioRendererParameter>(); |
| 262 | 380 | ||
| 263 | u64 buffer_sz = Common::AlignUp(4 * params.unknown8, 0x40); | 381 | u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40); |
| 264 | buffer_sz += params.unknownC * 1024; | 382 | buffer_sz += params.unknown_c * 1024; |
| 265 | buffer_sz += 0x940 * (params.unknownC + 1); | 383 | buffer_sz += 0x940 * (params.unknown_c + 1); |
| 266 | buffer_sz += 0x3F0 * params.voice_count; | 384 | buffer_sz += 0x3F0 * params.voice_count; |
| 267 | buffer_sz += Common::AlignUp(8 * (params.unknownC + 1), 0x10); | 385 | buffer_sz += Common::AlignUp(8 * (params.unknown_c + 1), 0x10); |
| 268 | buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10); | 386 | buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10); |
| 269 | buffer_sz += | 387 | buffer_sz += |
| 270 | Common::AlignUp((0x3C0 * (params.sink_count + params.unknownC) + 4 * params.sample_count) * | 388 | Common::AlignUp((0x3C0 * (params.sink_count + params.unknown_c) + 4 * params.sample_count) * |
| 271 | (params.unknown8 + 6), | 389 | (params.unknown_8 + 6), |
| 272 | 0x40); | 390 | 0x40); |
| 273 | 391 | ||
| 274 | if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) { | 392 | if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { |
| 275 | u32 count = params.unknownC + 1; | 393 | u32 count = params.unknown_c + 1; |
| 276 | u64 node_count = Common::AlignUp(count, 0x40); | 394 | u64 node_count = Common::AlignUp(count, 0x40); |
| 277 | u64 node_state_buffer_sz = | 395 | u64 node_state_buffer_sz = |
| 278 | 4 * (node_count * node_count) + 0xC * node_count + 2 * (node_count / 8); | 396 | 4 * (node_count * node_count) + 0xC * node_count + 2 * (node_count / 8); |
| @@ -287,20 +405,20 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 287 | } | 405 | } |
| 288 | 406 | ||
| 289 | buffer_sz += 0x20 * (params.effect_count + 4 * params.voice_count) + 0x50; | 407 | buffer_sz += 0x20 * (params.effect_count + 4 * params.voice_count) + 0x50; |
| 290 | if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) { | 408 | if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { |
| 291 | buffer_sz += 0xE0 * params.unknown2c; | 409 | buffer_sz += 0xE0 * params.unknown_2c; |
| 292 | buffer_sz += 0x20 * params.splitter_count; | 410 | buffer_sz += 0x20 * params.splitter_count; |
| 293 | buffer_sz += Common::AlignUp(4 * params.unknown2c, 0x10); | 411 | buffer_sz += Common::AlignUp(4 * params.unknown_2c, 0x10); |
| 294 | } | 412 | } |
| 295 | buffer_sz = Common::AlignUp(buffer_sz, 0x40) + 0x170 * params.sink_count; | 413 | buffer_sz = Common::AlignUp(buffer_sz, 0x40) + 0x170 * params.sink_count; |
| 296 | u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count + | 414 | u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count + |
| 297 | ((params.voice_count * 256) | 0x40); | 415 | ((params.voice_count * 256) | 0x40); |
| 298 | 416 | ||
| 299 | if (params.unknown1c >= 1) { | 417 | if (params.unknown_1c >= 1) { |
| 300 | output_sz = Common::AlignUp(((16 * params.sink_count + 16 * params.effect_count + | 418 | output_sz = Common::AlignUp(((16 * params.sink_count + 16 * params.effect_count + |
| 301 | 16 * params.voice_count + 16) + | 419 | 16 * params.voice_count + 16) + |
| 302 | 0x658) * | 420 | 0x658) * |
| 303 | (params.unknown1c + 1) + | 421 | (params.unknown_1c + 1) + |
| 304 | 0xc0, | 422 | 0xc0, |
| 305 | 0x40) + | 423 | 0x40) + |
| 306 | output_sz; | 424 | output_sz; |
| @@ -312,7 +430,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 312 | rb.Push(RESULT_SUCCESS); | 430 | rb.Push(RESULT_SUCCESS); |
| 313 | rb.Push<u64>(output_sz); | 431 | rb.Push<u64>(output_sz); |
| 314 | 432 | ||
| 315 | NGLOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz); | 433 | LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz); |
| 316 | } | 434 | } |
| 317 | 435 | ||
| 318 | void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { | 436 | void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { |
| @@ -321,14 +439,14 @@ void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { | |||
| 321 | rb.Push(RESULT_SUCCESS); | 439 | rb.Push(RESULT_SUCCESS); |
| 322 | rb.PushIpcInterface<Audio::IAudioDevice>(); | 440 | rb.PushIpcInterface<Audio::IAudioDevice>(); |
| 323 | 441 | ||
| 324 | NGLOG_DEBUG(Service_Audio, "called"); | 442 | LOG_DEBUG(Service_Audio, "called"); |
| 325 | } | 443 | } |
| 326 | 444 | ||
| 327 | bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { | 445 | bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { |
| 328 | u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap | 446 | u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap |
| 329 | switch (feature) { | 447 | switch (feature) { |
| 330 | case AudioFeatures::Splitter: | 448 | case AudioFeatures::Splitter: |
| 331 | return version_num >= 2; | 449 | return version_num >= 2u; |
| 332 | default: | 450 | default: |
| 333 | return false; | 451 | return false; |
| 334 | } | 452 | } |
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index fe53de4ce..b9b81db4f 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h | |||
| @@ -12,6 +12,24 @@ class HLERequestContext; | |||
| 12 | 12 | ||
| 13 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 14 | 14 | ||
| 15 | struct AudioRendererParameter { | ||
| 16 | u32_le sample_rate; | ||
| 17 | u32_le sample_count; | ||
| 18 | u32_le unknown_8; | ||
| 19 | u32_le unknown_c; | ||
| 20 | u32_le voice_count; | ||
| 21 | u32_le sink_count; | ||
| 22 | u32_le effect_count; | ||
| 23 | u32_le unknown_1c; | ||
| 24 | u8 unknown_20; | ||
| 25 | INSERT_PADDING_BYTES(3); | ||
| 26 | u32_le splitter_count; | ||
| 27 | u32_le unknown_2c; | ||
| 28 | INSERT_PADDING_WORDS(1); | ||
| 29 | u32_le revision; | ||
| 30 | }; | ||
| 31 | static_assert(sizeof(AudioRendererParameter) == 52, "AudioRendererParameter is an invalid size"); | ||
| 32 | |||
| 15 | class AudRenU final : public ServiceFramework<AudRenU> { | 33 | class AudRenU final : public ServiceFramework<AudRenU> { |
| 16 | public: | 34 | public: |
| 17 | explicit AudRenU(); | 35 | explicit AudRenU(); |
| @@ -22,25 +40,6 @@ private: | |||
| 22 | void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx); | 40 | void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx); |
| 23 | void GetAudioDevice(Kernel::HLERequestContext& ctx); | 41 | void GetAudioDevice(Kernel::HLERequestContext& ctx); |
| 24 | 42 | ||
| 25 | struct WorkerBufferParameters { | ||
| 26 | u32_le sample_rate; | ||
| 27 | u32_le sample_count; | ||
| 28 | u32_le unknown8; | ||
| 29 | u32_le unknownC; | ||
| 30 | u32_le voice_count; | ||
| 31 | u32_le sink_count; | ||
| 32 | u32_le effect_count; | ||
| 33 | u32_le unknown1c; | ||
| 34 | u8 unknown20; | ||
| 35 | u8 padding1[3]; | ||
| 36 | u32_le splitter_count; | ||
| 37 | u32_le unknown2c; | ||
| 38 | u8 padding2[4]; | ||
| 39 | u32_le magic; | ||
| 40 | }; | ||
| 41 | static_assert(sizeof(WorkerBufferParameters) == 52, | ||
| 42 | "WorkerBufferParameters is an invalid size"); | ||
| 43 | |||
| 44 | enum class AudioFeatures : u32 { | 43 | enum class AudioFeatures : u32 { |
| 45 | Splitter, | 44 | Splitter, |
| 46 | }; | 45 | }; |
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp new file mode 100644 index 000000000..844df382c --- /dev/null +++ b/src/core/hle/service/audio/hwopus.cpp | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | ||
| 7 | #include "core/hle/kernel/hle_ipc.h" | ||
| 8 | #include "core/hle/service/audio/hwopus.h" | ||
| 9 | |||
| 10 | namespace Service::Audio { | ||
| 11 | |||
| 12 | void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { | ||
| 13 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 14 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 15 | rb.Push(RESULT_SUCCESS); | ||
| 16 | rb.Push<u32>(0x4000); | ||
| 17 | } | ||
| 18 | |||
| 19 | HwOpus::HwOpus() : ServiceFramework("hwopus") { | ||
| 20 | static const FunctionInfo functions[] = { | ||
| 21 | {0, nullptr, "Initialize"}, | ||
| 22 | {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"}, | ||
| 23 | {2, nullptr, "InitializeMultiStream"}, | ||
| 24 | {3, nullptr, "GetWorkBufferSizeMultiStream"}, | ||
| 25 | }; | ||
| 26 | RegisterHandlers(functions); | ||
| 27 | } | ||
| 28 | |||
| 29 | } // namespace Service::Audio | ||
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h new file mode 100644 index 000000000..090b8c825 --- /dev/null +++ b/src/core/hle/service/audio/hwopus.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service::Audio { | ||
| 10 | |||
| 11 | class HwOpus final : public ServiceFramework<HwOpus> { | ||
| 12 | public: | ||
| 13 | explicit HwOpus(); | ||
| 14 | ~HwOpus() = default; | ||
| 15 | |||
| 16 | private: | ||
| 17 | void GetWorkBufferSize(Kernel::HLERequestContext& ctx); | ||
| 18 | }; | ||
| 19 | |||
| 20 | } // namespace Service::Audio | ||
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 52be9db22..35e024c3d 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp | |||
| @@ -36,7 +36,7 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { | |||
| 36 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 36 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 37 | rb.Push(RESULT_SUCCESS); | 37 | rb.Push(RESULT_SUCCESS); |
| 38 | rb.PushIpcInterface<IBcatService>(); | 38 | rb.PushIpcInterface<IBcatService>(); |
| 39 | NGLOG_DEBUG(Service_BCAT, "called"); | 39 | LOG_DEBUG(Service_BCAT, "called"); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 42 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 2d4282209..299b9474f 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp | |||
| @@ -16,13 +16,13 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | |||
| 16 | void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) { | 16 | void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) { |
| 17 | IPC::RequestParser rp(ctx); | 17 | IPC::RequestParser rp(ctx); |
| 18 | u32 error_code = rp.Pop<u32>(); | 18 | u32 error_code = rp.Pop<u32>(); |
| 19 | NGLOG_WARNING(Service_Fatal, "(STUBBED) called, error_code=0x{:X}", error_code); | 19 | LOG_WARNING(Service_Fatal, "(STUBBED) called, error_code=0x{:X}", error_code); |
| 20 | IPC::ResponseBuilder rb{ctx, 2}; | 20 | IPC::ResponseBuilder rb{ctx, 2}; |
| 21 | rb.Push(RESULT_SUCCESS); | 21 | rb.Push(RESULT_SUCCESS); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) { | 24 | void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) { |
| 25 | NGLOG_WARNING(Service_Fatal, "(STUBBED) called"); | 25 | LOG_WARNING(Service_Fatal, "(STUBBED) called"); |
| 26 | IPC::ResponseBuilder rb{ctx, 2}; | 26 | IPC::ResponseBuilder rb{ctx, 2}; |
| 27 | rb.Push(RESULT_SUCCESS); | 27 | rb.Push(RESULT_SUCCESS); |
| 28 | } | 28 | } |
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 68d1c90a5..f58b518b6 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -25,14 +25,14 @@ ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& fact | |||
| 25 | ASSERT_MSG(inserted, "Tried to register more than one system with same id code"); | 25 | ASSERT_MSG(inserted, "Tried to register more than one system with same id code"); |
| 26 | 26 | ||
| 27 | auto& filesystem = result.first->second; | 27 | auto& filesystem = result.first->second; |
| 28 | NGLOG_DEBUG(Service_FS, "Registered file system {} with id code 0x{:08X}", | 28 | LOG_DEBUG(Service_FS, "Registered file system {} with id code 0x{:08X}", filesystem->GetName(), |
| 29 | filesystem->GetName(), static_cast<u32>(type)); | 29 | static_cast<u32>(type)); |
| 30 | return RESULT_SUCCESS; | 30 | return RESULT_SUCCESS; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, | 33 | ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, |
| 34 | FileSys::Path& path) { | 34 | FileSys::Path& path) { |
| 35 | NGLOG_TRACE(Service_FS, "Opening FileSystem with type={}", static_cast<u32>(type)); | 35 | LOG_TRACE(Service_FS, "Opening FileSystem with type={}", static_cast<u32>(type)); |
| 36 | 36 | ||
| 37 | auto itr = filesystem_map.find(type); | 37 | auto itr = filesystem_map.find(type); |
| 38 | if (itr == filesystem_map.end()) { | 38 | if (itr == filesystem_map.end()) { |
| @@ -44,7 +44,7 @@ ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | ResultCode FormatFileSystem(Type type) { | 46 | ResultCode FormatFileSystem(Type type) { |
| 47 | NGLOG_TRACE(Service_FS, "Formatting FileSystem with type={}", static_cast<u32>(type)); | 47 | LOG_TRACE(Service_FS, "Formatting FileSystem with type={}", static_cast<u32>(type)); |
| 48 | 48 | ||
| 49 | auto itr = filesystem_map.find(type); | 49 | auto itr = filesystem_map.find(type); |
| 50 | if (itr == filesystem_map.end()) { | 50 | if (itr == filesystem_map.end()) { |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index eb5748cf8..82efe7f7d 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -37,7 +37,7 @@ private: | |||
| 37 | const s64 offset = rp.Pop<s64>(); | 37 | const s64 offset = rp.Pop<s64>(); |
| 38 | const s64 length = rp.Pop<s64>(); | 38 | const s64 length = rp.Pop<s64>(); |
| 39 | 39 | ||
| 40 | NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); | 40 | LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); |
| 41 | 41 | ||
| 42 | // Error checking | 42 | // Error checking |
| 43 | if (length < 0) { | 43 | if (length < 0) { |
| @@ -89,7 +89,7 @@ private: | |||
| 89 | const s64 offset = rp.Pop<s64>(); | 89 | const s64 offset = rp.Pop<s64>(); |
| 90 | const s64 length = rp.Pop<s64>(); | 90 | const s64 length = rp.Pop<s64>(); |
| 91 | 91 | ||
| 92 | NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); | 92 | LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); |
| 93 | 93 | ||
| 94 | // Error checking | 94 | // Error checking |
| 95 | if (length < 0) { | 95 | if (length < 0) { |
| @@ -126,7 +126,7 @@ private: | |||
| 126 | const s64 offset = rp.Pop<s64>(); | 126 | const s64 offset = rp.Pop<s64>(); |
| 127 | const s64 length = rp.Pop<s64>(); | 127 | const s64 length = rp.Pop<s64>(); |
| 128 | 128 | ||
| 129 | NGLOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); | 129 | LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); |
| 130 | 130 | ||
| 131 | // Error checking | 131 | // Error checking |
| 132 | if (length < 0) { | 132 | if (length < 0) { |
| @@ -154,7 +154,7 @@ private: | |||
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | void Flush(Kernel::HLERequestContext& ctx) { | 156 | void Flush(Kernel::HLERequestContext& ctx) { |
| 157 | NGLOG_DEBUG(Service_FS, "called"); | 157 | LOG_DEBUG(Service_FS, "called"); |
| 158 | backend->Flush(); | 158 | backend->Flush(); |
| 159 | 159 | ||
| 160 | IPC::ResponseBuilder rb{ctx, 2}; | 160 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -165,7 +165,7 @@ private: | |||
| 165 | IPC::RequestParser rp{ctx}; | 165 | IPC::RequestParser rp{ctx}; |
| 166 | const u64 size = rp.Pop<u64>(); | 166 | const u64 size = rp.Pop<u64>(); |
| 167 | backend->SetSize(size); | 167 | backend->SetSize(size); |
| 168 | NGLOG_DEBUG(Service_FS, "called, size={}", size); | 168 | LOG_DEBUG(Service_FS, "called, size={}", size); |
| 169 | 169 | ||
| 170 | IPC::ResponseBuilder rb{ctx, 2}; | 170 | IPC::ResponseBuilder rb{ctx, 2}; |
| 171 | rb.Push(RESULT_SUCCESS); | 171 | rb.Push(RESULT_SUCCESS); |
| @@ -173,7 +173,7 @@ private: | |||
| 173 | 173 | ||
| 174 | void GetSize(Kernel::HLERequestContext& ctx) { | 174 | void GetSize(Kernel::HLERequestContext& ctx) { |
| 175 | const u64 size = backend->GetSize(); | 175 | const u64 size = backend->GetSize(); |
| 176 | NGLOG_DEBUG(Service_FS, "called, size={}", size); | 176 | LOG_DEBUG(Service_FS, "called, size={}", size); |
| 177 | 177 | ||
| 178 | IPC::ResponseBuilder rb{ctx, 4}; | 178 | IPC::ResponseBuilder rb{ctx, 4}; |
| 179 | rb.Push(RESULT_SUCCESS); | 179 | rb.Push(RESULT_SUCCESS); |
| @@ -199,7 +199,7 @@ private: | |||
| 199 | IPC::RequestParser rp{ctx}; | 199 | IPC::RequestParser rp{ctx}; |
| 200 | const u64 unk = rp.Pop<u64>(); | 200 | const u64 unk = rp.Pop<u64>(); |
| 201 | 201 | ||
| 202 | NGLOG_DEBUG(Service_FS, "called, unk=0x{:X}", unk); | 202 | LOG_DEBUG(Service_FS, "called, unk=0x{:X}", unk); |
| 203 | 203 | ||
| 204 | // Calculate how many entries we can fit in the output buffer | 204 | // Calculate how many entries we can fit in the output buffer |
| 205 | u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); | 205 | u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); |
| @@ -221,7 +221,7 @@ private: | |||
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | void GetEntryCount(Kernel::HLERequestContext& ctx) { | 223 | void GetEntryCount(Kernel::HLERequestContext& ctx) { |
| 224 | NGLOG_DEBUG(Service_FS, "called"); | 224 | LOG_DEBUG(Service_FS, "called"); |
| 225 | 225 | ||
| 226 | u64 count = backend->GetEntryCount(); | 226 | u64 count = backend->GetEntryCount(); |
| 227 | 227 | ||
| @@ -265,7 +265,7 @@ public: | |||
| 265 | u64 mode = rp.Pop<u64>(); | 265 | u64 mode = rp.Pop<u64>(); |
| 266 | u32 size = rp.Pop<u32>(); | 266 | u32 size = rp.Pop<u32>(); |
| 267 | 267 | ||
| 268 | NGLOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size); | 268 | LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size); |
| 269 | 269 | ||
| 270 | IPC::ResponseBuilder rb{ctx, 2}; | 270 | IPC::ResponseBuilder rb{ctx, 2}; |
| 271 | rb.Push(backend->CreateFile(name, size)); | 271 | rb.Push(backend->CreateFile(name, size)); |
| @@ -277,7 +277,7 @@ public: | |||
| 277 | auto file_buffer = ctx.ReadBuffer(); | 277 | auto file_buffer = ctx.ReadBuffer(); |
| 278 | std::string name = Common::StringFromBuffer(file_buffer); | 278 | std::string name = Common::StringFromBuffer(file_buffer); |
| 279 | 279 | ||
| 280 | NGLOG_DEBUG(Service_FS, "called file {}", name); | 280 | LOG_DEBUG(Service_FS, "called file {}", name); |
| 281 | 281 | ||
| 282 | IPC::ResponseBuilder rb{ctx, 2}; | 282 | IPC::ResponseBuilder rb{ctx, 2}; |
| 283 | rb.Push(backend->DeleteFile(name)); | 283 | rb.Push(backend->DeleteFile(name)); |
| @@ -289,7 +289,7 @@ public: | |||
| 289 | auto file_buffer = ctx.ReadBuffer(); | 289 | auto file_buffer = ctx.ReadBuffer(); |
| 290 | std::string name = Common::StringFromBuffer(file_buffer); | 290 | std::string name = Common::StringFromBuffer(file_buffer); |
| 291 | 291 | ||
| 292 | NGLOG_DEBUG(Service_FS, "called directory {}", name); | 292 | LOG_DEBUG(Service_FS, "called directory {}", name); |
| 293 | 293 | ||
| 294 | IPC::ResponseBuilder rb{ctx, 2}; | 294 | IPC::ResponseBuilder rb{ctx, 2}; |
| 295 | rb.Push(backend->CreateDirectory(name)); | 295 | rb.Push(backend->CreateDirectory(name)); |
| @@ -307,7 +307,7 @@ public: | |||
| 307 | Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size()); | 307 | Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size()); |
| 308 | std::string dst_name = Common::StringFromBuffer(buffer); | 308 | std::string dst_name = Common::StringFromBuffer(buffer); |
| 309 | 309 | ||
| 310 | NGLOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name); | 310 | LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name); |
| 311 | 311 | ||
| 312 | IPC::ResponseBuilder rb{ctx, 2}; | 312 | IPC::ResponseBuilder rb{ctx, 2}; |
| 313 | rb.Push(backend->RenameFile(src_name, dst_name)); | 313 | rb.Push(backend->RenameFile(src_name, dst_name)); |
| @@ -321,7 +321,7 @@ public: | |||
| 321 | 321 | ||
| 322 | auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); | 322 | auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); |
| 323 | 323 | ||
| 324 | NGLOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode)); | 324 | LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode)); |
| 325 | 325 | ||
| 326 | auto result = backend->OpenFile(name, mode); | 326 | auto result = backend->OpenFile(name, mode); |
| 327 | if (result.Failed()) { | 327 | if (result.Failed()) { |
| @@ -346,7 +346,7 @@ public: | |||
| 346 | // TODO(Subv): Implement this filter. | 346 | // TODO(Subv): Implement this filter. |
| 347 | u32 filter_flags = rp.Pop<u32>(); | 347 | u32 filter_flags = rp.Pop<u32>(); |
| 348 | 348 | ||
| 349 | NGLOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags); | 349 | LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags); |
| 350 | 350 | ||
| 351 | auto result = backend->OpenDirectory(name); | 351 | auto result = backend->OpenDirectory(name); |
| 352 | if (result.Failed()) { | 352 | if (result.Failed()) { |
| @@ -368,7 +368,7 @@ public: | |||
| 368 | auto file_buffer = ctx.ReadBuffer(); | 368 | auto file_buffer = ctx.ReadBuffer(); |
| 369 | std::string name = Common::StringFromBuffer(file_buffer); | 369 | std::string name = Common::StringFromBuffer(file_buffer); |
| 370 | 370 | ||
| 371 | NGLOG_DEBUG(Service_FS, "called file {}", name); | 371 | LOG_DEBUG(Service_FS, "called file {}", name); |
| 372 | 372 | ||
| 373 | auto result = backend->GetEntryType(name); | 373 | auto result = backend->GetEntryType(name); |
| 374 | if (result.Failed()) { | 374 | if (result.Failed()) { |
| @@ -383,7 +383,7 @@ public: | |||
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | void Commit(Kernel::HLERequestContext& ctx) { | 385 | void Commit(Kernel::HLERequestContext& ctx) { |
| 386 | NGLOG_WARNING(Service_FS, "(STUBBED) called"); | 386 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 387 | 387 | ||
| 388 | IPC::ResponseBuilder rb{ctx, 2}; | 388 | IPC::ResponseBuilder rb{ctx, 2}; |
| 389 | rb.Push(RESULT_SUCCESS); | 389 | rb.Push(RESULT_SUCCESS); |
| @@ -499,14 +499,14 @@ void FSP_SRV::TryLoadRomFS() { | |||
| 499 | } | 499 | } |
| 500 | 500 | ||
| 501 | void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) { | 501 | void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) { |
| 502 | NGLOG_WARNING(Service_FS, "(STUBBED) called"); | 502 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 503 | 503 | ||
| 504 | IPC::ResponseBuilder rb{ctx, 2}; | 504 | IPC::ResponseBuilder rb{ctx, 2}; |
| 505 | rb.Push(RESULT_SUCCESS); | 505 | rb.Push(RESULT_SUCCESS); |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { | 508 | void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { |
| 509 | NGLOG_DEBUG(Service_FS, "called"); | 509 | LOG_DEBUG(Service_FS, "called"); |
| 510 | 510 | ||
| 511 | FileSys::Path unused; | 511 | FileSys::Path unused; |
| 512 | auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap(); | 512 | auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap(); |
| @@ -523,14 +523,14 @@ void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { | |||
| 523 | auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); | 523 | auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); |
| 524 | u128 uid = rp.PopRaw<u128>(); | 524 | u128 uid = rp.PopRaw<u128>(); |
| 525 | 525 | ||
| 526 | NGLOG_WARNING(Service_FS, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); | 526 | LOG_WARNING(Service_FS, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); |
| 527 | 527 | ||
| 528 | IPC::ResponseBuilder rb{ctx, 2}; | 528 | IPC::ResponseBuilder rb{ctx, 2}; |
| 529 | rb.Push(RESULT_SUCCESS); | 529 | rb.Push(RESULT_SUCCESS); |
| 530 | } | 530 | } |
| 531 | 531 | ||
| 532 | void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { | 532 | void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { |
| 533 | NGLOG_WARNING(Service_FS, "(STUBBED) called"); | 533 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 534 | 534 | ||
| 535 | // TODO(Subv): Read the input parameters and mount the requested savedata instead of always | 535 | // TODO(Subv): Read the input parameters and mount the requested savedata instead of always |
| 536 | // mounting the current process' savedata. | 536 | // mounting the current process' savedata. |
| @@ -549,7 +549,7 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { | |||
| 549 | } | 549 | } |
| 550 | 550 | ||
| 551 | void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { | 551 | void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { |
| 552 | NGLOG_WARNING(Service_FS, "(STUBBED) called"); | 552 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 553 | 553 | ||
| 554 | IPC::ResponseBuilder rb{ctx, 3}; | 554 | IPC::ResponseBuilder rb{ctx, 3}; |
| 555 | rb.Push(RESULT_SUCCESS); | 555 | rb.Push(RESULT_SUCCESS); |
| @@ -557,12 +557,12 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { | |||
| 557 | } | 557 | } |
| 558 | 558 | ||
| 559 | void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { | 559 | void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { |
| 560 | NGLOG_DEBUG(Service_FS, "called"); | 560 | LOG_DEBUG(Service_FS, "called"); |
| 561 | 561 | ||
| 562 | TryLoadRomFS(); | 562 | TryLoadRomFS(); |
| 563 | if (!romfs) { | 563 | if (!romfs) { |
| 564 | // TODO (bunnei): Find the right error code to use here | 564 | // TODO (bunnei): Find the right error code to use here |
| 565 | NGLOG_CRITICAL(Service_FS, "no file system interface available!"); | 565 | LOG_CRITICAL(Service_FS, "no file system interface available!"); |
| 566 | IPC::ResponseBuilder rb{ctx, 2}; | 566 | IPC::ResponseBuilder rb{ctx, 2}; |
| 567 | rb.Push(ResultCode(-1)); | 567 | rb.Push(ResultCode(-1)); |
| 568 | return; | 568 | return; |
| @@ -571,7 +571,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { | |||
| 571 | // Attempt to open a StorageBackend interface to the RomFS | 571 | // Attempt to open a StorageBackend interface to the RomFS |
| 572 | auto storage = romfs->OpenFile({}, {}); | 572 | auto storage = romfs->OpenFile({}, {}); |
| 573 | if (storage.Failed()) { | 573 | if (storage.Failed()) { |
| 574 | NGLOG_CRITICAL(Service_FS, "no storage interface available!"); | 574 | LOG_CRITICAL(Service_FS, "no storage interface available!"); |
| 575 | IPC::ResponseBuilder rb{ctx, 2}; | 575 | IPC::ResponseBuilder rb{ctx, 2}; |
| 576 | rb.Push(storage.Code()); | 576 | rb.Push(storage.Code()); |
| 577 | return; | 577 | return; |
| @@ -583,7 +583,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { | |||
| 583 | } | 583 | } |
| 584 | 584 | ||
| 585 | void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { | 585 | void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { |
| 586 | NGLOG_WARNING(Service_FS, "(STUBBED) called, using OpenDataStorageByCurrentProcess"); | 586 | LOG_WARNING(Service_FS, "(STUBBED) called, using OpenDataStorageByCurrentProcess"); |
| 587 | OpenDataStorageByCurrentProcess(ctx); | 587 | OpenDataStorageByCurrentProcess(ctx); |
| 588 | } | 588 | } |
| 589 | 589 | ||
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 94d9fbf25..c98a46e05 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -13,7 +13,7 @@ namespace Service::Friend { | |||
| 13 | void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { | 13 | void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { |
| 14 | IPC::ResponseBuilder rb{ctx, 2}; | 14 | IPC::ResponseBuilder rb{ctx, 2}; |
| 15 | rb.Push(RESULT_SUCCESS); | 15 | rb.Push(RESULT_SUCCESS); |
| 16 | NGLOG_WARNING(Service_Friend, "(STUBBED) called"); | 16 | LOG_WARNING(Service_Friend, "(STUBBED) called"); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 19 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 00c5308ba..b0f4a384e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -53,7 +53,7 @@ private: | |||
| 53 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 53 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 54 | rb.Push(RESULT_SUCCESS); | 54 | rb.Push(RESULT_SUCCESS); |
| 55 | rb.PushCopyObjects(shared_mem); | 55 | rb.PushCopyObjects(shared_mem); |
| 56 | NGLOG_DEBUG(Service_HID, "called"); | 56 | LOG_DEBUG(Service_HID, "called"); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | void LoadInputDevices() { | 59 | void LoadInputDevices() { |
| @@ -75,7 +75,7 @@ private: | |||
| 75 | 75 | ||
| 76 | // Set up controllers as neon red+blue Joy-Con attached to console | 76 | // Set up controllers as neon red+blue Joy-Con attached to console |
| 77 | ControllerHeader& controller_header = mem.controllers[Controller_Handheld].header; | 77 | ControllerHeader& controller_header = mem.controllers[Controller_Handheld].header; |
| 78 | controller_header.type = ControllerType_Handheld | ControllerType_JoyconPair; | 78 | controller_header.type = ControllerType_Handheld; |
| 79 | controller_header.single_colors_descriptor = ColorDesc_ColorsNonexistent; | 79 | controller_header.single_colors_descriptor = ColorDesc_ColorsNonexistent; |
| 80 | controller_header.right_color_body = JOYCON_BODY_NEON_RED; | 80 | controller_header.right_color_body = JOYCON_BODY_NEON_RED; |
| 81 | controller_header.right_color_buttons = JOYCON_BUTTONS_NEON_RED; | 81 | controller_header.right_color_buttons = JOYCON_BUTTONS_NEON_RED; |
| @@ -90,19 +90,22 @@ private: | |||
| 90 | 90 | ||
| 91 | // HID shared memory stores the state of the past 17 samples in a circlular buffer, | 91 | // HID shared memory stores the state of the past 17 samples in a circlular buffer, |
| 92 | // each with a timestamp in number of samples since boot. | 92 | // each with a timestamp in number of samples since boot. |
| 93 | const ControllerInputEntry& last_entry = layout.entries[layout.header.latest_entry]; | ||
| 94 | |||
| 93 | layout.header.timestamp_ticks = CoreTiming::GetTicks(); | 95 | layout.header.timestamp_ticks = CoreTiming::GetTicks(); |
| 94 | layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES; | 96 | layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES; |
| 95 | 97 | ||
| 96 | ControllerInputEntry& entry = layout.entries[layout.header.latest_entry]; | 98 | ControllerInputEntry& entry = layout.entries[layout.header.latest_entry]; |
| 97 | entry.connection_state = ConnectionState_Connected | ConnectionState_Wired; | 99 | entry.timestamp = last_entry.timestamp + 1; |
| 98 | entry.timestamp++; | ||
| 99 | // TODO(shinyquagsire23): Is this always identical to timestamp? | 100 | // TODO(shinyquagsire23): Is this always identical to timestamp? |
| 100 | entry.timestamp_2++; | 101 | entry.timestamp_2 = entry.timestamp; |
| 101 | 102 | ||
| 102 | // TODO(shinyquagsire23): More than just handheld input | 103 | // TODO(shinyquagsire23): More than just handheld input |
| 103 | if (controller != Controller_Handheld) | 104 | if (controller != Controller_Handheld) |
| 104 | continue; | 105 | continue; |
| 105 | 106 | ||
| 107 | entry.connection_state = ConnectionState_Connected | ConnectionState_Wired; | ||
| 108 | |||
| 106 | // TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future? | 109 | // TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future? |
| 107 | // For now everything is just the default handheld layout, but split Joy-Con will | 110 | // For now everything is just the default handheld layout, but split Joy-Con will |
| 108 | // rotate the face buttons and directions for certain layouts. | 111 | // rotate the face buttons and directions for certain layouts. |
| @@ -262,7 +265,7 @@ private: | |||
| 262 | void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { | 265 | void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { |
| 263 | IPC::ResponseBuilder rb{ctx, 2}; | 266 | IPC::ResponseBuilder rb{ctx, 2}; |
| 264 | rb.Push(RESULT_SUCCESS); | 267 | rb.Push(RESULT_SUCCESS); |
| 265 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 268 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 266 | } | 269 | } |
| 267 | }; | 270 | }; |
| 268 | 271 | ||
| @@ -394,144 +397,144 @@ private: | |||
| 394 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 397 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 395 | rb.Push(RESULT_SUCCESS); | 398 | rb.Push(RESULT_SUCCESS); |
| 396 | rb.PushIpcInterface<IAppletResource>(applet_resource); | 399 | rb.PushIpcInterface<IAppletResource>(applet_resource); |
| 397 | NGLOG_DEBUG(Service_HID, "called"); | 400 | LOG_DEBUG(Service_HID, "called"); |
| 398 | } | 401 | } |
| 399 | 402 | ||
| 400 | void ActivateDebugPad(Kernel::HLERequestContext& ctx) { | 403 | void ActivateDebugPad(Kernel::HLERequestContext& ctx) { |
| 401 | IPC::ResponseBuilder rb{ctx, 2}; | 404 | IPC::ResponseBuilder rb{ctx, 2}; |
| 402 | rb.Push(RESULT_SUCCESS); | 405 | rb.Push(RESULT_SUCCESS); |
| 403 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 406 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 404 | } | 407 | } |
| 405 | 408 | ||
| 406 | void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { | 409 | void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { |
| 407 | IPC::ResponseBuilder rb{ctx, 2}; | 410 | IPC::ResponseBuilder rb{ctx, 2}; |
| 408 | rb.Push(RESULT_SUCCESS); | 411 | rb.Push(RESULT_SUCCESS); |
| 409 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 412 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 410 | } | 413 | } |
| 411 | 414 | ||
| 412 | void ActivateMouse(Kernel::HLERequestContext& ctx) { | 415 | void ActivateMouse(Kernel::HLERequestContext& ctx) { |
| 413 | IPC::ResponseBuilder rb{ctx, 2}; | 416 | IPC::ResponseBuilder rb{ctx, 2}; |
| 414 | rb.Push(RESULT_SUCCESS); | 417 | rb.Push(RESULT_SUCCESS); |
| 415 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 418 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 416 | } | 419 | } |
| 417 | 420 | ||
| 418 | void ActivateKeyboard(Kernel::HLERequestContext& ctx) { | 421 | void ActivateKeyboard(Kernel::HLERequestContext& ctx) { |
| 419 | IPC::ResponseBuilder rb{ctx, 2}; | 422 | IPC::ResponseBuilder rb{ctx, 2}; |
| 420 | rb.Push(RESULT_SUCCESS); | 423 | rb.Push(RESULT_SUCCESS); |
| 421 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 424 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 422 | } | 425 | } |
| 423 | 426 | ||
| 424 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { | 427 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 425 | IPC::ResponseBuilder rb{ctx, 2}; | 428 | IPC::ResponseBuilder rb{ctx, 2}; |
| 426 | rb.Push(RESULT_SUCCESS); | 429 | rb.Push(RESULT_SUCCESS); |
| 427 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 430 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 428 | } | 431 | } |
| 429 | 432 | ||
| 430 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 433 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 431 | IPC::ResponseBuilder rb{ctx, 2}; | 434 | IPC::ResponseBuilder rb{ctx, 2}; |
| 432 | rb.Push(RESULT_SUCCESS); | 435 | rb.Push(RESULT_SUCCESS); |
| 433 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 436 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 434 | } | 437 | } |
| 435 | 438 | ||
| 436 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 439 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 437 | IPC::ResponseBuilder rb{ctx, 2}; | 440 | IPC::ResponseBuilder rb{ctx, 2}; |
| 438 | rb.Push(RESULT_SUCCESS); | 441 | rb.Push(RESULT_SUCCESS); |
| 439 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 442 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 440 | } | 443 | } |
| 441 | 444 | ||
| 442 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 445 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 443 | IPC::ResponseBuilder rb{ctx, 3}; | 446 | IPC::ResponseBuilder rb{ctx, 3}; |
| 444 | rb.Push(RESULT_SUCCESS); | 447 | rb.Push(RESULT_SUCCESS); |
| 445 | rb.Push<u32>(0); | 448 | rb.Push<u32>(0); |
| 446 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 449 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 447 | } | 450 | } |
| 448 | 451 | ||
| 449 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { | 452 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { |
| 450 | IPC::ResponseBuilder rb{ctx, 2}; | 453 | IPC::ResponseBuilder rb{ctx, 2}; |
| 451 | rb.Push(RESULT_SUCCESS); | 454 | rb.Push(RESULT_SUCCESS); |
| 452 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 455 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 453 | } | 456 | } |
| 454 | 457 | ||
| 455 | void ActivateNpad(Kernel::HLERequestContext& ctx) { | 458 | void ActivateNpad(Kernel::HLERequestContext& ctx) { |
| 456 | IPC::ResponseBuilder rb{ctx, 2}; | 459 | IPC::ResponseBuilder rb{ctx, 2}; |
| 457 | rb.Push(RESULT_SUCCESS); | 460 | rb.Push(RESULT_SUCCESS); |
| 458 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 461 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 459 | } | 462 | } |
| 460 | 463 | ||
| 461 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | 464 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { |
| 462 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 465 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 463 | rb.Push(RESULT_SUCCESS); | 466 | rb.Push(RESULT_SUCCESS); |
| 464 | rb.PushCopyObjects(event); | 467 | rb.PushCopyObjects(event); |
| 465 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 468 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 466 | } | 469 | } |
| 467 | 470 | ||
| 468 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { | 471 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { |
| 469 | IPC::ResponseBuilder rb{ctx, 2}; | 472 | IPC::ResponseBuilder rb{ctx, 2}; |
| 470 | rb.Push(RESULT_SUCCESS); | 473 | rb.Push(RESULT_SUCCESS); |
| 471 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 474 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 472 | } | 475 | } |
| 473 | 476 | ||
| 474 | void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | 477 | void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { |
| 475 | IPC::ResponseBuilder rb{ctx, 2}; | 478 | IPC::ResponseBuilder rb{ctx, 2}; |
| 476 | rb.Push(RESULT_SUCCESS); | 479 | rb.Push(RESULT_SUCCESS); |
| 477 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 480 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 478 | } | 481 | } |
| 479 | 482 | ||
| 480 | void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | 483 | void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { |
| 481 | IPC::ResponseBuilder rb{ctx, 3}; | 484 | IPC::ResponseBuilder rb{ctx, 3}; |
| 482 | rb.Push(RESULT_SUCCESS); | 485 | rb.Push(RESULT_SUCCESS); |
| 483 | rb.Push(joy_hold_type); | 486 | rb.Push(joy_hold_type); |
| 484 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 487 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 485 | } | 488 | } |
| 486 | 489 | ||
| 487 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { | 490 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { |
| 488 | IPC::ResponseBuilder rb{ctx, 2}; | 491 | IPC::ResponseBuilder rb{ctx, 2}; |
| 489 | rb.Push(RESULT_SUCCESS); | 492 | rb.Push(RESULT_SUCCESS); |
| 490 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 493 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 491 | } | 494 | } |
| 492 | 495 | ||
| 493 | void SendVibrationValue(Kernel::HLERequestContext& ctx) { | 496 | void SendVibrationValue(Kernel::HLERequestContext& ctx) { |
| 494 | IPC::ResponseBuilder rb{ctx, 2}; | 497 | IPC::ResponseBuilder rb{ctx, 2}; |
| 495 | rb.Push(RESULT_SUCCESS); | 498 | rb.Push(RESULT_SUCCESS); |
| 496 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 499 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 497 | } | 500 | } |
| 498 | 501 | ||
| 499 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { | 502 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { |
| 500 | IPC::ResponseBuilder rb{ctx, 2}; | 503 | IPC::ResponseBuilder rb{ctx, 2}; |
| 501 | rb.Push(RESULT_SUCCESS); | 504 | rb.Push(RESULT_SUCCESS); |
| 502 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 505 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 503 | } | 506 | } |
| 504 | 507 | ||
| 505 | void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | 508 | void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { |
| 506 | IPC::ResponseBuilder rb{ctx, 2}; | 509 | IPC::ResponseBuilder rb{ctx, 2}; |
| 507 | rb.Push(RESULT_SUCCESS); | 510 | rb.Push(RESULT_SUCCESS); |
| 508 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 511 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 509 | } | 512 | } |
| 510 | 513 | ||
| 511 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { | 514 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { |
| 512 | IPC::ResponseBuilder rb{ctx, 2}; | 515 | IPC::ResponseBuilder rb{ctx, 2}; |
| 513 | rb.Push(RESULT_SUCCESS); | 516 | rb.Push(RESULT_SUCCESS); |
| 514 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 517 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 515 | } | 518 | } |
| 516 | 519 | ||
| 517 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | 520 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { |
| 518 | IPC::ResponseBuilder rb{ctx, 4}; | 521 | IPC::ResponseBuilder rb{ctx, 4}; |
| 519 | rb.Push(RESULT_SUCCESS); | 522 | rb.Push(RESULT_SUCCESS); |
| 520 | rb.Push<u64>(0); | 523 | rb.Push<u64>(0); |
| 521 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 524 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 522 | } | 525 | } |
| 523 | 526 | ||
| 524 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { | 527 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { |
| 525 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 528 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 526 | rb.Push(RESULT_SUCCESS); | 529 | rb.Push(RESULT_SUCCESS); |
| 527 | rb.PushIpcInterface<IActiveVibrationDeviceList>(); | 530 | rb.PushIpcInterface<IActiveVibrationDeviceList>(); |
| 528 | NGLOG_DEBUG(Service_HID, "called"); | 531 | LOG_DEBUG(Service_HID, "called"); |
| 529 | } | 532 | } |
| 530 | 533 | ||
| 531 | void SendVibrationValues(Kernel::HLERequestContext& ctx) { | 534 | void SendVibrationValues(Kernel::HLERequestContext& ctx) { |
| 532 | IPC::ResponseBuilder rb{ctx, 2}; | 535 | IPC::ResponseBuilder rb{ctx, 2}; |
| 533 | rb.Push(RESULT_SUCCESS); | 536 | rb.Push(RESULT_SUCCESS); |
| 534 | NGLOG_WARNING(Service_HID, "(STUBBED) called"); | 537 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 535 | } | 538 | } |
| 536 | }; | 539 | }; |
| 537 | 540 | ||
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 15eee8f01..b499308d6 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -12,7 +12,7 @@ namespace Service::HID { | |||
| 12 | // Begin enums and output structs | 12 | // Begin enums and output structs |
| 13 | 13 | ||
| 14 | constexpr u32 HID_NUM_ENTRIES = 17; | 14 | constexpr u32 HID_NUM_ENTRIES = 17; |
| 15 | constexpr u32 HID_NUM_LAYOUTS = 2; | 15 | constexpr u32 HID_NUM_LAYOUTS = 7; |
| 16 | constexpr s32 HID_JOYSTICK_MAX = 0x8000; | 16 | constexpr s32 HID_JOYSTICK_MAX = 0x8000; |
| 17 | constexpr s32 HID_JOYSTICK_MIN = -0x8000; | 17 | constexpr s32 HID_JOYSTICK_MIN = -0x8000; |
| 18 | 18 | ||
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 46194643e..e85a8bdb9 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp | |||
| @@ -141,19 +141,19 @@ private: | |||
| 141 | if (header.IsTailLog()) { | 141 | if (header.IsTailLog()) { |
| 142 | switch (header.severity) { | 142 | switch (header.severity) { |
| 143 | case MessageHeader::Severity::Trace: | 143 | case MessageHeader::Severity::Trace: |
| 144 | NGLOG_TRACE(Debug_Emulated, "{}", log_stream.str()); | 144 | LOG_TRACE(Debug_Emulated, "{}", log_stream.str()); |
| 145 | break; | 145 | break; |
| 146 | case MessageHeader::Severity::Info: | 146 | case MessageHeader::Severity::Info: |
| 147 | NGLOG_INFO(Debug_Emulated, "{}", log_stream.str()); | 147 | LOG_INFO(Debug_Emulated, "{}", log_stream.str()); |
| 148 | break; | 148 | break; |
| 149 | case MessageHeader::Severity::Warning: | 149 | case MessageHeader::Severity::Warning: |
| 150 | NGLOG_WARNING(Debug_Emulated, "{}", log_stream.str()); | 150 | LOG_WARNING(Debug_Emulated, "{}", log_stream.str()); |
| 151 | break; | 151 | break; |
| 152 | case MessageHeader::Severity::Error: | 152 | case MessageHeader::Severity::Error: |
| 153 | NGLOG_ERROR(Debug_Emulated, "{}", log_stream.str()); | 153 | LOG_ERROR(Debug_Emulated, "{}", log_stream.str()); |
| 154 | break; | 154 | break; |
| 155 | case MessageHeader::Severity::Critical: | 155 | case MessageHeader::Severity::Critical: |
| 156 | NGLOG_CRITICAL(Debug_Emulated, "{}", log_stream.str()); | 156 | LOG_CRITICAL(Debug_Emulated, "{}", log_stream.str()); |
| 157 | break; | 157 | break; |
| 158 | } | 158 | } |
| 159 | } | 159 | } |
| @@ -178,7 +178,7 @@ void LM::Initialize(Kernel::HLERequestContext& ctx) { | |||
| 178 | rb.Push(RESULT_SUCCESS); | 178 | rb.Push(RESULT_SUCCESS); |
| 179 | rb.PushIpcInterface<Logger>(); | 179 | rb.PushIpcInterface<Logger>(); |
| 180 | 180 | ||
| 181 | NGLOG_DEBUG(Service_LM, "called"); | 181 | LOG_DEBUG(Service_LM, "called"); |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | LM::LM() : ServiceFramework("lm") { | 184 | LM::LM() : ServiceFramework("lm") { |
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp index b3a85b818..08f45b78a 100644 --- a/src/core/hle/service/mm/mm_u.cpp +++ b/src/core/hle/service/mm/mm_u.cpp | |||
| @@ -14,7 +14,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) { | |||
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | void MM_U::Initialize(Kernel::HLERequestContext& ctx) { | 16 | void MM_U::Initialize(Kernel::HLERequestContext& ctx) { |
| 17 | NGLOG_WARNING(Service_MM, "(STUBBED) called"); | 17 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 18 | IPC::ResponseBuilder rb{ctx, 2}; | 18 | IPC::ResponseBuilder rb{ctx, 2}; |
| 19 | rb.Push(RESULT_SUCCESS); | 19 | rb.Push(RESULT_SUCCESS); |
| 20 | } | 20 | } |
| @@ -25,13 +25,13 @@ void MM_U::SetAndWait(Kernel::HLERequestContext& ctx) { | |||
| 25 | max = rp.Pop<u32>(); | 25 | max = rp.Pop<u32>(); |
| 26 | current = min; | 26 | current = min; |
| 27 | 27 | ||
| 28 | NGLOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); | 28 | LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); |
| 29 | IPC::ResponseBuilder rb{ctx, 2}; | 29 | IPC::ResponseBuilder rb{ctx, 2}; |
| 30 | rb.Push(RESULT_SUCCESS); | 30 | rb.Push(RESULT_SUCCESS); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | void MM_U::Get(Kernel::HLERequestContext& ctx) { | 33 | void MM_U::Get(Kernel::HLERequestContext& ctx) { |
| 34 | NGLOG_WARNING(Service_MM, "(STUBBED) called"); | 34 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 35 | IPC::ResponseBuilder rb{ctx, 3}; | 35 | IPC::ResponseBuilder rb{ctx, 3}; |
| 36 | rb.Push(RESULT_SUCCESS); | 36 | rb.Push(RESULT_SUCCESS); |
| 37 | rb.Push(current); | 37 | rb.Push(current); |
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 2a9f84037..56b05e9e8 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -64,7 +64,7 @@ private: | |||
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | void Initialize(Kernel::HLERequestContext& ctx) { | 66 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 67 | NGLOG_WARNING(Service_NFP, "(STUBBED) called"); | 67 | LOG_WARNING(Service_NFP, "(STUBBED) called"); |
| 68 | 68 | ||
| 69 | state = State::Initialized; | 69 | state = State::Initialized; |
| 70 | 70 | ||
| @@ -78,7 +78,7 @@ private: | |||
| 78 | 78 | ||
| 79 | ctx.WriteBuffer(&device_handle, sizeof(device_handle)); | 79 | ctx.WriteBuffer(&device_handle, sizeof(device_handle)); |
| 80 | 80 | ||
| 81 | NGLOG_WARNING(Service_NFP, "(STUBBED) called, array_size={}", array_size); | 81 | LOG_WARNING(Service_NFP, "(STUBBED) called, array_size={}", array_size); |
| 82 | 82 | ||
| 83 | IPC::ResponseBuilder rb{ctx, 3}; | 83 | IPC::ResponseBuilder rb{ctx, 3}; |
| 84 | rb.Push(RESULT_SUCCESS); | 84 | rb.Push(RESULT_SUCCESS); |
| @@ -88,7 +88,7 @@ private: | |||
| 88 | void AttachActivateEvent(Kernel::HLERequestContext& ctx) { | 88 | void AttachActivateEvent(Kernel::HLERequestContext& ctx) { |
| 89 | IPC::RequestParser rp{ctx}; | 89 | IPC::RequestParser rp{ctx}; |
| 90 | const u64 dev_handle = rp.Pop<u64>(); | 90 | const u64 dev_handle = rp.Pop<u64>(); |
| 91 | NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); | 91 | LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); |
| 92 | 92 | ||
| 93 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 93 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 94 | rb.Push(RESULT_SUCCESS); | 94 | rb.Push(RESULT_SUCCESS); |
| @@ -98,7 +98,7 @@ private: | |||
| 98 | void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { | 98 | void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { |
| 99 | IPC::RequestParser rp{ctx}; | 99 | IPC::RequestParser rp{ctx}; |
| 100 | const u64 dev_handle = rp.Pop<u64>(); | 100 | const u64 dev_handle = rp.Pop<u64>(); |
| 101 | NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); | 101 | LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); |
| 102 | 102 | ||
| 103 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 103 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 104 | rb.Push(RESULT_SUCCESS); | 104 | rb.Push(RESULT_SUCCESS); |
| @@ -106,14 +106,14 @@ private: | |||
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | void GetState(Kernel::HLERequestContext& ctx) { | 108 | void GetState(Kernel::HLERequestContext& ctx) { |
| 109 | NGLOG_WARNING(Service_NFP, "(STUBBED) called"); | 109 | LOG_WARNING(Service_NFP, "(STUBBED) called"); |
| 110 | IPC::ResponseBuilder rb{ctx, 3}; | 110 | IPC::ResponseBuilder rb{ctx, 3}; |
| 111 | rb.Push(RESULT_SUCCESS); | 111 | rb.Push(RESULT_SUCCESS); |
| 112 | rb.Push<u32>(static_cast<u32>(state)); | 112 | rb.Push<u32>(static_cast<u32>(state)); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | void GetDeviceState(Kernel::HLERequestContext& ctx) { | 115 | void GetDeviceState(Kernel::HLERequestContext& ctx) { |
| 116 | NGLOG_WARNING(Service_NFP, "(STUBBED) called"); | 116 | LOG_WARNING(Service_NFP, "(STUBBED) called"); |
| 117 | IPC::ResponseBuilder rb{ctx, 3}; | 117 | IPC::ResponseBuilder rb{ctx, 3}; |
| 118 | rb.Push(RESULT_SUCCESS); | 118 | rb.Push(RESULT_SUCCESS); |
| 119 | rb.Push<u32>(static_cast<u32>(device_state)); | 119 | rb.Push<u32>(static_cast<u32>(device_state)); |
| @@ -122,7 +122,7 @@ private: | |||
| 122 | void GetNpadId(Kernel::HLERequestContext& ctx) { | 122 | void GetNpadId(Kernel::HLERequestContext& ctx) { |
| 123 | IPC::RequestParser rp{ctx}; | 123 | IPC::RequestParser rp{ctx}; |
| 124 | const u64 dev_handle = rp.Pop<u64>(); | 124 | const u64 dev_handle = rp.Pop<u64>(); |
| 125 | NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); | 125 | LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); |
| 126 | IPC::ResponseBuilder rb{ctx, 3}; | 126 | IPC::ResponseBuilder rb{ctx, 3}; |
| 127 | rb.Push(RESULT_SUCCESS); | 127 | rb.Push(RESULT_SUCCESS); |
| 128 | rb.Push<u32>(npad_id); | 128 | rb.Push<u32>(npad_id); |
| @@ -131,7 +131,7 @@ private: | |||
| 131 | void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { | 131 | void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { |
| 132 | IPC::RequestParser rp{ctx}; | 132 | IPC::RequestParser rp{ctx}; |
| 133 | const u64 dev_handle = rp.Pop<u64>(); | 133 | const u64 dev_handle = rp.Pop<u64>(); |
| 134 | NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); | 134 | LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); |
| 135 | 135 | ||
| 136 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 136 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 137 | rb.Push(RESULT_SUCCESS); | 137 | rb.Push(RESULT_SUCCESS); |
| @@ -148,7 +148,7 @@ private: | |||
| 148 | }; | 148 | }; |
| 149 | 149 | ||
| 150 | void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | 150 | void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { |
| 151 | NGLOG_DEBUG(Service_NFP, "called"); | 151 | LOG_DEBUG(Service_NFP, "called"); |
| 152 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 152 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 153 | rb.Push(RESULT_SUCCESS); | 153 | rb.Push(RESULT_SUCCESS); |
| 154 | rb.PushIpcInterface<IUser>(); | 154 | rb.PushIpcInterface<IUser>(); |
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 62489c7fe..54a151c26 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp | |||
| @@ -62,33 +62,33 @@ public: | |||
| 62 | 62 | ||
| 63 | private: | 63 | private: |
| 64 | void GetRequestState(Kernel::HLERequestContext& ctx) { | 64 | void GetRequestState(Kernel::HLERequestContext& ctx) { |
| 65 | NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); | 65 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 66 | IPC::ResponseBuilder rb{ctx, 3}; | 66 | IPC::ResponseBuilder rb{ctx, 3}; |
| 67 | rb.Push(RESULT_SUCCESS); | 67 | rb.Push(RESULT_SUCCESS); |
| 68 | rb.Push<u32>(0); | 68 | rb.Push<u32>(0); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | void GetResult(Kernel::HLERequestContext& ctx) { | 71 | void GetResult(Kernel::HLERequestContext& ctx) { |
| 72 | NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); | 72 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 73 | IPC::ResponseBuilder rb{ctx, 2}; | 73 | IPC::ResponseBuilder rb{ctx, 2}; |
| 74 | rb.Push(RESULT_SUCCESS); | 74 | rb.Push(RESULT_SUCCESS); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { | 77 | void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { |
| 78 | NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); | 78 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 79 | IPC::ResponseBuilder rb{ctx, 2, 2}; | 79 | IPC::ResponseBuilder rb{ctx, 2, 2}; |
| 80 | rb.Push(RESULT_SUCCESS); | 80 | rb.Push(RESULT_SUCCESS); |
| 81 | rb.PushCopyObjects(event1, event2); | 81 | rb.PushCopyObjects(event1, event2); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | void Cancel(Kernel::HLERequestContext& ctx) { | 84 | void Cancel(Kernel::HLERequestContext& ctx) { |
| 85 | NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); | 85 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 86 | IPC::ResponseBuilder rb{ctx, 2}; | 86 | IPC::ResponseBuilder rb{ctx, 2}; |
| 87 | rb.Push(RESULT_SUCCESS); | 87 | rb.Push(RESULT_SUCCESS); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) { | 90 | void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) { |
| 91 | NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); | 91 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 92 | IPC::ResponseBuilder rb{ctx, 2}; | 92 | IPC::ResponseBuilder rb{ctx, 2}; |
| 93 | rb.Push(RESULT_SUCCESS); | 93 | rb.Push(RESULT_SUCCESS); |
| 94 | } | 94 | } |
| @@ -114,7 +114,7 @@ public: | |||
| 114 | 114 | ||
| 115 | private: | 115 | private: |
| 116 | void GetClientId(Kernel::HLERequestContext& ctx) { | 116 | void GetClientId(Kernel::HLERequestContext& ctx) { |
| 117 | NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); | 117 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 118 | IPC::ResponseBuilder rb{ctx, 4}; | 118 | IPC::ResponseBuilder rb{ctx, 4}; |
| 119 | rb.Push(RESULT_SUCCESS); | 119 | rb.Push(RESULT_SUCCESS); |
| 120 | rb.Push<u64>(0); | 120 | rb.Push<u64>(0); |
| @@ -125,7 +125,7 @@ private: | |||
| 125 | rb.Push(RESULT_SUCCESS); | 125 | rb.Push(RESULT_SUCCESS); |
| 126 | rb.PushIpcInterface<IScanRequest>(); | 126 | rb.PushIpcInterface<IScanRequest>(); |
| 127 | 127 | ||
| 128 | NGLOG_DEBUG(Service_NIFM, "called"); | 128 | LOG_DEBUG(Service_NIFM, "called"); |
| 129 | } | 129 | } |
| 130 | void CreateRequest(Kernel::HLERequestContext& ctx) { | 130 | void CreateRequest(Kernel::HLERequestContext& ctx) { |
| 131 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 131 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| @@ -133,10 +133,10 @@ private: | |||
| 133 | rb.Push(RESULT_SUCCESS); | 133 | rb.Push(RESULT_SUCCESS); |
| 134 | rb.PushIpcInterface<IRequest>(); | 134 | rb.PushIpcInterface<IRequest>(); |
| 135 | 135 | ||
| 136 | NGLOG_DEBUG(Service_NIFM, "called"); | 136 | LOG_DEBUG(Service_NIFM, "called"); |
| 137 | } | 137 | } |
| 138 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { | 138 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { |
| 139 | NGLOG_WARNING(Service_NIFM, "(STUBBED) called"); | 139 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 140 | IPC::ResponseBuilder rb{ctx, 2}; | 140 | IPC::ResponseBuilder rb{ctx, 2}; |
| 141 | rb.Push(RESULT_SUCCESS); | 141 | rb.Push(RESULT_SUCCESS); |
| 142 | } | 142 | } |
| @@ -146,7 +146,7 @@ private: | |||
| 146 | rb.Push(RESULT_SUCCESS); | 146 | rb.Push(RESULT_SUCCESS); |
| 147 | rb.PushIpcInterface<INetworkProfile>(); | 147 | rb.PushIpcInterface<INetworkProfile>(); |
| 148 | 148 | ||
| 149 | NGLOG_DEBUG(Service_NIFM, "called"); | 149 | LOG_DEBUG(Service_NIFM, "called"); |
| 150 | } | 150 | } |
| 151 | }; | 151 | }; |
| 152 | 152 | ||
| @@ -196,14 +196,14 @@ void Module::Interface::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) | |||
| 196 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 196 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 197 | rb.Push(RESULT_SUCCESS); | 197 | rb.Push(RESULT_SUCCESS); |
| 198 | rb.PushIpcInterface<IGeneralService>(); | 198 | rb.PushIpcInterface<IGeneralService>(); |
| 199 | NGLOG_DEBUG(Service_NIFM, "called"); | 199 | LOG_DEBUG(Service_NIFM, "called"); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | void Module::Interface::CreateGeneralService(Kernel::HLERequestContext& ctx) { | 202 | void Module::Interface::CreateGeneralService(Kernel::HLERequestContext& ctx) { |
| 203 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 203 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 204 | rb.Push(RESULT_SUCCESS); | 204 | rb.Push(RESULT_SUCCESS); |
| 205 | rb.PushIpcInterface<IGeneralService>(); | 205 | rb.PushIpcInterface<IGeneralService>(); |
| 206 | NGLOG_DEBUG(Service_NIFM, "called"); | 206 | LOG_DEBUG(Service_NIFM, "called"); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 209 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 636af9a1e..d6a12ede5 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -52,7 +52,7 @@ PL_U::PL_U() : ServiceFramework("pl:u") { | |||
| 52 | ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE); | 52 | ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE); |
| 53 | file.ReadBytes(shared_font->data(), shared_font->size()); | 53 | file.ReadBytes(shared_font->data(), shared_font->size()); |
| 54 | } else { | 54 | } else { |
| 55 | NGLOG_WARNING(Service_NS, "Unable to load shared font: {}", filepath); | 55 | LOG_WARNING(Service_NS, "Unable to load shared font: {}", filepath); |
| 56 | } | 56 | } |
| 57 | } | 57 | } |
| 58 | 58 | ||
| @@ -60,7 +60,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { | |||
| 60 | IPC::RequestParser rp{ctx}; | 60 | IPC::RequestParser rp{ctx}; |
| 61 | const u32 shared_font_type{rp.Pop<u32>()}; | 61 | const u32 shared_font_type{rp.Pop<u32>()}; |
| 62 | 62 | ||
| 63 | NGLOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); | 63 | LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); |
| 64 | IPC::ResponseBuilder rb{ctx, 2}; | 64 | IPC::ResponseBuilder rb{ctx, 2}; |
| 65 | rb.Push(RESULT_SUCCESS); | 65 | rb.Push(RESULT_SUCCESS); |
| 66 | } | 66 | } |
| @@ -69,7 +69,7 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { | |||
| 69 | IPC::RequestParser rp{ctx}; | 69 | IPC::RequestParser rp{ctx}; |
| 70 | const u32 font_id{rp.Pop<u32>()}; | 70 | const u32 font_id{rp.Pop<u32>()}; |
| 71 | 71 | ||
| 72 | NGLOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 72 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); |
| 73 | IPC::ResponseBuilder rb{ctx, 3}; | 73 | IPC::ResponseBuilder rb{ctx, 3}; |
| 74 | rb.Push(RESULT_SUCCESS); | 74 | rb.Push(RESULT_SUCCESS); |
| 75 | rb.Push<u32>(static_cast<u32>(LoadState::Done)); | 75 | rb.Push<u32>(static_cast<u32>(LoadState::Done)); |
| @@ -79,7 +79,7 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) { | |||
| 79 | IPC::RequestParser rp{ctx}; | 79 | IPC::RequestParser rp{ctx}; |
| 80 | const u32 font_id{rp.Pop<u32>()}; | 80 | const u32 font_id{rp.Pop<u32>()}; |
| 81 | 81 | ||
| 82 | NGLOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 82 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); |
| 83 | IPC::ResponseBuilder rb{ctx, 3}; | 83 | IPC::ResponseBuilder rb{ctx, 3}; |
| 84 | rb.Push(RESULT_SUCCESS); | 84 | rb.Push(RESULT_SUCCESS); |
| 85 | rb.Push<u32>(SHARED_FONT_REGIONS[font_id].size); | 85 | rb.Push<u32>(SHARED_FONT_REGIONS[font_id].size); |
| @@ -89,7 +89,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { | |||
| 89 | IPC::RequestParser rp{ctx}; | 89 | IPC::RequestParser rp{ctx}; |
| 90 | const u32 font_id{rp.Pop<u32>()}; | 90 | const u32 font_id{rp.Pop<u32>()}; |
| 91 | 91 | ||
| 92 | NGLOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 92 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); |
| 93 | IPC::ResponseBuilder rb{ctx, 3}; | 93 | IPC::ResponseBuilder rb{ctx, 3}; |
| 94 | rb.Push(RESULT_SUCCESS); | 94 | rb.Push(RESULT_SUCCESS); |
| 95 | rb.Push<u32>(SHARED_FONT_REGIONS[font_id].offset); | 95 | rb.Push<u32>(SHARED_FONT_REGIONS[font_id].offset); |
| @@ -110,7 +110,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | |||
| 110 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, | 110 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, |
| 111 | "PL_U:shared_font_mem"); | 111 | "PL_U:shared_font_mem"); |
| 112 | 112 | ||
| 113 | NGLOG_DEBUG(Service_NS, "called"); | 113 | LOG_DEBUG(Service_NS, "called"); |
| 114 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 114 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 115 | rb.Push(RESULT_SUCCESS); | 115 | rb.Push(RESULT_SUCCESS); |
| 116 | rb.PushCopyObjects(shared_font_mem); | 116 | rb.PushCopyObjects(shared_font_mem); |
| @@ -119,7 +119,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | |||
| 119 | void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { | 119 | void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { |
| 120 | IPC::RequestParser rp{ctx}; | 120 | IPC::RequestParser rp{ctx}; |
| 121 | const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for | 121 | const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for |
| 122 | NGLOG_DEBUG(Service_NS, "called, language_code=%lx", language_code); | 122 | LOG_DEBUG(Service_NS, "called, language_code=%lx", language_code); |
| 123 | IPC::ResponseBuilder rb{ctx, 4}; | 123 | IPC::ResponseBuilder rb{ctx, 4}; |
| 124 | std::vector<u32> font_codes; | 124 | std::vector<u32> font_codes; |
| 125 | std::vector<u32> font_offsets; | 125 | std::vector<u32> font_offsets; |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 103e66d0c..c39d5a164 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | |||
| @@ -20,9 +20,9 @@ u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector | |||
| 20 | void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, | 20 | void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, |
| 21 | u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform) { | 21 | u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform) { |
| 22 | VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); | 22 | VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); |
| 23 | NGLOG_WARNING(Service, | 23 | LOG_WARNING(Service, |
| 24 | "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", | 24 | "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", |
| 25 | addr, offset, width, height, stride, format); | 25 | addr, offset, width, height, stride, format); |
| 26 | 26 | ||
| 27 | using PixelFormat = Tegra::FramebufferConfig::PixelFormat; | 27 | using PixelFormat = Tegra::FramebufferConfig::PixelFormat; |
| 28 | const Tegra::FramebufferConfig framebuffer{ | 28 | const Tegra::FramebufferConfig framebuffer{ |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index c1eea861d..57b128b40 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -8,12 +8,14 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" | 9 | #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" |
| 10 | #include "core/hle/service/nvdrv/devices/nvmap.h" | 10 | #include "core/hle/service/nvdrv/devices/nvmap.h" |
| 11 | #include "video_core/renderer_base.h" | ||
| 12 | #include "video_core/video_core.h" | ||
| 11 | 13 | ||
| 12 | namespace Service::Nvidia::Devices { | 14 | namespace Service::Nvidia::Devices { |
| 13 | 15 | ||
| 14 | u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 16 | u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 15 | NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 17 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 16 | command.raw, input.size(), output.size()); | 18 | command.raw, input.size(), output.size()); |
| 17 | 19 | ||
| 18 | switch (static_cast<IoctlCommand>(command.raw)) { | 20 | switch (static_cast<IoctlCommand>(command.raw)) { |
| 19 | case IoctlCommand::IocInitalizeExCommand: | 21 | case IoctlCommand::IocInitalizeExCommand: |
| @@ -40,15 +42,15 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vecto | |||
| 40 | u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { | 42 | u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { |
| 41 | IoctlInitalizeEx params{}; | 43 | IoctlInitalizeEx params{}; |
| 42 | std::memcpy(¶ms, input.data(), input.size()); | 44 | std::memcpy(¶ms, input.data(), input.size()); |
| 43 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); | 45 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); |
| 44 | return 0; | 46 | return 0; |
| 45 | } | 47 | } |
| 46 | 48 | ||
| 47 | u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { | 49 | u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { |
| 48 | IoctlAllocSpace params{}; | 50 | IoctlAllocSpace params{}; |
| 49 | std::memcpy(¶ms, input.data(), input.size()); | 51 | std::memcpy(¶ms, input.data(), input.size()); |
| 50 | NGLOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages, | 52 | LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages, |
| 51 | params.page_size, params.flags); | 53 | params.page_size, params.flags); |
| 52 | 54 | ||
| 53 | auto& gpu = Core::System::GetInstance().GPU(); | 55 | auto& gpu = Core::System::GetInstance().GPU(); |
| 54 | const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)}; | 56 | const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)}; |
| @@ -65,7 +67,7 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& | |||
| 65 | u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { | 67 | u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { |
| 66 | size_t num_entries = input.size() / sizeof(IoctlRemapEntry); | 68 | size_t num_entries = input.size() / sizeof(IoctlRemapEntry); |
| 67 | 69 | ||
| 68 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries=0x{:X}", num_entries); | 70 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries=0x{:X}", num_entries); |
| 69 | 71 | ||
| 70 | std::vector<IoctlRemapEntry> entries(num_entries); | 72 | std::vector<IoctlRemapEntry> entries(num_entries); |
| 71 | std::memcpy(entries.data(), input.data(), input.size()); | 73 | std::memcpy(entries.data(), input.data(), input.size()); |
| @@ -73,8 +75,8 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 73 | auto& gpu = Core::System::GetInstance().GPU(); | 75 | auto& gpu = Core::System::GetInstance().GPU(); |
| 74 | 76 | ||
| 75 | for (const auto& entry : entries) { | 77 | for (const auto& entry : entries) { |
| 76 | NGLOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", | 78 | LOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", |
| 77 | entry.offset, entry.nvmap_handle, entry.pages); | 79 | entry.offset, entry.nvmap_handle, entry.pages); |
| 78 | Tegra::GPUVAddr offset = static_cast<Tegra::GPUVAddr>(entry.offset) << 0x10; | 80 | Tegra::GPUVAddr offset = static_cast<Tegra::GPUVAddr>(entry.offset) << 0x10; |
| 79 | 81 | ||
| 80 | auto object = nvmap_dev->GetObject(entry.nvmap_handle); | 82 | auto object = nvmap_dev->GetObject(entry.nvmap_handle); |
| @@ -96,11 +98,11 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 96 | IoctlMapBufferEx params{}; | 98 | IoctlMapBufferEx params{}; |
| 97 | std::memcpy(¶ms, input.data(), input.size()); | 99 | std::memcpy(¶ms, input.data(), input.size()); |
| 98 | 100 | ||
| 99 | NGLOG_DEBUG(Service_NVDRV, | 101 | LOG_DEBUG(Service_NVDRV, |
| 100 | "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" | 102 | "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" |
| 101 | ", offset={}", | 103 | ", offset={}", |
| 102 | params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size, | 104 | params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size, |
| 103 | params.offset); | 105 | params.offset); |
| 104 | 106 | ||
| 105 | if (!params.nvmap_handle) { | 107 | if (!params.nvmap_handle) { |
| 106 | return 0; | 108 | return 0; |
| @@ -146,7 +148,7 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 146 | IoctlUnmapBuffer params{}; | 148 | IoctlUnmapBuffer params{}; |
| 147 | std::memcpy(¶ms, input.data(), input.size()); | 149 | std::memcpy(¶ms, input.data(), input.size()); |
| 148 | 150 | ||
| 149 | NGLOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); | 151 | LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); |
| 150 | 152 | ||
| 151 | auto& gpu = Core::System::GetInstance().GPU(); | 153 | auto& gpu = Core::System::GetInstance().GPU(); |
| 152 | 154 | ||
| @@ -154,6 +156,9 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 154 | 156 | ||
| 155 | ASSERT_MSG(itr != buffer_mappings.end(), "Tried to unmap invalid mapping"); | 157 | ASSERT_MSG(itr != buffer_mappings.end(), "Tried to unmap invalid mapping"); |
| 156 | 158 | ||
| 159 | // Remove this memory region from the rasterizer cache. | ||
| 160 | VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(params.offset, itr->second.size); | ||
| 161 | |||
| 157 | params.offset = gpu.memory_manager->UnmapBuffer(params.offset, itr->second.size); | 162 | params.offset = gpu.memory_manager->UnmapBuffer(params.offset, itr->second.size); |
| 158 | 163 | ||
| 159 | buffer_mappings.erase(itr->second.offset); | 164 | buffer_mappings.erase(itr->second.offset); |
| @@ -165,7 +170,7 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 165 | u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { | 170 | u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { |
| 166 | IoctlBindChannel params{}; | 171 | IoctlBindChannel params{}; |
| 167 | std::memcpy(¶ms, input.data(), input.size()); | 172 | std::memcpy(¶ms, input.data(), input.size()); |
| 168 | NGLOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); | 173 | LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); |
| 169 | channel = params.fd; | 174 | channel = params.fd; |
| 170 | return 0; | 175 | return 0; |
| 171 | } | 176 | } |
| @@ -173,8 +178,8 @@ u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 173 | u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { | 178 | u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { |
| 174 | IoctlGetVaRegions params{}; | 179 | IoctlGetVaRegions params{}; |
| 175 | std::memcpy(¶ms, input.data(), input.size()); | 180 | std::memcpy(¶ms, input.data(), input.size()); |
| 176 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, | 181 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, |
| 177 | params.buf_size); | 182 | params.buf_size); |
| 178 | 183 | ||
| 179 | params.buf_size = 0x30; | 184 | params.buf_size = 0x30; |
| 180 | params.regions[0].offset = 0x04000000; | 185 | params.regions[0].offset = 0x04000000; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 7872d1e09..671b092e1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -9,8 +9,8 @@ | |||
| 9 | namespace Service::Nvidia::Devices { | 9 | namespace Service::Nvidia::Devices { |
| 10 | 10 | ||
| 11 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 11 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 12 | NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 12 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 13 | command.raw, input.size(), output.size()); | 13 | command.raw, input.size(), output.size()); |
| 14 | 14 | ||
| 15 | switch (static_cast<IoctlCommand>(command.raw)) { | 15 | switch (static_cast<IoctlCommand>(command.raw)) { |
| 16 | case IoctlCommand::IocGetConfigCommand: | 16 | case IoctlCommand::IocGetConfigCommand: |
| @@ -29,33 +29,18 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector< | |||
| 29 | u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { | 29 | u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { |
| 30 | IocGetConfigParams params{}; | 30 | IocGetConfigParams params{}; |
| 31 | std::memcpy(¶ms, input.data(), sizeof(params)); | 31 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 32 | NGLOG_DEBUG(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), | 32 | LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), |
| 33 | params.param_str.data()); | 33 | params.param_str.data()); |
| 34 | 34 | return 0x30006; // Returns error on production mode | |
| 35 | if (!strcmp(params.domain_str.data(), "nv")) { | ||
| 36 | if (!strcmp(params.param_str.data(), "NV_MEMORY_PROFILER")) { | ||
| 37 | params.config_str[0] = '0'; | ||
| 38 | } else if (!strcmp(params.param_str.data(), "NVN_THROUGH_OPENGL")) { | ||
| 39 | params.config_str[0] = '0'; | ||
| 40 | } else if (!strcmp(params.param_str.data(), "NVRM_GPU_PREVENT_USE")) { | ||
| 41 | params.config_str[0] = '0'; | ||
| 42 | } else { | ||
| 43 | params.config_str[0] = '\0'; | ||
| 44 | } | ||
| 45 | } else { | ||
| 46 | UNIMPLEMENTED(); // unknown domain? Only nv has been seen so far on hardware | ||
| 47 | } | ||
| 48 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 49 | return 0; | ||
| 50 | } | 35 | } |
| 51 | 36 | ||
| 52 | u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, | 37 | u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, |
| 53 | bool is_async) { | 38 | bool is_async) { |
| 54 | IocCtrlEventWaitParams params{}; | 39 | IocCtrlEventWaitParams params{}; |
| 55 | std::memcpy(¶ms, input.data(), sizeof(params)); | 40 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 56 | NGLOG_WARNING(Service_NVDRV, | 41 | LOG_WARNING(Service_NVDRV, |
| 57 | "(STUBBED) called, syncpt_id={}, threshold={}, timeout={}, is_async={}", | 42 | "(STUBBED) called, syncpt_id={}, threshold={}, timeout={}, is_async={}", |
| 58 | params.syncpt_id, params.threshold, params.timeout, is_async); | 43 | params.syncpt_id, params.threshold, params.timeout, is_async); |
| 59 | 44 | ||
| 60 | // TODO(Subv): Implement actual syncpt waiting. | 45 | // TODO(Subv): Implement actual syncpt waiting. |
| 61 | params.value = 0; | 46 | params.value = 0; |
| @@ -64,7 +49,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& | |||
| 64 | } | 49 | } |
| 65 | 50 | ||
| 66 | u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { | 51 | u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { |
| 67 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 52 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 68 | // TODO(bunnei): Implement this. | 53 | // TODO(bunnei): Implement this. |
| 69 | return 0; | 54 | return 0; |
| 70 | } | 55 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 0abc0de83..44e062f50 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -10,8 +10,8 @@ | |||
| 10 | namespace Service::Nvidia::Devices { | 10 | namespace Service::Nvidia::Devices { |
| 11 | 11 | ||
| 12 | u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 12 | u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 13 | NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 13 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 14 | command.raw, input.size(), output.size()); | 14 | command.raw, input.size(), output.size()); |
| 15 | 15 | ||
| 16 | switch (static_cast<IoctlCommand>(command.raw)) { | 16 | switch (static_cast<IoctlCommand>(command.raw)) { |
| 17 | case IoctlCommand::IocGetCharacteristicsCommand: | 17 | case IoctlCommand::IocGetCharacteristicsCommand: |
| @@ -36,7 +36,7 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec | |||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output) { | 38 | u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output) { |
| 39 | NGLOG_DEBUG(Service_NVDRV, "called"); | 39 | LOG_DEBUG(Service_NVDRV, "called"); |
| 40 | IoctlCharacteristics params{}; | 40 | IoctlCharacteristics params{}; |
| 41 | std::memcpy(¶ms, input.data(), input.size()); | 41 | std::memcpy(¶ms, input.data(), input.size()); |
| 42 | params.gc.arch = 0x120; | 42 | params.gc.arch = 0x120; |
| @@ -83,8 +83,8 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto | |||
| 83 | u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) { | 83 | u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) { |
| 84 | IoctlGpuGetTpcMasksArgs params{}; | 84 | IoctlGpuGetTpcMasksArgs params{}; |
| 85 | std::memcpy(¶ms, input.data(), input.size()); | 85 | std::memcpy(¶ms, input.data(), input.size()); |
| 86 | NGLOG_INFO(Service_NVDRV, "called, mask=0x{:X}, mask_buf_addr=0x{:X}", params.mask_buf_size, | 86 | LOG_INFO(Service_NVDRV, "called, mask=0x{:X}, mask_buf_addr=0x{:X}", params.mask_buf_size, |
| 87 | params.mask_buf_addr); | 87 | params.mask_buf_addr); |
| 88 | // TODO(ogniK): Confirm value on hardware | 88 | // TODO(ogniK): Confirm value on hardware |
| 89 | if (params.mask_buf_size) | 89 | if (params.mask_buf_size) |
| 90 | params.tpc_mask_size = 4 * 1; // 4 * num_gpc | 90 | params.tpc_mask_size = 4 * 1; // 4 * num_gpc |
| @@ -95,7 +95,7 @@ u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& | |||
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { | 97 | u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { |
| 98 | NGLOG_DEBUG(Service_NVDRV, "called"); | 98 | LOG_DEBUG(Service_NVDRV, "called"); |
| 99 | IoctlActiveSlotMask params{}; | 99 | IoctlActiveSlotMask params{}; |
| 100 | std::memcpy(¶ms, input.data(), input.size()); | 100 | std::memcpy(¶ms, input.data(), input.size()); |
| 101 | params.slot = 0x07; | 101 | params.slot = 0x07; |
| @@ -105,7 +105,7 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector | |||
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { | 107 | u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { |
| 108 | NGLOG_DEBUG(Service_NVDRV, "called"); | 108 | LOG_DEBUG(Service_NVDRV, "called"); |
| 109 | IoctlZcullGetCtxSize params{}; | 109 | IoctlZcullGetCtxSize params{}; |
| 110 | std::memcpy(¶ms, input.data(), input.size()); | 110 | std::memcpy(¶ms, input.data(), input.size()); |
| 111 | params.size = 0x1; | 111 | params.size = 0x1; |
| @@ -114,7 +114,7 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u | |||
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { | 116 | u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { |
| 117 | NGLOG_DEBUG(Service_NVDRV, "called"); | 117 | LOG_DEBUG(Service_NVDRV, "called"); |
| 118 | IoctlNvgpuGpuZcullGetInfoArgs params{}; | 118 | IoctlNvgpuGpuZcullGetInfoArgs params{}; |
| 119 | std::memcpy(¶ms, input.data(), input.size()); | 119 | std::memcpy(¶ms, input.data(), input.size()); |
| 120 | params.width_align_pixels = 0x20; | 120 | params.width_align_pixels = 0x20; |
| @@ -132,7 +132,7 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& | |||
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { | 134 | u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 135 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 135 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 136 | IoctlZbcSetTable params{}; | 136 | IoctlZbcSetTable params{}; |
| 137 | std::memcpy(¶ms, input.data(), input.size()); | 137 | std::memcpy(¶ms, input.data(), input.size()); |
| 138 | // TODO(ogniK): What does this even actually do? | 138 | // TODO(ogniK): What does this even actually do? |
| @@ -141,7 +141,7 @@ u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& | |||
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { | 143 | u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 144 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 144 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 145 | IoctlZbcQueryTable params{}; | 145 | IoctlZbcQueryTable params{}; |
| 146 | std::memcpy(¶ms, input.data(), input.size()); | 146 | std::memcpy(¶ms, input.data(), input.size()); |
| 147 | // TODO : To implement properly | 147 | // TODO : To implement properly |
| @@ -150,7 +150,7 @@ u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8> | |||
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { | 152 | u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { |
| 153 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 153 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 154 | IoctlFlushL2 params{}; | 154 | IoctlFlushL2 params{}; |
| 155 | std::memcpy(¶ms, input.data(), input.size()); | 155 | std::memcpy(¶ms, input.data(), input.size()); |
| 156 | // TODO : To implement properly | 156 | // TODO : To implement properly |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 79aab87f9..8de870596 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -12,8 +12,8 @@ | |||
| 12 | namespace Service::Nvidia::Devices { | 12 | namespace Service::Nvidia::Devices { |
| 13 | 13 | ||
| 14 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 14 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 15 | NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 15 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 16 | command.raw, input.size(), output.size()); | 16 | command.raw, input.size(), output.size()); |
| 17 | 17 | ||
| 18 | switch (static_cast<IoctlCommand>(command.raw)) { | 18 | switch (static_cast<IoctlCommand>(command.raw)) { |
| 19 | case IoctlCommand::IocSetNVMAPfdCommand: | 19 | case IoctlCommand::IocSetNVMAPfdCommand: |
| @@ -51,13 +51,13 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u | |||
| 51 | u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | 51 | u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { |
| 52 | IoctlSetNvmapFD params{}; | 52 | IoctlSetNvmapFD params{}; |
| 53 | std::memcpy(¶ms, input.data(), input.size()); | 53 | std::memcpy(¶ms, input.data(), input.size()); |
| 54 | NGLOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 54 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 55 | nvmap_fd = params.nvmap_fd; | 55 | nvmap_fd = params.nvmap_fd; |
| 56 | return 0; | 56 | return 0; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 59 | u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 60 | NGLOG_DEBUG(Service_NVDRV, "called"); | 60 | LOG_DEBUG(Service_NVDRV, "called"); |
| 61 | IoctlClientData params{}; | 61 | IoctlClientData params{}; |
| 62 | std::memcpy(¶ms, input.data(), input.size()); | 62 | std::memcpy(¶ms, input.data(), input.size()); |
| 63 | user_data = params.data; | 63 | user_data = params.data; |
| @@ -65,7 +65,7 @@ u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& out | |||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 67 | u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 68 | NGLOG_DEBUG(Service_NVDRV, "called"); | 68 | LOG_DEBUG(Service_NVDRV, "called"); |
| 69 | IoctlClientData params{}; | 69 | IoctlClientData params{}; |
| 70 | std::memcpy(¶ms, input.data(), input.size()); | 70 | std::memcpy(¶ms, input.data(), input.size()); |
| 71 | params.data = user_data; | 71 | params.data = user_data; |
| @@ -75,8 +75,8 @@ u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& out | |||
| 75 | 75 | ||
| 76 | u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { | 76 | u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { |
| 77 | std::memcpy(&zcull_params, input.data(), input.size()); | 77 | std::memcpy(&zcull_params, input.data(), input.size()); |
| 78 | NGLOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, | 78 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, |
| 79 | zcull_params.mode); | 79 | zcull_params.mode); |
| 80 | std::memcpy(output.data(), &zcull_params, output.size()); | 80 | std::memcpy(output.data(), &zcull_params, output.size()); |
| 81 | return 0; | 81 | return 0; |
| 82 | } | 82 | } |
| @@ -84,26 +84,26 @@ u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 84 | u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { | 84 | u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { |
| 85 | IoctlSetErrorNotifier params{}; | 85 | IoctlSetErrorNotifier params{}; |
| 86 | std::memcpy(¶ms, input.data(), input.size()); | 86 | std::memcpy(¶ms, input.data(), input.size()); |
| 87 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", | 87 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, |
| 88 | params.offset, params.size, params.mem); | 88 | params.size, params.mem); |
| 89 | std::memcpy(output.data(), ¶ms, output.size()); | 89 | std::memcpy(output.data(), ¶ms, output.size()); |
| 90 | return 0; | 90 | return 0; |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { | 93 | u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { |
| 94 | std::memcpy(&channel_priority, input.data(), input.size()); | 94 | std::memcpy(&channel_priority, input.data(), input.size()); |
| 95 | NGLOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); | 95 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); |
| 96 | return 0; | 96 | return 0; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { | 99 | u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { |
| 100 | IoctlAllocGpfifoEx2 params{}; | 100 | IoctlAllocGpfifoEx2 params{}; |
| 101 | std::memcpy(¶ms, input.data(), input.size()); | 101 | std::memcpy(¶ms, input.data(), input.size()); |
| 102 | NGLOG_WARNING(Service_NVDRV, | 102 | LOG_WARNING(Service_NVDRV, |
| 103 | "(STUBBED) called, num_entries={:X}, flags={:X}, unk0={:X}, " | 103 | "(STUBBED) called, num_entries={:X}, flags={:X}, unk0={:X}, " |
| 104 | "unk1={:X}, unk2={:X}, unk3={:X}", | 104 | "unk1={:X}, unk2={:X}, unk3={:X}", |
| 105 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, | 105 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, |
| 106 | params.unk3); | 106 | params.unk3); |
| 107 | params.fence_out.id = 0; | 107 | params.fence_out.id = 0; |
| 108 | params.fence_out.value = 0; | 108 | params.fence_out.value = 0; |
| 109 | std::memcpy(output.data(), ¶ms, output.size()); | 109 | std::memcpy(output.data(), ¶ms, output.size()); |
| @@ -113,20 +113,21 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 113 | u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { | 113 | u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { |
| 114 | IoctlAllocObjCtx params{}; | 114 | IoctlAllocObjCtx params{}; |
| 115 | std::memcpy(¶ms, input.data(), input.size()); | 115 | std::memcpy(¶ms, input.data(), input.size()); |
| 116 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, | 116 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, |
| 117 | params.flags); | 117 | params.flags); |
| 118 | params.obj_id = 0x0; | 118 | params.obj_id = 0x0; |
| 119 | std::memcpy(output.data(), ¶ms, output.size()); | 119 | std::memcpy(output.data(), ¶ms, output.size()); |
| 120 | return 0; | 120 | return 0; |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | 123 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { |
| 124 | if (input.size() < sizeof(IoctlSubmitGpfifo)) | 124 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 125 | UNIMPLEMENTED(); | 125 | UNIMPLEMENTED(); |
| 126 | } | ||
| 126 | IoctlSubmitGpfifo params{}; | 127 | IoctlSubmitGpfifo params{}; |
| 127 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 128 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); |
| 128 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", | 129 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", |
| 129 | params.gpfifo, params.num_entries, params.flags); | 130 | params.gpfifo, params.num_entries, params.flags); |
| 130 | 131 | ||
| 131 | auto entries = std::vector<IoctlGpfifoEntry>(); | 132 | auto entries = std::vector<IoctlGpfifoEntry>(); |
| 132 | entries.resize(params.num_entries); | 133 | entries.resize(params.num_entries); |
| @@ -145,7 +146,7 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 145 | u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | 146 | u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { |
| 146 | IoctlGetWaitbase params{}; | 147 | IoctlGetWaitbase params{}; |
| 147 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | 148 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); |
| 148 | NGLOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); | 149 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); |
| 149 | params.value = 0; // Seems to be hard coded at 0 | 150 | params.value = 0; // Seems to be hard coded at 0 |
| 150 | std::memcpy(output.data(), ¶ms, output.size()); | 151 | std::memcpy(output.data(), ¶ms, output.size()); |
| 151 | return 0; | 152 | return 0; |
| @@ -154,7 +155,7 @@ u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& outpu | |||
| 154 | u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { | 155 | u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { |
| 155 | IoctlChannelSetTimeout params{}; | 156 | IoctlChannelSetTimeout params{}; |
| 156 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); | 157 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); |
| 157 | NGLOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); | 158 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); |
| 158 | return 0; | 159 | return 0; |
| 159 | } | 160 | } |
| 160 | 161 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 0b6c22898..b51c73ee8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -9,8 +9,8 @@ | |||
| 9 | namespace Service::Nvidia::Devices { | 9 | namespace Service::Nvidia::Devices { |
| 10 | 10 | ||
| 11 | u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 11 | u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 12 | NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 12 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 13 | command.raw, input.size(), output.size()); | 13 | command.raw, input.size(), output.size()); |
| 14 | 14 | ||
| 15 | switch (static_cast<IoctlCommand>(command.raw)) { | 15 | switch (static_cast<IoctlCommand>(command.raw)) { |
| 16 | case IoctlCommand::IocSetNVMAPfdCommand: | 16 | case IoctlCommand::IocSetNVMAPfdCommand: |
| @@ -24,7 +24,7 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector | |||
| 24 | u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | 24 | u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { |
| 25 | IoctlSetNvmapFD params{}; | 25 | IoctlSetNvmapFD params{}; |
| 26 | std::memcpy(¶ms, input.data(), input.size()); | 26 | std::memcpy(¶ms, input.data(), input.size()); |
| 27 | NGLOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 27 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 28 | nvmap_fd = params.nvmap_fd; | 28 | nvmap_fd = params.nvmap_fd; |
| 29 | return 0; | 29 | return 0; |
| 30 | } | 30 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 23fe98190..724eeb139 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -52,7 +52,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 52 | u32 handle = next_handle++; | 52 | u32 handle = next_handle++; |
| 53 | handles[handle] = std::move(object); | 53 | handles[handle] = std::move(object); |
| 54 | 54 | ||
| 55 | NGLOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); | 55 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); |
| 56 | 56 | ||
| 57 | params.handle = handle; | 57 | params.handle = handle; |
| 58 | 58 | ||
| @@ -73,7 +73,7 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 73 | object->addr = params.addr; | 73 | object->addr = params.addr; |
| 74 | object->status = Object::Status::Allocated; | 74 | object->status = Object::Status::Allocated; |
| 75 | 75 | ||
| 76 | NGLOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); | 76 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); |
| 77 | 77 | ||
| 78 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 78 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 79 | return 0; | 79 | return 0; |
| @@ -83,7 +83,7 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 83 | IocGetIdParams params; | 83 | IocGetIdParams params; |
| 84 | std::memcpy(¶ms, input.data(), sizeof(params)); | 84 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 85 | 85 | ||
| 86 | NGLOG_WARNING(Service_NVDRV, "called"); | 86 | LOG_WARNING(Service_NVDRV, "called"); |
| 87 | 87 | ||
| 88 | auto object = GetObject(params.handle); | 88 | auto object = GetObject(params.handle); |
| 89 | ASSERT(object); | 89 | ASSERT(object); |
| @@ -98,7 +98,7 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 98 | IocFromIdParams params; | 98 | IocFromIdParams params; |
| 99 | std::memcpy(¶ms, input.data(), sizeof(params)); | 99 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 100 | 100 | ||
| 101 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 101 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 102 | 102 | ||
| 103 | auto itr = std::find_if(handles.begin(), handles.end(), | 103 | auto itr = std::find_if(handles.begin(), handles.end(), |
| 104 | [&](const auto& entry) { return entry.second->id == params.id; }); | 104 | [&](const auto& entry) { return entry.second->id == params.id; }); |
| @@ -119,7 +119,7 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 119 | IocParamParams params; | 119 | IocParamParams params; |
| 120 | std::memcpy(¶ms, input.data(), sizeof(params)); | 120 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 121 | 121 | ||
| 122 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param); | 122 | LOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param); |
| 123 | 123 | ||
| 124 | auto object = GetObject(params.handle); | 124 | auto object = GetObject(params.handle); |
| 125 | ASSERT(object); | 125 | ASSERT(object); |
| @@ -148,6 +148,7 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | 150 | u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { |
| 151 | // TODO(Subv): These flags are unconfirmed. | ||
| 151 | enum FreeFlags { | 152 | enum FreeFlags { |
| 152 | Freed = 0, | 153 | Freed = 0, |
| 153 | NotFreedYet = 1, | 154 | NotFreedYet = 1, |
| @@ -156,20 +157,26 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 156 | IocFreeParams params; | 157 | IocFreeParams params; |
| 157 | std::memcpy(¶ms, input.data(), sizeof(params)); | 158 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 158 | 159 | ||
| 159 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 160 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 160 | 161 | ||
| 161 | auto itr = handles.find(params.handle); | 162 | auto itr = handles.find(params.handle); |
| 162 | ASSERT(itr != handles.end()); | 163 | ASSERT(itr != handles.end()); |
| 163 | 164 | ||
| 165 | ASSERT(itr->second->refcount > 0); | ||
| 166 | |||
| 164 | itr->second->refcount--; | 167 | itr->second->refcount--; |
| 165 | 168 | ||
| 166 | params.refcount = itr->second->refcount; | ||
| 167 | params.size = itr->second->size; | 169 | params.size = itr->second->size; |
| 168 | 170 | ||
| 169 | if (itr->second->refcount == 0) | 171 | if (itr->second->refcount == 0) { |
| 170 | params.flags = Freed; | 172 | params.flags = Freed; |
| 171 | else | 173 | // The address of the nvmap is written to the output if we're finally freeing it, otherwise |
| 174 | // 0 is written. | ||
| 175 | params.address = itr->second->addr; | ||
| 176 | } else { | ||
| 172 | params.flags = NotFreedYet; | 177 | params.flags = NotFreedYet; |
| 178 | params.address = 0; | ||
| 179 | } | ||
| 173 | 180 | ||
| 174 | handles.erase(params.handle); | 181 | handles.erase(params.handle); |
| 175 | 182 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 39fafaa7c..f2eec6409 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h | |||
| @@ -94,7 +94,7 @@ private: | |||
| 94 | struct IocFreeParams { | 94 | struct IocFreeParams { |
| 95 | u32_le handle; | 95 | u32_le handle; |
| 96 | INSERT_PADDING_BYTES(4); | 96 | INSERT_PADDING_BYTES(4); |
| 97 | u64_le refcount; | 97 | u64_le address; |
| 98 | u32_le size; | 98 | u32_le size; |
| 99 | u32_le flags; | 99 | u32_le flags; |
| 100 | }; | 100 | }; |
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 45d2862ef..b10efd5c9 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | namespace Service::Nvidia { | 12 | namespace Service::Nvidia { |
| 13 | 13 | ||
| 14 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { | 14 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { |
| 15 | NGLOG_DEBUG(Service_NVDRV, "called"); | 15 | LOG_DEBUG(Service_NVDRV, "called"); |
| 16 | 16 | ||
| 17 | const auto& buffer = ctx.ReadBuffer(); | 17 | const auto& buffer = ctx.ReadBuffer(); |
| 18 | std::string device_name(buffer.begin(), buffer.end()); | 18 | std::string device_name(buffer.begin(), buffer.end()); |
| @@ -25,7 +25,7 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) { | |||
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { | 27 | void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { |
| 28 | NGLOG_DEBUG(Service_NVDRV, "called"); | 28 | LOG_DEBUG(Service_NVDRV, "called"); |
| 29 | 29 | ||
| 30 | IPC::RequestParser rp{ctx}; | 30 | IPC::RequestParser rp{ctx}; |
| 31 | u32 fd = rp.Pop<u32>(); | 31 | u32 fd = rp.Pop<u32>(); |
| @@ -41,7 +41,7 @@ void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { | 43 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { |
| 44 | NGLOG_DEBUG(Service_NVDRV, "called"); | 44 | LOG_DEBUG(Service_NVDRV, "called"); |
| 45 | 45 | ||
| 46 | IPC::RequestParser rp{ctx}; | 46 | IPC::RequestParser rp{ctx}; |
| 47 | u32 fd = rp.Pop<u32>(); | 47 | u32 fd = rp.Pop<u32>(); |
| @@ -53,7 +53,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) { | |||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { | 55 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { |
| 56 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 56 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 57 | IPC::ResponseBuilder rb{ctx, 3}; | 57 | IPC::ResponseBuilder rb{ctx, 3}; |
| 58 | rb.Push(RESULT_SUCCESS); | 58 | rb.Push(RESULT_SUCCESS); |
| 59 | rb.Push<u32>(0); | 59 | rb.Push<u32>(0); |
| @@ -63,7 +63,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { | |||
| 63 | IPC::RequestParser rp{ctx}; | 63 | IPC::RequestParser rp{ctx}; |
| 64 | u32 fd = rp.Pop<u32>(); | 64 | u32 fd = rp.Pop<u32>(); |
| 65 | u32 event_id = rp.Pop<u32>(); | 65 | u32 event_id = rp.Pop<u32>(); |
| 66 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); | 66 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); |
| 67 | 67 | ||
| 68 | IPC::ResponseBuilder rb{ctx, 3, 1}; | 68 | IPC::ResponseBuilder rb{ctx, 3, 1}; |
| 69 | rb.Push(RESULT_SUCCESS); | 69 | rb.Push(RESULT_SUCCESS); |
| @@ -75,14 +75,14 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { | |||
| 75 | IPC::RequestParser rp{ctx}; | 75 | IPC::RequestParser rp{ctx}; |
| 76 | pid = rp.Pop<u64>(); | 76 | pid = rp.Pop<u64>(); |
| 77 | 77 | ||
| 78 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); | 78 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); |
| 79 | IPC::ResponseBuilder rb{ctx, 3}; | 79 | IPC::ResponseBuilder rb{ctx, 3}; |
| 80 | rb.Push(RESULT_SUCCESS); | 80 | rb.Push(RESULT_SUCCESS); |
| 81 | rb.Push<u32>(0); | 81 | rb.Push<u32>(0); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { | 84 | void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { |
| 85 | NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 85 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 86 | IPC::ResponseBuilder rb{ctx, 2}; | 86 | IPC::ResponseBuilder rb{ctx, 2}; |
| 87 | rb.Push(RESULT_SUCCESS); | 87 | rb.Push(RESULT_SUCCESS); |
| 88 | } | 88 | } |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 49e88b394..f7f2fe1b2 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -23,7 +23,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { | |||
| 23 | buffer.igbp_buffer = igbp_buffer; | 23 | buffer.igbp_buffer = igbp_buffer; |
| 24 | buffer.status = Buffer::Status::Free; | 24 | buffer.status = Buffer::Status::Free; |
| 25 | 25 | ||
| 26 | NGLOG_WARNING(Service, "Adding graphics buffer {}", slot); | 26 | LOG_WARNING(Service, "Adding graphics buffer {}", slot); |
| 27 | 27 | ||
| 28 | queue.emplace_back(buffer); | 28 | queue.emplace_back(buffer); |
| 29 | 29 | ||
| @@ -94,7 +94,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) { | |||
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | u32 BufferQueue::Query(QueryType type) { | 96 | u32 BufferQueue::Query(QueryType type) { |
| 97 | NGLOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); | 97 | LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); |
| 98 | switch (type) { | 98 | switch (type) { |
| 99 | case QueryType::NativeWindowFormat: | 99 | case QueryType::NativeWindowFormat: |
| 100 | // TODO(Subv): Use an enum for this | 100 | // TODO(Subv): Use an enum for this |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 5c50ed601..ef3c2cc98 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -48,7 +48,7 @@ NVFlinger::~NVFlinger() { | |||
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | u64 NVFlinger::OpenDisplay(const std::string& name) { | 50 | u64 NVFlinger::OpenDisplay(const std::string& name) { |
| 51 | NGLOG_WARNING(Service, "Opening display {}", name); | 51 | LOG_WARNING(Service, "Opening display {}", name); |
| 52 | 52 | ||
| 53 | // TODO(Subv): Currently we only support the Default display. | 53 | // TODO(Subv): Currently we only support the Default display. |
| 54 | ASSERT(name == "Default"); | 54 | ASSERT(name == "Default"); |
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp index dd20d5ae7..fcf1f3da3 100644 --- a/src/core/hle/service/pctl/module.cpp +++ b/src/core/hle/service/pctl/module.cpp | |||
| @@ -112,7 +112,7 @@ public: | |||
| 112 | 112 | ||
| 113 | private: | 113 | private: |
| 114 | void Initialize(Kernel::HLERequestContext& ctx) { | 114 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 115 | NGLOG_WARNING(Service_PCTL, "(STUBBED) called"); | 115 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); |
| 116 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | 116 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; |
| 117 | rb.Push(RESULT_SUCCESS); | 117 | rb.Push(RESULT_SUCCESS); |
| 118 | } | 118 | } |
| @@ -122,14 +122,14 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { | |||
| 122 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 122 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 123 | rb.Push(RESULT_SUCCESS); | 123 | rb.Push(RESULT_SUCCESS); |
| 124 | rb.PushIpcInterface<IParentalControlService>(); | 124 | rb.PushIpcInterface<IParentalControlService>(); |
| 125 | NGLOG_DEBUG(Service_PCTL, "called"); | 125 | LOG_DEBUG(Service_PCTL, "called"); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { | 128 | void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { |
| 129 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 129 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 130 | rb.Push(RESULT_SUCCESS); | 130 | rb.Push(RESULT_SUCCESS); |
| 131 | rb.PushIpcInterface<IParentalControlService>(); | 131 | rb.PushIpcInterface<IParentalControlService>(); |
| 132 | NGLOG_DEBUG(Service_PCTL, "called"); | 132 | LOG_DEBUG(Service_PCTL, "called"); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 135 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index eaf30ee6b..3c43b8d8c 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp | |||
| @@ -27,7 +27,7 @@ PlayReport::PlayReport(const char* name) : ServiceFramework(name) { | |||
| 27 | 27 | ||
| 28 | void PlayReport::SaveReportWithUser(Kernel::HLERequestContext& ctx) { | 28 | void PlayReport::SaveReportWithUser(Kernel::HLERequestContext& ctx) { |
| 29 | // TODO(ogniK): Do we want to add play report? | 29 | // TODO(ogniK): Do we want to add play report? |
| 30 | NGLOG_WARNING(Service_PREPO, "(STUBBED) called"); | 30 | LOG_WARNING(Service_PREPO, "(STUBBED) called"); |
| 31 | 31 | ||
| 32 | IPC::ResponseBuilder rb{ctx, 2}; | 32 | IPC::ResponseBuilder rb{ctx, 2}; |
| 33 | rb.Push(RESULT_SUCCESS); | 33 | rb.Push(RESULT_SUCCESS); |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index bdd9eb5a5..0d036bfaa 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -122,7 +122,7 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext | |||
| 122 | } | 122 | } |
| 123 | buf.push_back('}'); | 123 | buf.push_back('}'); |
| 124 | 124 | ||
| 125 | NGLOG_ERROR(Service, "unknown / unimplemented {}", fmt::to_string(buf)); | 125 | LOG_ERROR(Service, "unknown / unimplemented {}", fmt::to_string(buf)); |
| 126 | UNIMPLEMENTED(); | 126 | UNIMPLEMENTED(); |
| 127 | } | 127 | } |
| 128 | 128 | ||
| @@ -133,7 +133,7 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { | |||
| 133 | return ReportUnimplementedFunction(ctx, info); | 133 | return ReportUnimplementedFunction(ctx, info); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | NGLOG_TRACE( | 136 | LOG_TRACE( |
| 137 | Service, "{}", | 137 | Service, "{}", |
| 138 | MakeFunctionString(info->name, GetServiceName().c_str(), ctx.CommandBuffer()).c_str()); | 138 | MakeFunctionString(info->name, GetServiceName().c_str(), ctx.CommandBuffer()).c_str()); |
| 139 | handler_invoker(this, info->handler_callback, ctx); | 139 | handler_invoker(this, info->handler_callback, ctx); |
| @@ -206,12 +206,12 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) { | |||
| 206 | VI::InstallInterfaces(*sm, nv_flinger); | 206 | VI::InstallInterfaces(*sm, nv_flinger); |
| 207 | Set::InstallInterfaces(*sm); | 207 | Set::InstallInterfaces(*sm); |
| 208 | 208 | ||
| 209 | NGLOG_DEBUG(Service, "initialized OK"); | 209 | LOG_DEBUG(Service, "initialized OK"); |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | /// Shutdown ServiceManager | 212 | /// Shutdown ServiceManager |
| 213 | void Shutdown() { | 213 | void Shutdown() { |
| 214 | g_kernel_named_ports.clear(); | 214 | g_kernel_named_ports.clear(); |
| 215 | NGLOG_DEBUG(Service, "shutdown OK"); | 215 | LOG_DEBUG(Service, "shutdown OK"); |
| 216 | } | 216 | } |
| 217 | } // namespace Service | 217 | } // namespace Service |
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index f0572bed6..bd295cdf6 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp | |||
| @@ -12,9 +12,6 @@ | |||
| 12 | namespace Service::Set { | 12 | namespace Service::Set { |
| 13 | 13 | ||
| 14 | void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { | 14 | void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { |
| 15 | IPC::RequestParser rp{ctx}; | ||
| 16 | u32 id = rp.Pop<u32>(); | ||
| 17 | |||
| 18 | static constexpr std::array<LanguageCode, 17> available_language_codes = {{ | 15 | static constexpr std::array<LanguageCode, 17> available_language_codes = {{ |
| 19 | LanguageCode::JA, | 16 | LanguageCode::JA, |
| 20 | LanguageCode::EN_US, | 17 | LanguageCode::EN_US, |
| @@ -40,7 +37,7 @@ void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { | |||
| 40 | rb.Push(RESULT_SUCCESS); | 37 | rb.Push(RESULT_SUCCESS); |
| 41 | rb.Push(static_cast<u64>(available_language_codes.size())); | 38 | rb.Push(static_cast<u64>(available_language_codes.size())); |
| 42 | 39 | ||
| 43 | NGLOG_DEBUG(Service_SET, "called"); | 40 | LOG_DEBUG(Service_SET, "called"); |
| 44 | } | 41 | } |
| 45 | 42 | ||
| 46 | SET::SET() : ServiceFramework("set") { | 43 | SET::SET() : ServiceFramework("set") { |
| @@ -50,7 +47,7 @@ SET::SET() : ServiceFramework("set") { | |||
| 50 | {2, nullptr, "MakeLanguageCode"}, | 47 | {2, nullptr, "MakeLanguageCode"}, |
| 51 | {3, nullptr, "GetAvailableLanguageCodeCount"}, | 48 | {3, nullptr, "GetAvailableLanguageCodeCount"}, |
| 52 | {4, nullptr, "GetRegionCode"}, | 49 | {4, nullptr, "GetRegionCode"}, |
| 53 | {5, nullptr, "GetAvailableLanguageCodes2"}, | 50 | {5, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes2"}, |
| 54 | {6, nullptr, "GetAvailableLanguageCodeCount2"}, | 51 | {6, nullptr, "GetAvailableLanguageCodeCount2"}, |
| 55 | {7, nullptr, "GetKeyCodeMap"}, | 52 | {7, nullptr, "GetKeyCodeMap"}, |
| 56 | {8, nullptr, "GetQuestFlag"}, | 53 | {8, nullptr, "GetQuestFlag"}, |
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 762a664c5..fa85277fe 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -16,7 +16,7 @@ void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) { | |||
| 16 | rb.Push(RESULT_SUCCESS); | 16 | rb.Push(RESULT_SUCCESS); |
| 17 | rb.Push<u32>(0); | 17 | rb.Push<u32>(0); |
| 18 | 18 | ||
| 19 | NGLOG_WARNING(Service_SET, "(STUBBED) called"); | 19 | LOG_WARNING(Service_SET, "(STUBBED) called"); |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | SET_SYS::SET_SYS() : ServiceFramework("set:sys") { | 22 | SET_SYS::SET_SYS() : ServiceFramework("set:sys") { |
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index fe5097cdc..518a0cc46 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp | |||
| @@ -17,7 +17,7 @@ void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { | |||
| 17 | rb.Push(RESULT_SUCCESS); | 17 | rb.Push(RESULT_SUCCESS); |
| 18 | rb.Push<u32>(1); // Converted sessions start with 1 request handler | 18 | rb.Push<u32>(1); // Converted sessions start with 1 request handler |
| 19 | 19 | ||
| 20 | NGLOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); | 20 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { | 23 | void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { |
| @@ -29,11 +29,11 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { | |||
| 29 | Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; | 29 | Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; |
| 30 | rb.PushMoveObjects(session); | 30 | rb.PushMoveObjects(session); |
| 31 | 31 | ||
| 32 | NGLOG_DEBUG(Service, "called, session={}", session->GetObjectId()); | 32 | LOG_DEBUG(Service, "called, session={}", session->GetObjectId()); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { | 35 | void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { |
| 36 | NGLOG_WARNING(Service, "(STUBBED) called, using DuplicateSession"); | 36 | LOG_WARNING(Service, "(STUBBED) called, using DuplicateSession"); |
| 37 | 37 | ||
| 38 | DuplicateSession(ctx); | 38 | DuplicateSession(ctx); |
| 39 | } | 39 | } |
| @@ -43,7 +43,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 43 | rb.Push(RESULT_SUCCESS); | 43 | rb.Push(RESULT_SUCCESS); |
| 44 | rb.Push<u32>(0x500); | 44 | rb.Push<u32>(0x500); |
| 45 | 45 | ||
| 46 | NGLOG_WARNING(Service, "(STUBBED) called"); | 46 | LOG_WARNING(Service, "(STUBBED) called"); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | Controller::Controller() : ServiceFramework("IpcController") { | 49 | Controller::Controller() : ServiceFramework("IpcController") { |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index bded8421f..f22a2a79f 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -86,7 +86,7 @@ SM::~SM() = default; | |||
| 86 | void SM::Initialize(Kernel::HLERequestContext& ctx) { | 86 | void SM::Initialize(Kernel::HLERequestContext& ctx) { |
| 87 | IPC::ResponseBuilder rb{ctx, 2}; | 87 | IPC::ResponseBuilder rb{ctx, 2}; |
| 88 | rb.Push(RESULT_SUCCESS); | 88 | rb.Push(RESULT_SUCCESS); |
| 89 | NGLOG_DEBUG(Service_SM, "called"); | 89 | LOG_DEBUG(Service_SM, "called"); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | void SM::GetService(Kernel::HLERequestContext& ctx) { | 92 | void SM::GetService(Kernel::HLERequestContext& ctx) { |
| @@ -102,8 +102,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { | |||
| 102 | if (client_port.Failed()) { | 102 | if (client_port.Failed()) { |
| 103 | IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); | 103 | IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); |
| 104 | rb.Push(client_port.Code()); | 104 | rb.Push(client_port.Code()); |
| 105 | NGLOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, | 105 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw); |
| 106 | client_port.Code().raw); | ||
| 107 | if (name.length() == 0) | 106 | if (name.length() == 0) |
| 108 | return; // LibNX Fix | 107 | return; // LibNX Fix |
| 109 | UNIMPLEMENTED(); | 108 | UNIMPLEMENTED(); |
| @@ -113,7 +112,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { | |||
| 113 | auto session = client_port.Unwrap()->Connect(); | 112 | auto session = client_port.Unwrap()->Connect(); |
| 114 | ASSERT(session.Succeeded()); | 113 | ASSERT(session.Succeeded()); |
| 115 | if (session.Succeeded()) { | 114 | if (session.Succeeded()) { |
| 116 | NGLOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId()); | 115 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId()); |
| 117 | IPC::ResponseBuilder rb = | 116 | IPC::ResponseBuilder rb = |
| 118 | rp.MakeBuilder(2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles); | 117 | rp.MakeBuilder(2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles); |
| 119 | rb.Push(session.Code()); | 118 | rb.Push(session.Code()); |
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index ab909fdaa..32648bdd9 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | namespace Service::Sockets { | 8 | namespace Service::Sockets { |
| 9 | 9 | ||
| 10 | void BSD::RegisterClient(Kernel::HLERequestContext& ctx) { | 10 | void BSD::RegisterClient(Kernel::HLERequestContext& ctx) { |
| 11 | NGLOG_WARNING(Service, "(STUBBED) called"); | 11 | LOG_WARNING(Service, "(STUBBED) called"); |
| 12 | 12 | ||
| 13 | IPC::ResponseBuilder rb{ctx, 3}; | 13 | IPC::ResponseBuilder rb{ctx, 3}; |
| 14 | 14 | ||
| @@ -17,7 +17,7 @@ void BSD::RegisterClient(Kernel::HLERequestContext& ctx) { | |||
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) { | 19 | void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) { |
| 20 | NGLOG_WARNING(Service, "(STUBBED) called"); | 20 | LOG_WARNING(Service, "(STUBBED) called"); |
| 21 | 21 | ||
| 22 | IPC::ResponseBuilder rb{ctx, 3}; | 22 | IPC::ResponseBuilder rb{ctx, 3}; |
| 23 | 23 | ||
| @@ -32,8 +32,7 @@ void BSD::Socket(Kernel::HLERequestContext& ctx) { | |||
| 32 | u32 type = rp.Pop<u32>(); | 32 | u32 type = rp.Pop<u32>(); |
| 33 | u32 protocol = rp.Pop<u32>(); | 33 | u32 protocol = rp.Pop<u32>(); |
| 34 | 34 | ||
| 35 | NGLOG_WARNING(Service, "(STUBBED) called domain={} type={} protocol={}", domain, type, | 35 | LOG_WARNING(Service, "(STUBBED) called domain={} type={} protocol={}", domain, type, protocol); |
| 36 | protocol); | ||
| 37 | 36 | ||
| 38 | u32 fd = next_fd++; | 37 | u32 fd = next_fd++; |
| 39 | 38 | ||
| @@ -45,7 +44,7 @@ void BSD::Socket(Kernel::HLERequestContext& ctx) { | |||
| 45 | } | 44 | } |
| 46 | 45 | ||
| 47 | void BSD::Connect(Kernel::HLERequestContext& ctx) { | 46 | void BSD::Connect(Kernel::HLERequestContext& ctx) { |
| 48 | NGLOG_WARNING(Service, "(STUBBED) called"); | 47 | LOG_WARNING(Service, "(STUBBED) called"); |
| 49 | 48 | ||
| 50 | IPC::ResponseBuilder rb{ctx, 4}; | 49 | IPC::ResponseBuilder rb{ctx, 4}; |
| 51 | 50 | ||
| @@ -55,7 +54,7 @@ void BSD::Connect(Kernel::HLERequestContext& ctx) { | |||
| 55 | } | 54 | } |
| 56 | 55 | ||
| 57 | void BSD::SendTo(Kernel::HLERequestContext& ctx) { | 56 | void BSD::SendTo(Kernel::HLERequestContext& ctx) { |
| 58 | NGLOG_WARNING(Service, "(STUBBED) called"); | 57 | LOG_WARNING(Service, "(STUBBED) called"); |
| 59 | 58 | ||
| 60 | IPC::ResponseBuilder rb{ctx, 4}; | 59 | IPC::ResponseBuilder rb{ctx, 4}; |
| 61 | 60 | ||
| @@ -65,7 +64,7 @@ void BSD::SendTo(Kernel::HLERequestContext& ctx) { | |||
| 65 | } | 64 | } |
| 66 | 65 | ||
| 67 | void BSD::Close(Kernel::HLERequestContext& ctx) { | 66 | void BSD::Close(Kernel::HLERequestContext& ctx) { |
| 68 | NGLOG_WARNING(Service, "(STUBBED) called"); | 67 | LOG_WARNING(Service, "(STUBBED) called"); |
| 69 | 68 | ||
| 70 | IPC::ResponseBuilder rb{ctx, 4}; | 69 | IPC::ResponseBuilder rb{ctx, 4}; |
| 71 | 70 | ||
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index f377e59f2..d235c4cfd 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp | |||
| @@ -10,7 +10,7 @@ namespace Service::Sockets { | |||
| 10 | void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) { | 10 | void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) { |
| 11 | IPC::RequestParser rp{ctx}; | 11 | IPC::RequestParser rp{ctx}; |
| 12 | 12 | ||
| 13 | NGLOG_WARNING(Service, "(STUBBED) called"); | 13 | LOG_WARNING(Service, "(STUBBED) called"); |
| 14 | 14 | ||
| 15 | IPC::ResponseBuilder rb{ctx, 2}; | 15 | IPC::ResponseBuilder rb{ctx, 2}; |
| 16 | 16 | ||
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp index 76ba97156..3f5a342a7 100644 --- a/src/core/hle/service/spl/module.cpp +++ b/src/core/hle/service/spl/module.cpp | |||
| @@ -28,7 +28,7 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { | |||
| 28 | 28 | ||
| 29 | IPC::ResponseBuilder rb{ctx, 2}; | 29 | IPC::ResponseBuilder rb{ctx, 2}; |
| 30 | rb.Push(RESULT_SUCCESS); | 30 | rb.Push(RESULT_SUCCESS); |
| 31 | NGLOG_DEBUG(Service_SPL, "called"); | 31 | LOG_DEBUG(Service_SPL, "called"); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 34 | void InstallInterfaces(SM::ServiceManager& service_manager) { |
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index b3dad8b06..40aea6090 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp | |||
| @@ -65,7 +65,7 @@ public: | |||
| 65 | 65 | ||
| 66 | private: | 66 | private: |
| 67 | void SetOption(Kernel::HLERequestContext& ctx) { | 67 | void SetOption(Kernel::HLERequestContext& ctx) { |
| 68 | NGLOG_WARNING(Service_SSL, "(STUBBED) called"); | 68 | LOG_WARNING(Service_SSL, "(STUBBED) called"); |
| 69 | IPC::RequestParser rp{ctx}; | 69 | IPC::RequestParser rp{ctx}; |
| 70 | 70 | ||
| 71 | IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); | 71 | IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); |
| @@ -73,7 +73,7 @@ private: | |||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | void CreateConnection(Kernel::HLERequestContext& ctx) { | 75 | void CreateConnection(Kernel::HLERequestContext& ctx) { |
| 76 | NGLOG_WARNING(Service_SSL, "(STUBBED) called"); | 76 | LOG_WARNING(Service_SSL, "(STUBBED) called"); |
| 77 | 77 | ||
| 78 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 78 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 79 | rb.Push(RESULT_SUCCESS); | 79 | rb.Push(RESULT_SUCCESS); |
| @@ -82,7 +82,7 @@ private: | |||
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | void SSL::CreateContext(Kernel::HLERequestContext& ctx) { | 84 | void SSL::CreateContext(Kernel::HLERequestContext& ctx) { |
| 85 | NGLOG_WARNING(Service_SSL, "(STUBBED) called"); | 85 | LOG_WARNING(Service_SSL, "(STUBBED) called"); |
| 86 | 86 | ||
| 87 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 87 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 88 | rb.Push(RESULT_SUCCESS); | 88 | rb.Push(RESULT_SUCCESS); |
| @@ -103,7 +103,7 @@ SSL::SSL() : ServiceFramework("ssl") { | |||
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | void SSL::SetInterfaceVersion(Kernel::HLERequestContext& ctx) { | 105 | void SSL::SetInterfaceVersion(Kernel::HLERequestContext& ctx) { |
| 106 | NGLOG_WARNING(Service_SSL, "(STUBBED) called"); | 106 | LOG_WARNING(Service_SSL, "(STUBBED) called"); |
| 107 | IPC::RequestParser rp{ctx}; | 107 | IPC::RequestParser rp{ctx}; |
| 108 | u32 unk1 = rp.Pop<u32>(); // Probably minor/major? | 108 | u32 unk1 = rp.Pop<u32>(); // Probably minor/major? |
| 109 | u32 unk2 = rp.Pop<u32>(); // TODO(ogniK): Figure out what this does | 109 | u32 unk2 = rp.Pop<u32>(); // TODO(ogniK): Figure out what this does |
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 654012189..507ae95f4 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -33,14 +33,14 @@ private: | |||
| 33 | const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( | 33 | const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( |
| 34 | std::chrono::system_clock::now().time_since_epoch()) | 34 | std::chrono::system_clock::now().time_since_epoch()) |
| 35 | .count()}; | 35 | .count()}; |
| 36 | NGLOG_DEBUG(Service_Time, "called"); | 36 | LOG_DEBUG(Service_Time, "called"); |
| 37 | IPC::ResponseBuilder rb{ctx, 4}; | 37 | IPC::ResponseBuilder rb{ctx, 4}; |
| 38 | rb.Push(RESULT_SUCCESS); | 38 | rb.Push(RESULT_SUCCESS); |
| 39 | rb.Push<u64>(time_since_epoch); | 39 | rb.Push<u64>(time_since_epoch); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | void GetSystemClockContext(Kernel::HLERequestContext& ctx) { | 42 | void GetSystemClockContext(Kernel::HLERequestContext& ctx) { |
| 43 | NGLOG_WARNING(Service_Time, "(STUBBED) called"); | 43 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 44 | SystemClockContext system_clock_ontext{}; | 44 | SystemClockContext system_clock_ontext{}; |
| 45 | IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; | 45 | IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; |
| 46 | rb.Push(RESULT_SUCCESS); | 46 | rb.Push(RESULT_SUCCESS); |
| @@ -59,7 +59,7 @@ public: | |||
| 59 | 59 | ||
| 60 | private: | 60 | private: |
| 61 | void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { | 61 | void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { |
| 62 | NGLOG_DEBUG(Service_Time, "called"); | 62 | LOG_DEBUG(Service_Time, "called"); |
| 63 | SteadyClockTimePoint steady_clock_time_point{ | 63 | SteadyClockTimePoint steady_clock_time_point{ |
| 64 | CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000}; | 64 | CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000}; |
| 65 | IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; | 65 | IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; |
| @@ -91,21 +91,21 @@ private: | |||
| 91 | TimeZoneRule my_time_zone_rule{}; | 91 | TimeZoneRule my_time_zone_rule{}; |
| 92 | 92 | ||
| 93 | void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { | 93 | void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { |
| 94 | NGLOG_DEBUG(Service_Time, "called"); | 94 | LOG_DEBUG(Service_Time, "called"); |
| 95 | IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; | 95 | IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; |
| 96 | rb.Push(RESULT_SUCCESS); | 96 | rb.Push(RESULT_SUCCESS); |
| 97 | rb.PushRaw(location_name); | 97 | rb.PushRaw(location_name); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { | 100 | void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { |
| 101 | NGLOG_WARNING(Service_Time, "(STUBBED) called"); | 101 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 102 | IPC::ResponseBuilder rb{ctx, 3}; | 102 | IPC::ResponseBuilder rb{ctx, 3}; |
| 103 | rb.Push(RESULT_SUCCESS); | 103 | rb.Push(RESULT_SUCCESS); |
| 104 | rb.Push<u32>(0); | 104 | rb.Push<u32>(0); |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | void LoadTimeZoneRule(Kernel::HLERequestContext& ctx) { | 107 | void LoadTimeZoneRule(Kernel::HLERequestContext& ctx) { |
| 108 | NGLOG_WARNING(Service_Time, "(STUBBED) called"); | 108 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 109 | 109 | ||
| 110 | ctx.WriteBuffer(&my_time_zone_rule, sizeof(TimeZoneRule)); | 110 | ctx.WriteBuffer(&my_time_zone_rule, sizeof(TimeZoneRule)); |
| 111 | 111 | ||
| @@ -117,7 +117,7 @@ private: | |||
| 117 | IPC::RequestParser rp{ctx}; | 117 | IPC::RequestParser rp{ctx}; |
| 118 | const u64 posix_time = rp.Pop<u64>(); | 118 | const u64 posix_time = rp.Pop<u64>(); |
| 119 | 119 | ||
| 120 | NGLOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); | 120 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); |
| 121 | 121 | ||
| 122 | TimeZoneRule time_zone_rule{}; | 122 | TimeZoneRule time_zone_rule{}; |
| 123 | auto buffer = ctx.ReadBuffer(); | 123 | auto buffer = ctx.ReadBuffer(); |
| @@ -138,7 +138,7 @@ private: | |||
| 138 | IPC::RequestParser rp{ctx}; | 138 | IPC::RequestParser rp{ctx}; |
| 139 | const u64 posix_time = rp.Pop<u64>(); | 139 | const u64 posix_time = rp.Pop<u64>(); |
| 140 | 140 | ||
| 141 | NGLOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); | 141 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); |
| 142 | 142 | ||
| 143 | CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; | 143 | CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; |
| 144 | CalendarAdditionalInfo additional_info{}; | 144 | CalendarAdditionalInfo additional_info{}; |
| @@ -176,35 +176,35 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct | |||
| 176 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 176 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 177 | rb.Push(RESULT_SUCCESS); | 177 | rb.Push(RESULT_SUCCESS); |
| 178 | rb.PushIpcInterface<ISystemClock>(); | 178 | rb.PushIpcInterface<ISystemClock>(); |
| 179 | NGLOG_DEBUG(Service_Time, "called"); | 179 | LOG_DEBUG(Service_Time, "called"); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { | 182 | void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { |
| 183 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 183 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 184 | rb.Push(RESULT_SUCCESS); | 184 | rb.Push(RESULT_SUCCESS); |
| 185 | rb.PushIpcInterface<ISystemClock>(); | 185 | rb.PushIpcInterface<ISystemClock>(); |
| 186 | NGLOG_DEBUG(Service_Time, "called"); | 186 | LOG_DEBUG(Service_Time, "called"); |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { | 189 | void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { |
| 190 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 190 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 191 | rb.Push(RESULT_SUCCESS); | 191 | rb.Push(RESULT_SUCCESS); |
| 192 | rb.PushIpcInterface<ISteadyClock>(); | 192 | rb.PushIpcInterface<ISteadyClock>(); |
| 193 | NGLOG_DEBUG(Service_Time, "called"); | 193 | LOG_DEBUG(Service_Time, "called"); |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { | 196 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { |
| 197 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 197 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 198 | rb.Push(RESULT_SUCCESS); | 198 | rb.Push(RESULT_SUCCESS); |
| 199 | rb.PushIpcInterface<ITimeZoneService>(); | 199 | rb.PushIpcInterface<ITimeZoneService>(); |
| 200 | NGLOG_DEBUG(Service_Time, "called"); | 200 | LOG_DEBUG(Service_Time, "called"); |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { | 203 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { |
| 204 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 204 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 205 | rb.Push(RESULT_SUCCESS); | 205 | rb.Push(RESULT_SUCCESS); |
| 206 | rb.PushIpcInterface<ISystemClock>(); | 206 | rb.PushIpcInterface<ISystemClock>(); |
| 207 | NGLOG_DEBUG(Service_Time, "called"); | 207 | LOG_DEBUG(Service_Time, "called"); |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) | 210 | Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index e86556671..f3765b555 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -470,7 +470,7 @@ private: | |||
| 470 | u32 flags = rp.Pop<u32>(); | 470 | u32 flags = rp.Pop<u32>(); |
| 471 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | 471 | auto buffer_queue = nv_flinger->GetBufferQueue(id); |
| 472 | 472 | ||
| 473 | NGLOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); | 473 | LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); |
| 474 | 474 | ||
| 475 | if (transaction == TransactionId::Connect) { | 475 | if (transaction == TransactionId::Connect) { |
| 476 | IGBPConnectRequestParcel request{ctx.ReadBuffer()}; | 476 | IGBPConnectRequestParcel request{ctx.ReadBuffer()}; |
| @@ -532,7 +532,7 @@ private: | |||
| 532 | IGBPQueryResponseParcel response{value}; | 532 | IGBPQueryResponseParcel response{value}; |
| 533 | ctx.WriteBuffer(response.Serialize()); | 533 | ctx.WriteBuffer(response.Serialize()); |
| 534 | } else if (transaction == TransactionId::CancelBuffer) { | 534 | } else if (transaction == TransactionId::CancelBuffer) { |
| 535 | NGLOG_WARNING(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); | 535 | LOG_WARNING(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); |
| 536 | } else { | 536 | } else { |
| 537 | ASSERT_MSG(false, "Unimplemented"); | 537 | ASSERT_MSG(false, "Unimplemented"); |
| 538 | } | 538 | } |
| @@ -547,8 +547,8 @@ private: | |||
| 547 | s32 addval = rp.PopRaw<s32>(); | 547 | s32 addval = rp.PopRaw<s32>(); |
| 548 | u32 type = rp.Pop<u32>(); | 548 | u32 type = rp.Pop<u32>(); |
| 549 | 549 | ||
| 550 | NGLOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, | 550 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, |
| 551 | type); | 551 | type); |
| 552 | IPC::ResponseBuilder rb{ctx, 2}; | 552 | IPC::ResponseBuilder rb{ctx, 2}; |
| 553 | rb.Push(RESULT_SUCCESS); | 553 | rb.Push(RESULT_SUCCESS); |
| 554 | } | 554 | } |
| @@ -562,7 +562,7 @@ private: | |||
| 562 | 562 | ||
| 563 | // TODO(Subv): Find out what this actually is. | 563 | // TODO(Subv): Find out what this actually is. |
| 564 | 564 | ||
| 565 | NGLOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); | 565 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); |
| 566 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 566 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 567 | rb.Push(RESULT_SUCCESS); | 567 | rb.Push(RESULT_SUCCESS); |
| 568 | rb.PushCopyObjects(buffer_queue->GetNativeHandle()); | 568 | rb.PushCopyObjects(buffer_queue->GetNativeHandle()); |
| @@ -625,7 +625,7 @@ public: | |||
| 625 | 625 | ||
| 626 | private: | 626 | private: |
| 627 | void SetLayerZ(Kernel::HLERequestContext& ctx) { | 627 | void SetLayerZ(Kernel::HLERequestContext& ctx) { |
| 628 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 628 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 629 | IPC::RequestParser rp{ctx}; | 629 | IPC::RequestParser rp{ctx}; |
| 630 | u64 layer_id = rp.Pop<u64>(); | 630 | u64 layer_id = rp.Pop<u64>(); |
| 631 | u64 z_value = rp.Pop<u64>(); | 631 | u64 z_value = rp.Pop<u64>(); |
| @@ -640,8 +640,8 @@ private: | |||
| 640 | bool visibility = rp.Pop<bool>(); | 640 | bool visibility = rp.Pop<bool>(); |
| 641 | IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); | 641 | IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); |
| 642 | rb.Push(RESULT_SUCCESS); | 642 | rb.Push(RESULT_SUCCESS); |
| 643 | NGLOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, | 643 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, |
| 644 | visibility); | 644 | visibility); |
| 645 | } | 645 | } |
| 646 | }; | 646 | }; |
| 647 | 647 | ||
| @@ -723,7 +723,7 @@ public: | |||
| 723 | 723 | ||
| 724 | private: | 724 | private: |
| 725 | void CloseDisplay(Kernel::HLERequestContext& ctx) { | 725 | void CloseDisplay(Kernel::HLERequestContext& ctx) { |
| 726 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 726 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 727 | IPC::RequestParser rp{ctx}; | 727 | IPC::RequestParser rp{ctx}; |
| 728 | u64 display = rp.Pop<u64>(); | 728 | u64 display = rp.Pop<u64>(); |
| 729 | 729 | ||
| @@ -732,7 +732,7 @@ private: | |||
| 732 | } | 732 | } |
| 733 | 733 | ||
| 734 | void CreateManagedLayer(Kernel::HLERequestContext& ctx) { | 734 | void CreateManagedLayer(Kernel::HLERequestContext& ctx) { |
| 735 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 735 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 736 | IPC::RequestParser rp{ctx}; | 736 | IPC::RequestParser rp{ctx}; |
| 737 | u32 unknown = rp.Pop<u32>(); | 737 | u32 unknown = rp.Pop<u32>(); |
| 738 | rp.Skip(1, false); | 738 | rp.Skip(1, false); |
| @@ -747,7 +747,7 @@ private: | |||
| 747 | } | 747 | } |
| 748 | 748 | ||
| 749 | void AddToLayerStack(Kernel::HLERequestContext& ctx) { | 749 | void AddToLayerStack(Kernel::HLERequestContext& ctx) { |
| 750 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 750 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 751 | IPC::RequestParser rp{ctx}; | 751 | IPC::RequestParser rp{ctx}; |
| 752 | u32 stack = rp.Pop<u32>(); | 752 | u32 stack = rp.Pop<u32>(); |
| 753 | u64 layer_id = rp.Pop<u64>(); | 753 | u64 layer_id = rp.Pop<u64>(); |
| @@ -762,8 +762,8 @@ private: | |||
| 762 | bool visibility = rp.Pop<bool>(); | 762 | bool visibility = rp.Pop<bool>(); |
| 763 | IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); | 763 | IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); |
| 764 | rb.Push(RESULT_SUCCESS); | 764 | rb.Push(RESULT_SUCCESS); |
| 765 | NGLOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, | 765 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, |
| 766 | visibility); | 766 | visibility); |
| 767 | } | 767 | } |
| 768 | 768 | ||
| 769 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 769 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; |
| @@ -776,7 +776,7 @@ public: | |||
| 776 | 776 | ||
| 777 | private: | 777 | private: |
| 778 | void GetRelayService(Kernel::HLERequestContext& ctx) { | 778 | void GetRelayService(Kernel::HLERequestContext& ctx) { |
| 779 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 779 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 780 | 780 | ||
| 781 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 781 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 782 | rb.Push(RESULT_SUCCESS); | 782 | rb.Push(RESULT_SUCCESS); |
| @@ -784,7 +784,7 @@ private: | |||
| 784 | } | 784 | } |
| 785 | 785 | ||
| 786 | void GetSystemDisplayService(Kernel::HLERequestContext& ctx) { | 786 | void GetSystemDisplayService(Kernel::HLERequestContext& ctx) { |
| 787 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 787 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 788 | 788 | ||
| 789 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 789 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 790 | rb.Push(RESULT_SUCCESS); | 790 | rb.Push(RESULT_SUCCESS); |
| @@ -792,7 +792,7 @@ private: | |||
| 792 | } | 792 | } |
| 793 | 793 | ||
| 794 | void GetManagerDisplayService(Kernel::HLERequestContext& ctx) { | 794 | void GetManagerDisplayService(Kernel::HLERequestContext& ctx) { |
| 795 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 795 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 796 | 796 | ||
| 797 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 797 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 798 | rb.Push(RESULT_SUCCESS); | 798 | rb.Push(RESULT_SUCCESS); |
| @@ -800,7 +800,7 @@ private: | |||
| 800 | } | 800 | } |
| 801 | 801 | ||
| 802 | void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx) { | 802 | void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx) { |
| 803 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 803 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 804 | 804 | ||
| 805 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 805 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 806 | rb.Push(RESULT_SUCCESS); | 806 | rb.Push(RESULT_SUCCESS); |
| @@ -808,7 +808,7 @@ private: | |||
| 808 | } | 808 | } |
| 809 | 809 | ||
| 810 | void OpenDisplay(Kernel::HLERequestContext& ctx) { | 810 | void OpenDisplay(Kernel::HLERequestContext& ctx) { |
| 811 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 811 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 812 | IPC::RequestParser rp{ctx}; | 812 | IPC::RequestParser rp{ctx}; |
| 813 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); | 813 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); |
| 814 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | 814 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); |
| @@ -823,7 +823,7 @@ private: | |||
| 823 | } | 823 | } |
| 824 | 824 | ||
| 825 | void CloseDisplay(Kernel::HLERequestContext& ctx) { | 825 | void CloseDisplay(Kernel::HLERequestContext& ctx) { |
| 826 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 826 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 827 | IPC::RequestParser rp{ctx}; | 827 | IPC::RequestParser rp{ctx}; |
| 828 | u64 display_id = rp.Pop<u64>(); | 828 | u64 display_id = rp.Pop<u64>(); |
| 829 | 829 | ||
| @@ -832,7 +832,7 @@ private: | |||
| 832 | } | 832 | } |
| 833 | 833 | ||
| 834 | void GetDisplayResolution(Kernel::HLERequestContext& ctx) { | 834 | void GetDisplayResolution(Kernel::HLERequestContext& ctx) { |
| 835 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 835 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 836 | IPC::RequestParser rp{ctx}; | 836 | IPC::RequestParser rp{ctx}; |
| 837 | u64 display_id = rp.Pop<u64>(); | 837 | u64 display_id = rp.Pop<u64>(); |
| 838 | 838 | ||
| @@ -849,7 +849,7 @@ private: | |||
| 849 | } | 849 | } |
| 850 | 850 | ||
| 851 | void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { | 851 | void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { |
| 852 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 852 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 853 | IPC::RequestParser rp{ctx}; | 853 | IPC::RequestParser rp{ctx}; |
| 854 | u32 scaling_mode = rp.Pop<u32>(); | 854 | u32 scaling_mode = rp.Pop<u32>(); |
| 855 | u64 unknown = rp.Pop<u64>(); | 855 | u64 unknown = rp.Pop<u64>(); |
| @@ -865,11 +865,11 @@ private: | |||
| 865 | IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); | 865 | IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); |
| 866 | rb.Push(RESULT_SUCCESS); | 866 | rb.Push(RESULT_SUCCESS); |
| 867 | rb.Push<u64>(1); | 867 | rb.Push<u64>(1); |
| 868 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 868 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 869 | } | 869 | } |
| 870 | 870 | ||
| 871 | void OpenLayer(Kernel::HLERequestContext& ctx) { | 871 | void OpenLayer(Kernel::HLERequestContext& ctx) { |
| 872 | NGLOG_DEBUG(Service_VI, "called"); | 872 | LOG_DEBUG(Service_VI, "called"); |
| 873 | IPC::RequestParser rp{ctx}; | 873 | IPC::RequestParser rp{ctx}; |
| 874 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); | 874 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); |
| 875 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | 875 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); |
| @@ -889,7 +889,7 @@ private: | |||
| 889 | } | 889 | } |
| 890 | 890 | ||
| 891 | void CreateStrayLayer(Kernel::HLERequestContext& ctx) { | 891 | void CreateStrayLayer(Kernel::HLERequestContext& ctx) { |
| 892 | NGLOG_DEBUG(Service_VI, "called"); | 892 | LOG_DEBUG(Service_VI, "called"); |
| 893 | 893 | ||
| 894 | IPC::RequestParser rp{ctx}; | 894 | IPC::RequestParser rp{ctx}; |
| 895 | u32 flags = rp.Pop<u32>(); | 895 | u32 flags = rp.Pop<u32>(); |
| @@ -909,7 +909,7 @@ private: | |||
| 909 | } | 909 | } |
| 910 | 910 | ||
| 911 | void DestroyStrayLayer(Kernel::HLERequestContext& ctx) { | 911 | void DestroyStrayLayer(Kernel::HLERequestContext& ctx) { |
| 912 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 912 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 913 | 913 | ||
| 914 | IPC::RequestParser rp{ctx}; | 914 | IPC::RequestParser rp{ctx}; |
| 915 | u64 layer_id = rp.Pop<u64>(); | 915 | u64 layer_id = rp.Pop<u64>(); |
| @@ -919,7 +919,7 @@ private: | |||
| 919 | } | 919 | } |
| 920 | 920 | ||
| 921 | void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { | 921 | void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { |
| 922 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 922 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 923 | IPC::RequestParser rp{ctx}; | 923 | IPC::RequestParser rp{ctx}; |
| 924 | u64 display_id = rp.Pop<u64>(); | 924 | u64 display_id = rp.Pop<u64>(); |
| 925 | 925 | ||
| @@ -968,7 +968,7 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name, | |||
| 968 | : ServiceFramework(name), module(std::move(module)), nv_flinger(std::move(nv_flinger)) {} | 968 | : ServiceFramework(name), module(std::move(module)), nv_flinger(std::move(nv_flinger)) {} |
| 969 | 969 | ||
| 970 | void Module::Interface::GetDisplayService(Kernel::HLERequestContext& ctx) { | 970 | void Module::Interface::GetDisplayService(Kernel::HLERequestContext& ctx) { |
| 971 | NGLOG_WARNING(Service_VI, "(STUBBED) called"); | 971 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 972 | 972 | ||
| 973 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 973 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 974 | rb.Push(RESULT_SUCCESS); | 974 | rb.Push(RESULT_SUCCESS); |
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index 8fc91dc9c..2f48068c1 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp | |||
| @@ -33,7 +33,7 @@ inline void Read(T& var, const u32 addr) { | |||
| 33 | LCD::Read(var, addr); | 33 | LCD::Read(var, addr); |
| 34 | break; | 34 | break; |
| 35 | default: | 35 | default: |
| 36 | NGLOG_ERROR(HW_Memory, "Unknown Read{} @ 0x{:08X}", sizeof(var) * 8, addr); | 36 | LOG_ERROR(HW_Memory, "Unknown Read{} @ 0x{:08X}", sizeof(var) * 8, addr); |
| 37 | break; | 37 | break; |
| 38 | } | 38 | } |
| 39 | } | 39 | } |
| @@ -62,7 +62,7 @@ inline void Write(u32 addr, const T data) { | |||
| 62 | LCD::Write(addr, data); | 62 | LCD::Write(addr, data); |
| 63 | break; | 63 | break; |
| 64 | default: | 64 | default: |
| 65 | NGLOG_ERROR(HW_Memory, "Unknown Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, data, addr); | 65 | LOG_ERROR(HW_Memory, "Unknown Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, data, addr); |
| 66 | break; | 66 | break; |
| 67 | } | 67 | } |
| 68 | } | 68 | } |
| @@ -85,12 +85,12 @@ void Update() {} | |||
| 85 | /// Initialize hardware | 85 | /// Initialize hardware |
| 86 | void Init() { | 86 | void Init() { |
| 87 | LCD::Init(); | 87 | LCD::Init(); |
| 88 | NGLOG_DEBUG(HW, "Initialized OK"); | 88 | LOG_DEBUG(HW, "Initialized OK"); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | /// Shutdown hardware | 91 | /// Shutdown hardware |
| 92 | void Shutdown() { | 92 | void Shutdown() { |
| 93 | LCD::Shutdown(); | 93 | LCD::Shutdown(); |
| 94 | NGLOG_DEBUG(HW, "Shutdown OK"); | 94 | LOG_DEBUG(HW, "Shutdown OK"); |
| 95 | } | 95 | } |
| 96 | } // namespace HW | 96 | } // namespace HW |
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp index e8525efde..0b62174d5 100644 --- a/src/core/hw/lcd.cpp +++ b/src/core/hw/lcd.cpp | |||
| @@ -20,7 +20,7 @@ inline void Read(T& var, const u32 raw_addr) { | |||
| 20 | 20 | ||
| 21 | // Reads other than u32 are untested, so I'd rather have them abort than silently fail | 21 | // Reads other than u32 are untested, so I'd rather have them abort than silently fail |
| 22 | if (index >= 0x400 || !std::is_same<T, u32>::value) { | 22 | if (index >= 0x400 || !std::is_same<T, u32>::value) { |
| 23 | NGLOG_ERROR(HW_LCD, "Unknown Read{} @ 0x{:08X}", sizeof(var) * 8, addr); | 23 | LOG_ERROR(HW_LCD, "Unknown Read{} @ 0x{:08X}", sizeof(var) * 8, addr); |
| 24 | return; | 24 | return; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| @@ -34,7 +34,7 @@ inline void Write(u32 addr, const T data) { | |||
| 34 | 34 | ||
| 35 | // Writes other than u32 are untested, so I'd rather have them abort than silently fail | 35 | // Writes other than u32 are untested, so I'd rather have them abort than silently fail |
| 36 | if (index >= 0x400 || !std::is_same<T, u32>::value) { | 36 | if (index >= 0x400 || !std::is_same<T, u32>::value) { |
| 37 | NGLOG_ERROR(HW_LCD, "Unknown Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, data, addr); | 37 | LOG_ERROR(HW_LCD, "Unknown Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, data, addr); |
| 38 | return; | 38 | return; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| @@ -56,12 +56,12 @@ template void Write<u8>(u32 addr, const u8 data); | |||
| 56 | /// Initialize hardware | 56 | /// Initialize hardware |
| 57 | void Init() { | 57 | void Init() { |
| 58 | memset(&g_regs, 0, sizeof(g_regs)); | 58 | memset(&g_regs, 0, sizeof(g_regs)); |
| 59 | NGLOG_DEBUG(HW_LCD, "Initialized OK"); | 59 | LOG_DEBUG(HW_LCD, "Initialized OK"); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | /// Shutdown hardware | 62 | /// Shutdown hardware |
| 63 | void Shutdown() { | 63 | void Shutdown() { |
| 64 | NGLOG_DEBUG(HW_LCD, "Shutdown OK"); | 64 | LOG_DEBUG(HW_LCD, "Shutdown OK"); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | } // namespace LCD | 67 | } // namespace LCD |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index b01b2caf6..eb7feb617 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -132,7 +132,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( | |||
| 132 | const VAddr load_addr = next_load_addr; | 132 | const VAddr load_addr = next_load_addr; |
| 133 | next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); | 133 | next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); |
| 134 | if (next_load_addr) { | 134 | if (next_load_addr) { |
| 135 | NGLOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); | 135 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); |
| 136 | } else { | 136 | } else { |
| 137 | next_load_addr = load_addr; | 137 | next_load_addr = load_addr; |
| 138 | } | 138 | } |
| @@ -163,7 +163,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS( | |||
| 163 | std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { | 163 | std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { |
| 164 | 164 | ||
| 165 | if (filepath_romfs.empty()) { | 165 | if (filepath_romfs.empty()) { |
| 166 | NGLOG_DEBUG(Loader, "No RomFS available"); | 166 | LOG_DEBUG(Loader, "No RomFS available"); |
| 167 | return ResultStatus::ErrorNotUsed; | 167 | return ResultStatus::ErrorNotUsed; |
| 168 | } | 168 | } |
| 169 | 169 | ||
| @@ -176,8 +176,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS( | |||
| 176 | offset = 0; | 176 | offset = 0; |
| 177 | size = romfs_file->GetSize(); | 177 | size = romfs_file->GetSize(); |
| 178 | 178 | ||
| 179 | NGLOG_DEBUG(Loader, "RomFS offset: 0x{:016X}", offset); | 179 | LOG_DEBUG(Loader, "RomFS offset: 0x{:016X}", offset); |
| 180 | NGLOG_DEBUG(Loader, "RomFS size: 0x{:016X}", size); | 180 | LOG_DEBUG(Loader, "RomFS size: 0x{:016X}", size); |
| 181 | 181 | ||
| 182 | // Reset read pointer | 182 | // Reset read pointer |
| 183 | file.Seek(0, SEEK_SET); | 183 | file.Seek(0, SEEK_SET); |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index e42d3a870..b69e5c6ef 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -273,18 +273,18 @@ const char* ElfReader::GetSectionName(int section) const { | |||
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | 275 | SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { |
| 276 | NGLOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); | 276 | LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); |
| 277 | 277 | ||
| 278 | // Should we relocate? | 278 | // Should we relocate? |
| 279 | relocate = (header->e_type != ET_EXEC); | 279 | relocate = (header->e_type != ET_EXEC); |
| 280 | 280 | ||
| 281 | if (relocate) { | 281 | if (relocate) { |
| 282 | NGLOG_DEBUG(Loader, "Relocatable module"); | 282 | LOG_DEBUG(Loader, "Relocatable module"); |
| 283 | entryPoint += vaddr; | 283 | entryPoint += vaddr; |
| 284 | } else { | 284 | } else { |
| 285 | NGLOG_DEBUG(Loader, "Prerelocated executable"); | 285 | LOG_DEBUG(Loader, "Prerelocated executable"); |
| 286 | } | 286 | } |
| 287 | NGLOG_DEBUG(Loader, "{} segments:", header->e_phnum); | 287 | LOG_DEBUG(Loader, "{} segments:", header->e_phnum); |
| 288 | 288 | ||
| 289 | // First pass : Get the bits into RAM | 289 | // First pass : Get the bits into RAM |
| 290 | u32 base_addr = relocate ? vaddr : 0; | 290 | u32 base_addr = relocate ? vaddr : 0; |
| @@ -304,8 +304,8 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | |||
| 304 | 304 | ||
| 305 | for (unsigned int i = 0; i < header->e_phnum; ++i) { | 305 | for (unsigned int i = 0; i < header->e_phnum; ++i) { |
| 306 | Elf32_Phdr* p = &segments[i]; | 306 | Elf32_Phdr* p = &segments[i]; |
| 307 | NGLOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, | 307 | LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, |
| 308 | p->p_vaddr, p->p_filesz, p->p_memsz); | 308 | p->p_vaddr, p->p_filesz, p->p_memsz); |
| 309 | 309 | ||
| 310 | if (p->p_type == PT_LOAD) { | 310 | if (p->p_type == PT_LOAD) { |
| 311 | CodeSet::Segment* codeset_segment; | 311 | CodeSet::Segment* codeset_segment; |
| @@ -317,16 +317,16 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | |||
| 317 | } else if (permission_flags == (PF_R | PF_W)) { | 317 | } else if (permission_flags == (PF_R | PF_W)) { |
| 318 | codeset_segment = &codeset->data; | 318 | codeset_segment = &codeset->data; |
| 319 | } else { | 319 | } else { |
| 320 | NGLOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i, | 320 | LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i, |
| 321 | p->p_flags); | 321 | p->p_flags); |
| 322 | continue; | 322 | continue; |
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | if (codeset_segment->size != 0) { | 325 | if (codeset_segment->size != 0) { |
| 326 | NGLOG_ERROR(Loader, | 326 | LOG_ERROR(Loader, |
| 327 | "ELF has more than one segment of the same type. Skipping extra " | 327 | "ELF has more than one segment of the same type. Skipping extra " |
| 328 | "segment (id {})", | 328 | "segment (id {})", |
| 329 | i); | 329 | i); |
| 330 | continue; | 330 | continue; |
| 331 | } | 331 | } |
| 332 | 332 | ||
| @@ -345,7 +345,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | |||
| 345 | codeset->entrypoint = base_addr + header->e_entry; | 345 | codeset->entrypoint = base_addr + header->e_entry; |
| 346 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 346 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 347 | 347 | ||
| 348 | NGLOG_DEBUG(Loader, "Done loading."); | 348 | LOG_DEBUG(Loader, "Done loading."); |
| 349 | 349 | ||
| 350 | return codeset; | 350 | return codeset; |
| 351 | } | 351 | } |
diff --git a/src/core/loader/linker.cpp b/src/core/loader/linker.cpp index c7be5f265..769516b6f 100644 --- a/src/core/loader/linker.cpp +++ b/src/core/loader/linker.cpp | |||
| @@ -84,7 +84,7 @@ void Linker::WriteRelocations(std::vector<u8>& program_image, const std::vector< | |||
| 84 | } | 84 | } |
| 85 | break; | 85 | break; |
| 86 | default: | 86 | default: |
| 87 | NGLOG_CRITICAL(Loader, "Unknown relocation type: {}", static_cast<int>(rela.type)); | 87 | LOG_CRITICAL(Loader, "Unknown relocation type: {}", static_cast<int>(rela.type)); |
| 88 | break; | 88 | break; |
| 89 | } | 89 | } |
| 90 | } | 90 | } |
| @@ -141,7 +141,7 @@ void Linker::ResolveImports() { | |||
| 141 | if (search != exports.end()) { | 141 | if (search != exports.end()) { |
| 142 | Memory::Write64(import.second.ea, search->second + import.second.addend); | 142 | Memory::Write64(import.second.ea, search->second + import.second.addend); |
| 143 | } else { | 143 | } else { |
| 144 | NGLOG_ERROR(Loader, "Unresolved import: {}", import.first); | 144 | LOG_ERROR(Loader, "Unresolved import: {}", import.first); |
| 145 | } | 145 | } |
| 146 | } | 146 | } |
| 147 | } | 147 | } |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 6a4fd38cb..8831d8e83 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/hle/kernel/process.h" | 9 | #include "core/hle/kernel/process.h" |
| 10 | #include "core/loader/deconstructed_rom_directory.h" | 10 | #include "core/loader/deconstructed_rom_directory.h" |
| 11 | #include "core/loader/elf.h" | 11 | #include "core/loader/elf.h" |
| 12 | #include "core/loader/nca.h" | ||
| 12 | #include "core/loader/nro.h" | 13 | #include "core/loader/nro.h" |
| 13 | #include "core/loader/nso.h" | 14 | #include "core/loader/nso.h" |
| 14 | 15 | ||
| @@ -32,6 +33,7 @@ FileType IdentifyFile(FileUtil::IOFile& file, const std::string& filepath) { | |||
| 32 | CHECK_TYPE(ELF) | 33 | CHECK_TYPE(ELF) |
| 33 | CHECK_TYPE(NSO) | 34 | CHECK_TYPE(NSO) |
| 34 | CHECK_TYPE(NRO) | 35 | CHECK_TYPE(NRO) |
| 36 | CHECK_TYPE(NCA) | ||
| 35 | 37 | ||
| 36 | #undef CHECK_TYPE | 38 | #undef CHECK_TYPE |
| 37 | 39 | ||
| @@ -41,7 +43,7 @@ FileType IdentifyFile(FileUtil::IOFile& file, const std::string& filepath) { | |||
| 41 | FileType IdentifyFile(const std::string& file_name) { | 43 | FileType IdentifyFile(const std::string& file_name) { |
| 42 | FileUtil::IOFile file(file_name, "rb"); | 44 | FileUtil::IOFile file(file_name, "rb"); |
| 43 | if (!file.IsOpen()) { | 45 | if (!file.IsOpen()) { |
| 44 | NGLOG_ERROR(Loader, "Failed to load file {}", file_name); | 46 | LOG_ERROR(Loader, "Failed to load file {}", file_name); |
| 45 | return FileType::Unknown; | 47 | return FileType::Unknown; |
| 46 | } | 48 | } |
| 47 | 49 | ||
| @@ -57,6 +59,8 @@ FileType GuessFromExtension(const std::string& extension_) { | |||
| 57 | return FileType::NRO; | 59 | return FileType::NRO; |
| 58 | else if (extension == ".nso") | 60 | else if (extension == ".nso") |
| 59 | return FileType::NSO; | 61 | return FileType::NSO; |
| 62 | else if (extension == ".nca") | ||
| 63 | return FileType::NCA; | ||
| 60 | 64 | ||
| 61 | return FileType::Unknown; | 65 | return FileType::Unknown; |
| 62 | } | 66 | } |
| @@ -69,6 +73,8 @@ const char* GetFileTypeString(FileType type) { | |||
| 69 | return "NRO"; | 73 | return "NRO"; |
| 70 | case FileType::NSO: | 74 | case FileType::NSO: |
| 71 | return "NSO"; | 75 | return "NSO"; |
| 76 | case FileType::NCA: | ||
| 77 | return "NCA"; | ||
| 72 | case FileType::DeconstructedRomDirectory: | 78 | case FileType::DeconstructedRomDirectory: |
| 73 | return "Directory"; | 79 | return "Directory"; |
| 74 | case FileType::Error: | 80 | case FileType::Error: |
| @@ -104,6 +110,10 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileUtil::IOFile&& file, FileTyp | |||
| 104 | case FileType::NRO: | 110 | case FileType::NRO: |
| 105 | return std::make_unique<AppLoader_NRO>(std::move(file), filepath); | 111 | return std::make_unique<AppLoader_NRO>(std::move(file), filepath); |
| 106 | 112 | ||
| 113 | // NX NCA file format. | ||
| 114 | case FileType::NCA: | ||
| 115 | return std::make_unique<AppLoader_NCA>(std::move(file), filepath); | ||
| 116 | |||
| 107 | // NX deconstructed ROM directory. | 117 | // NX deconstructed ROM directory. |
| 108 | case FileType::DeconstructedRomDirectory: | 118 | case FileType::DeconstructedRomDirectory: |
| 109 | return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file), filepath); | 119 | return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file), filepath); |
| @@ -116,7 +126,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileUtil::IOFile&& file, FileTyp | |||
| 116 | std::unique_ptr<AppLoader> GetLoader(const std::string& filename) { | 126 | std::unique_ptr<AppLoader> GetLoader(const std::string& filename) { |
| 117 | FileUtil::IOFile file(filename, "rb"); | 127 | FileUtil::IOFile file(filename, "rb"); |
| 118 | if (!file.IsOpen()) { | 128 | if (!file.IsOpen()) { |
| 119 | NGLOG_ERROR(Loader, "Failed to load file {}", filename); | 129 | LOG_ERROR(Loader, "Failed to load file {}", filename); |
| 120 | return nullptr; | 130 | return nullptr; |
| 121 | } | 131 | } |
| 122 | 132 | ||
| @@ -127,12 +137,12 @@ std::unique_ptr<AppLoader> GetLoader(const std::string& filename) { | |||
| 127 | FileType filename_type = GuessFromExtension(filename_extension); | 137 | FileType filename_type = GuessFromExtension(filename_extension); |
| 128 | 138 | ||
| 129 | if (type != filename_type) { | 139 | if (type != filename_type) { |
| 130 | NGLOG_WARNING(Loader, "File {} has a different type than its extension.", filename); | 140 | LOG_WARNING(Loader, "File {} has a different type than its extension.", filename); |
| 131 | if (FileType::Unknown == type) | 141 | if (FileType::Unknown == type) |
| 132 | type = filename_type; | 142 | type = filename_type; |
| 133 | } | 143 | } |
| 134 | 144 | ||
| 135 | NGLOG_DEBUG(Loader, "Loading file {} as {}...", filename, GetFileTypeString(type)); | 145 | LOG_DEBUG(Loader, "Loading file {} as {}...", filename, GetFileTypeString(type)); |
| 136 | 146 | ||
| 137 | return GetFileLoader(std::move(file), type, filename_filename, filename); | 147 | return GetFileLoader(std::move(file), type, filename_filename, filename); |
| 138 | } | 148 | } |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index b1aabb1cb..b76f7b13d 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -29,6 +29,7 @@ enum class FileType { | |||
| 29 | ELF, | 29 | ELF, |
| 30 | NSO, | 30 | NSO, |
| 31 | NRO, | 31 | NRO, |
| 32 | NCA, | ||
| 32 | DeconstructedRomDirectory, | 33 | DeconstructedRomDirectory, |
| 33 | }; | 34 | }; |
| 34 | 35 | ||
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp new file mode 100644 index 000000000..da064f8e3 --- /dev/null +++ b/src/core/loader/nca.cpp | |||
| @@ -0,0 +1,303 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <vector> | ||
| 6 | |||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | #include "common/logging/log.h" | ||
| 10 | #include "common/swap.h" | ||
| 11 | #include "core/core.h" | ||
| 12 | #include "core/file_sys/program_metadata.h" | ||
| 13 | #include "core/file_sys/romfs_factory.h" | ||
| 14 | #include "core/hle/kernel/process.h" | ||
| 15 | #include "core/hle/kernel/resource_limit.h" | ||
| 16 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 17 | #include "core/loader/nca.h" | ||
| 18 | #include "core/loader/nso.h" | ||
| 19 | #include "core/memory.h" | ||
| 20 | |||
| 21 | namespace Loader { | ||
| 22 | |||
| 23 | // Media offsets in headers are stored divided by 512. Mult. by this to get real offset. | ||
| 24 | constexpr u64 MEDIA_OFFSET_MULTIPLIER = 0x200; | ||
| 25 | |||
| 26 | constexpr u64 SECTION_HEADER_SIZE = 0x200; | ||
| 27 | constexpr u64 SECTION_HEADER_OFFSET = 0x400; | ||
| 28 | |||
| 29 | enum class NcaContentType : u8 { Program = 0, Meta = 1, Control = 2, Manual = 3, Data = 4 }; | ||
| 30 | |||
| 31 | enum class NcaSectionFilesystemType : u8 { PFS0 = 0x2, ROMFS = 0x3 }; | ||
| 32 | |||
| 33 | struct NcaSectionTableEntry { | ||
| 34 | u32_le media_offset; | ||
| 35 | u32_le media_end_offset; | ||
| 36 | INSERT_PADDING_BYTES(0x8); | ||
| 37 | }; | ||
| 38 | static_assert(sizeof(NcaSectionTableEntry) == 0x10, "NcaSectionTableEntry has incorrect size."); | ||
| 39 | |||
| 40 | struct NcaHeader { | ||
| 41 | std::array<u8, 0x100> rsa_signature_1; | ||
| 42 | std::array<u8, 0x100> rsa_signature_2; | ||
| 43 | u32_le magic; | ||
| 44 | u8 is_system; | ||
| 45 | NcaContentType content_type; | ||
| 46 | u8 crypto_type; | ||
| 47 | u8 key_index; | ||
| 48 | u64_le size; | ||
| 49 | u64_le title_id; | ||
| 50 | INSERT_PADDING_BYTES(0x4); | ||
| 51 | u32_le sdk_version; | ||
| 52 | u8 crypto_type_2; | ||
| 53 | INSERT_PADDING_BYTES(15); | ||
| 54 | std::array<u8, 0x10> rights_id; | ||
| 55 | std::array<NcaSectionTableEntry, 0x4> section_tables; | ||
| 56 | std::array<std::array<u8, 0x20>, 0x4> hash_tables; | ||
| 57 | std::array<std::array<u8, 0x10>, 0x4> key_area; | ||
| 58 | INSERT_PADDING_BYTES(0xC0); | ||
| 59 | }; | ||
| 60 | static_assert(sizeof(NcaHeader) == 0x400, "NcaHeader has incorrect size."); | ||
| 61 | |||
| 62 | struct NcaSectionHeaderBlock { | ||
| 63 | INSERT_PADDING_BYTES(3); | ||
| 64 | NcaSectionFilesystemType filesystem_type; | ||
| 65 | u8 crypto_type; | ||
| 66 | INSERT_PADDING_BYTES(3); | ||
| 67 | }; | ||
| 68 | static_assert(sizeof(NcaSectionHeaderBlock) == 0x8, "NcaSectionHeaderBlock has incorrect size."); | ||
| 69 | |||
| 70 | struct Pfs0Superblock { | ||
| 71 | NcaSectionHeaderBlock header_block; | ||
| 72 | std::array<u8, 0x20> hash; | ||
| 73 | u32_le size; | ||
| 74 | INSERT_PADDING_BYTES(4); | ||
| 75 | u64_le hash_table_offset; | ||
| 76 | u64_le hash_table_size; | ||
| 77 | u64_le pfs0_header_offset; | ||
| 78 | u64_le pfs0_size; | ||
| 79 | INSERT_PADDING_BYTES(432); | ||
| 80 | }; | ||
| 81 | static_assert(sizeof(Pfs0Superblock) == 0x200, "Pfs0Superblock has incorrect size."); | ||
| 82 | |||
| 83 | static bool IsValidNca(const NcaHeader& header) { | ||
| 84 | return header.magic == Common::MakeMagic('N', 'C', 'A', '2') || | ||
| 85 | header.magic == Common::MakeMagic('N', 'C', 'A', '3'); | ||
| 86 | } | ||
| 87 | |||
| 88 | // TODO(DarkLordZach): Add support for encrypted. | ||
| 89 | class Nca final { | ||
| 90 | std::vector<FileSys::PartitionFilesystem> pfs; | ||
| 91 | std::vector<u64> pfs_offset; | ||
| 92 | |||
| 93 | u64 romfs_offset = 0; | ||
| 94 | u64 romfs_size = 0; | ||
| 95 | |||
| 96 | boost::optional<u8> exefs_id = boost::none; | ||
| 97 | |||
| 98 | FileUtil::IOFile file; | ||
| 99 | std::string path; | ||
| 100 | |||
| 101 | u64 GetExeFsFileOffset(const std::string& file_name) const; | ||
| 102 | u64 GetExeFsFileSize(const std::string& file_name) const; | ||
| 103 | |||
| 104 | public: | ||
| 105 | ResultStatus Load(FileUtil::IOFile&& file, std::string path); | ||
| 106 | |||
| 107 | FileSys::PartitionFilesystem GetPfs(u8 id) const; | ||
| 108 | |||
| 109 | u64 GetRomFsOffset() const; | ||
| 110 | u64 GetRomFsSize() const; | ||
| 111 | |||
| 112 | std::vector<u8> GetExeFsFile(const std::string& file_name); | ||
| 113 | }; | ||
| 114 | |||
| 115 | static bool IsPfsExeFs(const FileSys::PartitionFilesystem& pfs) { | ||
| 116 | // According to switchbrew, an exefs must only contain these two files: | ||
| 117 | return pfs.GetFileSize("main") > 0 && pfs.GetFileSize("main.npdm") > 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | ResultStatus Nca::Load(FileUtil::IOFile&& in_file, std::string in_path) { | ||
| 121 | file = std::move(in_file); | ||
| 122 | path = in_path; | ||
| 123 | file.Seek(0, SEEK_SET); | ||
| 124 | std::array<u8, sizeof(NcaHeader)> header_array{}; | ||
| 125 | if (sizeof(NcaHeader) != file.ReadBytes(header_array.data(), sizeof(NcaHeader))) | ||
| 126 | LOG_CRITICAL(Loader, "File reader errored out during header read."); | ||
| 127 | |||
| 128 | NcaHeader header{}; | ||
| 129 | std::memcpy(&header, header_array.data(), sizeof(NcaHeader)); | ||
| 130 | if (!IsValidNca(header)) | ||
| 131 | return ResultStatus::ErrorInvalidFormat; | ||
| 132 | |||
| 133 | int number_sections = | ||
| 134 | std::count_if(std::begin(header.section_tables), std::end(header.section_tables), | ||
| 135 | [](NcaSectionTableEntry entry) { return entry.media_offset > 0; }); | ||
| 136 | |||
| 137 | for (int i = 0; i < number_sections; ++i) { | ||
| 138 | // Seek to beginning of this section. | ||
| 139 | file.Seek(SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE, SEEK_SET); | ||
| 140 | std::array<u8, sizeof(NcaSectionHeaderBlock)> array{}; | ||
| 141 | if (sizeof(NcaSectionHeaderBlock) != | ||
| 142 | file.ReadBytes(array.data(), sizeof(NcaSectionHeaderBlock))) | ||
| 143 | LOG_CRITICAL(Loader, "File reader errored out during header read."); | ||
| 144 | |||
| 145 | NcaSectionHeaderBlock block{}; | ||
| 146 | std::memcpy(&block, array.data(), sizeof(NcaSectionHeaderBlock)); | ||
| 147 | |||
| 148 | if (block.filesystem_type == NcaSectionFilesystemType::ROMFS) { | ||
| 149 | romfs_offset = header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER; | ||
| 150 | romfs_size = | ||
| 151 | header.section_tables[i].media_end_offset * MEDIA_OFFSET_MULTIPLIER - romfs_offset; | ||
| 152 | } else if (block.filesystem_type == NcaSectionFilesystemType::PFS0) { | ||
| 153 | Pfs0Superblock sb{}; | ||
| 154 | // Seek back to beginning of this section. | ||
| 155 | file.Seek(SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE, SEEK_SET); | ||
| 156 | if (sizeof(Pfs0Superblock) != file.ReadBytes(&sb, sizeof(Pfs0Superblock))) | ||
| 157 | LOG_CRITICAL(Loader, "File reader errored out during header read."); | ||
| 158 | |||
| 159 | u64 offset = (static_cast<u64>(header.section_tables[i].media_offset) * | ||
| 160 | MEDIA_OFFSET_MULTIPLIER) + | ||
| 161 | sb.pfs0_header_offset; | ||
| 162 | FileSys::PartitionFilesystem npfs{}; | ||
| 163 | ResultStatus status = npfs.Load(path, offset); | ||
| 164 | |||
| 165 | if (status == ResultStatus::Success) { | ||
| 166 | pfs.emplace_back(std::move(npfs)); | ||
| 167 | pfs_offset.emplace_back(offset); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | for (size_t i = 0; i < pfs.size(); ++i) { | ||
| 173 | if (IsPfsExeFs(pfs[i])) | ||
| 174 | exefs_id = i; | ||
| 175 | } | ||
| 176 | |||
| 177 | return ResultStatus::Success; | ||
| 178 | } | ||
| 179 | |||
| 180 | FileSys::PartitionFilesystem Nca::GetPfs(u8 id) const { | ||
| 181 | return pfs[id]; | ||
| 182 | } | ||
| 183 | |||
| 184 | u64 Nca::GetExeFsFileOffset(const std::string& file_name) const { | ||
| 185 | if (exefs_id == boost::none) | ||
| 186 | return 0; | ||
| 187 | return pfs[*exefs_id].GetFileOffset(file_name) + pfs_offset[*exefs_id]; | ||
| 188 | } | ||
| 189 | |||
| 190 | u64 Nca::GetExeFsFileSize(const std::string& file_name) const { | ||
| 191 | if (exefs_id == boost::none) | ||
| 192 | return 0; | ||
| 193 | return pfs[*exefs_id].GetFileSize(file_name); | ||
| 194 | } | ||
| 195 | |||
| 196 | u64 Nca::GetRomFsOffset() const { | ||
| 197 | return romfs_offset; | ||
| 198 | } | ||
| 199 | |||
| 200 | u64 Nca::GetRomFsSize() const { | ||
| 201 | return romfs_size; | ||
| 202 | } | ||
| 203 | |||
| 204 | std::vector<u8> Nca::GetExeFsFile(const std::string& file_name) { | ||
| 205 | std::vector<u8> out(GetExeFsFileSize(file_name)); | ||
| 206 | file.Seek(GetExeFsFileOffset(file_name), SEEK_SET); | ||
| 207 | file.ReadBytes(out.data(), GetExeFsFileSize(file_name)); | ||
| 208 | return out; | ||
| 209 | } | ||
| 210 | |||
| 211 | AppLoader_NCA::AppLoader_NCA(FileUtil::IOFile&& file, std::string filepath) | ||
| 212 | : AppLoader(std::move(file)), filepath(std::move(filepath)) {} | ||
| 213 | |||
| 214 | FileType AppLoader_NCA::IdentifyType(FileUtil::IOFile& file, const std::string&) { | ||
| 215 | file.Seek(0, SEEK_SET); | ||
| 216 | std::array<u8, 0x400> header_enc_array{}; | ||
| 217 | if (0x400 != file.ReadBytes(header_enc_array.data(), 0x400)) | ||
| 218 | return FileType::Error; | ||
| 219 | |||
| 220 | // TODO(DarkLordZach): Assuming everything is decrypted. Add crypto support. | ||
| 221 | NcaHeader header{}; | ||
| 222 | std::memcpy(&header, header_enc_array.data(), sizeof(NcaHeader)); | ||
| 223 | |||
| 224 | if (IsValidNca(header) && header.content_type == NcaContentType::Program) | ||
| 225 | return FileType::NCA; | ||
| 226 | |||
| 227 | return FileType::Error; | ||
| 228 | } | ||
| 229 | |||
| 230 | ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) { | ||
| 231 | if (is_loaded) { | ||
| 232 | return ResultStatus::ErrorAlreadyLoaded; | ||
| 233 | } | ||
| 234 | if (!file.IsOpen()) { | ||
| 235 | return ResultStatus::Error; | ||
| 236 | } | ||
| 237 | |||
| 238 | nca = std::make_unique<Nca>(); | ||
| 239 | ResultStatus result = nca->Load(std::move(file), filepath); | ||
| 240 | if (result != ResultStatus::Success) { | ||
| 241 | return result; | ||
| 242 | } | ||
| 243 | |||
| 244 | result = metadata.Load(nca->GetExeFsFile("main.npdm")); | ||
| 245 | if (result != ResultStatus::Success) { | ||
| 246 | return result; | ||
| 247 | } | ||
| 248 | metadata.Print(); | ||
| 249 | |||
| 250 | const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; | ||
| 251 | if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) { | ||
| 252 | return ResultStatus::ErrorUnsupportedArch; | ||
| 253 | } | ||
| 254 | |||
| 255 | VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; | ||
| 256 | for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", | ||
| 257 | "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { | ||
| 258 | const VAddr load_addr = next_load_addr; | ||
| 259 | next_load_addr = AppLoader_NSO::LoadModule(module, nca->GetExeFsFile(module), load_addr); | ||
| 260 | if (next_load_addr) { | ||
| 261 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); | ||
| 262 | } else { | ||
| 263 | next_load_addr = load_addr; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | process->program_id = metadata.GetTitleID(); | ||
| 268 | process->svc_access_mask.set(); | ||
| 269 | process->address_mappings = default_address_mappings; | ||
| 270 | process->resource_limit = | ||
| 271 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||
| 272 | process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), | ||
| 273 | metadata.GetMainThreadStackSize()); | ||
| 274 | |||
| 275 | if (nca->GetRomFsSize() > 0) | ||
| 276 | Service::FileSystem::RegisterFileSystem(std::make_unique<FileSys::RomFS_Factory>(*this), | ||
| 277 | Service::FileSystem::Type::RomFS); | ||
| 278 | |||
| 279 | is_loaded = true; | ||
| 280 | return ResultStatus::Success; | ||
| 281 | } | ||
| 282 | |||
| 283 | ResultStatus AppLoader_NCA::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, | ||
| 284 | u64& size) { | ||
| 285 | if (nca->GetRomFsSize() == 0) { | ||
| 286 | LOG_DEBUG(Loader, "No RomFS available"); | ||
| 287 | return ResultStatus::ErrorNotUsed; | ||
| 288 | } | ||
| 289 | |||
| 290 | romfs_file = std::make_shared<FileUtil::IOFile>(filepath, "rb"); | ||
| 291 | |||
| 292 | offset = nca->GetRomFsOffset(); | ||
| 293 | size = nca->GetRomFsSize(); | ||
| 294 | |||
| 295 | LOG_DEBUG(Loader, "RomFS offset: 0x{:016X}", offset); | ||
| 296 | LOG_DEBUG(Loader, "RomFS size: 0x{:016X}", size); | ||
| 297 | |||
| 298 | return ResultStatus::Success; | ||
| 299 | } | ||
| 300 | |||
| 301 | AppLoader_NCA::~AppLoader_NCA() = default; | ||
| 302 | |||
| 303 | } // namespace Loader | ||
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h new file mode 100644 index 000000000..3b6c451d0 --- /dev/null +++ b/src/core/loader/nca.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/file_sys/partition_filesystem.h" | ||
| 10 | #include "core/file_sys/program_metadata.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | #include "core/loader/loader.h" | ||
| 13 | |||
| 14 | namespace Loader { | ||
| 15 | |||
| 16 | class Nca; | ||
| 17 | |||
| 18 | /// Loads an NCA file | ||
| 19 | class AppLoader_NCA final : public AppLoader { | ||
| 20 | public: | ||
| 21 | AppLoader_NCA(FileUtil::IOFile&& file, std::string filepath); | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Returns the type of the file | ||
| 25 | * @param file FileUtil::IOFile open file | ||
| 26 | * @param filepath Path of the file that we are opening. | ||
| 27 | * @return FileType found, or FileType::Error if this loader doesn't know it | ||
| 28 | */ | ||
| 29 | static FileType IdentifyType(FileUtil::IOFile& file, const std::string& filepath); | ||
| 30 | |||
| 31 | FileType GetFileType() override { | ||
| 32 | return IdentifyType(file, filepath); | ||
| 33 | } | ||
| 34 | |||
| 35 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | ||
| 36 | |||
| 37 | ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, | ||
| 38 | u64& size) override; | ||
| 39 | |||
| 40 | ~AppLoader_NCA(); | ||
| 41 | |||
| 42 | private: | ||
| 43 | std::string filepath; | ||
| 44 | FileSys::ProgramMetadata metadata; | ||
| 45 | |||
| 46 | std::unique_ptr<Nca> nca; | ||
| 47 | }; | ||
| 48 | |||
| 49 | } // namespace Loader | ||
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 01be9e217..7f84e4b1b 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -66,22 +66,13 @@ FileType AppLoader_NSO::IdentifyType(FileUtil::IOFile& file, const std::string&) | |||
| 66 | return FileType::Error; | 66 | return FileType::Error; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | static std::vector<u8> ReadSegment(FileUtil::IOFile& file, const NsoSegmentHeader& header, | 69 | static std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data, |
| 70 | int compressed_size) { | 70 | const NsoSegmentHeader& header) { |
| 71 | std::vector<u8> compressed_data; | ||
| 72 | compressed_data.resize(compressed_size); | ||
| 73 | |||
| 74 | file.Seek(header.offset, SEEK_SET); | ||
| 75 | if (compressed_size != file.ReadBytes(compressed_data.data(), compressed_size)) { | ||
| 76 | NGLOG_CRITICAL(Loader, "Failed to read {} NSO LZ4 compressed bytes", compressed_size); | ||
| 77 | return {}; | ||
| 78 | } | ||
| 79 | |||
| 80 | std::vector<u8> uncompressed_data; | 71 | std::vector<u8> uncompressed_data; |
| 81 | uncompressed_data.resize(header.size); | 72 | uncompressed_data.resize(header.size); |
| 82 | const int bytes_uncompressed = LZ4_decompress_safe( | 73 | const int bytes_uncompressed = LZ4_decompress_safe( |
| 83 | reinterpret_cast<const char*>(compressed_data.data()), | 74 | reinterpret_cast<const char*>(compressed_data.data()), |
| 84 | reinterpret_cast<char*>(uncompressed_data.data()), compressed_size, header.size); | 75 | reinterpret_cast<char*>(uncompressed_data.data()), compressed_data.size(), header.size); |
| 85 | 76 | ||
| 86 | ASSERT_MSG(bytes_uncompressed == header.size && bytes_uncompressed == uncompressed_data.size(), | 77 | ASSERT_MSG(bytes_uncompressed == header.size && bytes_uncompressed == uncompressed_data.size(), |
| 87 | "{} != {} != {}", bytes_uncompressed, header.size, uncompressed_data.size()); | 78 | "{} != {} != {}", bytes_uncompressed, header.size, uncompressed_data.size()); |
| @@ -89,10 +80,76 @@ static std::vector<u8> ReadSegment(FileUtil::IOFile& file, const NsoSegmentHeade | |||
| 89 | return uncompressed_data; | 80 | return uncompressed_data; |
| 90 | } | 81 | } |
| 91 | 82 | ||
| 83 | static std::vector<u8> ReadSegment(FileUtil::IOFile& file, const NsoSegmentHeader& header, | ||
| 84 | size_t compressed_size) { | ||
| 85 | std::vector<u8> compressed_data; | ||
| 86 | compressed_data.resize(compressed_size); | ||
| 87 | |||
| 88 | file.Seek(header.offset, SEEK_SET); | ||
| 89 | if (compressed_size != file.ReadBytes(compressed_data.data(), compressed_size)) { | ||
| 90 | LOG_CRITICAL(Loader, "Failed to read {} NSO LZ4 compressed bytes", compressed_size); | ||
| 91 | return {}; | ||
| 92 | } | ||
| 93 | |||
| 94 | return DecompressSegment(compressed_data, header); | ||
| 95 | } | ||
| 96 | |||
| 92 | static constexpr u32 PageAlignSize(u32 size) { | 97 | static constexpr u32 PageAlignSize(u32 size) { |
| 93 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; | 98 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; |
| 94 | } | 99 | } |
| 95 | 100 | ||
| 101 | VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>& file_data, | ||
| 102 | VAddr load_base) { | ||
| 103 | if (file_data.size() < sizeof(NsoHeader)) | ||
| 104 | return {}; | ||
| 105 | |||
| 106 | NsoHeader nso_header; | ||
| 107 | std::memcpy(&nso_header, file_data.data(), sizeof(NsoHeader)); | ||
| 108 | |||
| 109 | if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) | ||
| 110 | return {}; | ||
| 111 | |||
| 112 | // Build program image | ||
| 113 | Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); | ||
| 114 | std::vector<u8> program_image; | ||
| 115 | for (int i = 0; i < nso_header.segments.size(); ++i) { | ||
| 116 | std::vector<u8> compressed_data(nso_header.segments_compressed_size[i]); | ||
| 117 | for (int j = 0; j < nso_header.segments_compressed_size[i]; ++j) | ||
| 118 | compressed_data[j] = file_data[nso_header.segments[i].offset + j]; | ||
| 119 | std::vector<u8> data = DecompressSegment(compressed_data, nso_header.segments[i]); | ||
| 120 | program_image.resize(nso_header.segments[i].location); | ||
| 121 | program_image.insert(program_image.end(), data.begin(), data.end()); | ||
| 122 | codeset->segments[i].addr = nso_header.segments[i].location; | ||
| 123 | codeset->segments[i].offset = nso_header.segments[i].location; | ||
| 124 | codeset->segments[i].size = PageAlignSize(static_cast<u32>(data.size())); | ||
| 125 | } | ||
| 126 | |||
| 127 | // MOD header pointer is at .text offset + 4 | ||
| 128 | u32 module_offset; | ||
| 129 | std::memcpy(&module_offset, program_image.data() + 4, sizeof(u32)); | ||
| 130 | |||
| 131 | // Read MOD header | ||
| 132 | ModHeader mod_header{}; | ||
| 133 | // Default .bss to size in segment header if MOD0 section doesn't exist | ||
| 134 | u32 bss_size{PageAlignSize(nso_header.segments[2].bss_size)}; | ||
| 135 | std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(ModHeader)); | ||
| 136 | const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')}; | ||
| 137 | if (has_mod_header) { | ||
| 138 | // Resize program image to include .bss section and page align each section | ||
| 139 | bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); | ||
| 140 | } | ||
| 141 | codeset->data.size += bss_size; | ||
| 142 | const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)}; | ||
| 143 | program_image.resize(image_size); | ||
| 144 | |||
| 145 | // Load codeset for current process | ||
| 146 | codeset->name = name; | ||
| 147 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | ||
| 148 | Core::CurrentProcess()->LoadModule(codeset, load_base); | ||
| 149 | |||
| 150 | return load_base + image_size; | ||
| 151 | } | ||
| 152 | |||
| 96 | VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { | 153 | VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { |
| 97 | FileUtil::IOFile file(path, "rb"); | 154 | FileUtil::IOFile file(path, "rb"); |
| 98 | if (!file.IsOpen()) { | 155 | if (!file.IsOpen()) { |
| @@ -158,7 +215,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 158 | 215 | ||
| 159 | // Load module | 216 | // Load module |
| 160 | LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR); | 217 | LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR); |
| 161 | NGLOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", filepath, Memory::PROCESS_IMAGE_VADDR); | 218 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", filepath, Memory::PROCESS_IMAGE_VADDR); |
| 162 | 219 | ||
| 163 | process->svc_access_mask.set(); | 220 | process->svc_access_mask.set(); |
| 164 | process->address_mappings = default_address_mappings; | 221 | process->address_mappings = default_address_mappings; |
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 1ae30a824..386f4d39a 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h | |||
| @@ -29,6 +29,9 @@ public: | |||
| 29 | return IdentifyType(file, filepath); | 29 | return IdentifyType(file, filepath); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | static VAddr LoadModule(const std::string& name, const std::vector<u8>& file_data, | ||
| 33 | VAddr load_base); | ||
| 34 | |||
| 32 | static VAddr LoadModule(const std::string& path, VAddr load_base); | 35 | static VAddr LoadModule(const std::string& path, VAddr load_base); |
| 33 | 36 | ||
| 34 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 37 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 3b81acd63..190ccc25c 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -43,8 +43,8 @@ PageTable* GetCurrentPageTable() { | |||
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { | 45 | static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { |
| 46 | NGLOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, | 46 | LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, |
| 47 | (base + size) * PAGE_SIZE); | 47 | (base + size) * PAGE_SIZE); |
| 48 | 48 | ||
| 49 | RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE, | 49 | RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE, |
| 50 | FlushMode::FlushAndInvalidate); | 50 | FlushMode::FlushAndInvalidate); |
| @@ -173,7 +173,7 @@ T Read(const VAddr vaddr) { | |||
| 173 | PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | 173 | PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; |
| 174 | switch (type) { | 174 | switch (type) { |
| 175 | case PageType::Unmapped: | 175 | case PageType::Unmapped: |
| 176 | NGLOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); | 176 | LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); |
| 177 | return 0; | 177 | return 0; |
| 178 | case PageType::Memory: | 178 | case PageType::Memory: |
| 179 | ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); | 179 | ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); |
| @@ -205,8 +205,8 @@ void Write(const VAddr vaddr, const T data) { | |||
| 205 | PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | 205 | PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; |
| 206 | switch (type) { | 206 | switch (type) { |
| 207 | case PageType::Unmapped: | 207 | case PageType::Unmapped: |
| 208 | NGLOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, | 208 | LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, |
| 209 | static_cast<u32>(data), vaddr); | 209 | static_cast<u32>(data), vaddr); |
| 210 | return; | 210 | return; |
| 211 | case PageType::Memory: | 211 | case PageType::Memory: |
| 212 | ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); | 212 | ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); |
| @@ -241,6 +241,10 @@ bool IsValidVirtualAddress(const VAddr vaddr) { | |||
| 241 | return IsValidVirtualAddress(*Core::CurrentProcess(), vaddr); | 241 | return IsValidVirtualAddress(*Core::CurrentProcess(), vaddr); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | bool IsKernelVirtualAddress(const VAddr vaddr) { | ||
| 245 | return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; | ||
| 246 | } | ||
| 247 | |||
| 244 | bool IsValidPhysicalAddress(const PAddr paddr) { | 248 | bool IsValidPhysicalAddress(const PAddr paddr) { |
| 245 | return GetPhysicalPointer(paddr) != nullptr; | 249 | return GetPhysicalPointer(paddr) != nullptr; |
| 246 | } | 250 | } |
| @@ -255,7 +259,7 @@ u8* GetPointer(const VAddr vaddr) { | |||
| 255 | return GetPointerFromVMA(vaddr); | 259 | return GetPointerFromVMA(vaddr); |
| 256 | } | 260 | } |
| 257 | 261 | ||
| 258 | NGLOG_ERROR(HW_Memory, "Unknown GetPointer @ 0x{:016X}", vaddr); | 262 | LOG_ERROR(HW_Memory, "Unknown GetPointer @ 0x{:016X}", vaddr); |
| 259 | return nullptr; | 263 | return nullptr; |
| 260 | } | 264 | } |
| 261 | 265 | ||
| @@ -292,12 +296,12 @@ u8* GetPhysicalPointer(PAddr address) { | |||
| 292 | }); | 296 | }); |
| 293 | 297 | ||
| 294 | if (area == std::end(memory_areas)) { | 298 | if (area == std::end(memory_areas)) { |
| 295 | NGLOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ 0x{:016X}", address); | 299 | LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ 0x{:016X}", address); |
| 296 | return nullptr; | 300 | return nullptr; |
| 297 | } | 301 | } |
| 298 | 302 | ||
| 299 | if (area->paddr_base == IO_AREA_PADDR) { | 303 | if (area->paddr_base == IO_AREA_PADDR) { |
| 300 | NGLOG_ERROR(HW_Memory, "MMIO mappings are not supported yet. phys_addr={:016X}", address); | 304 | LOG_ERROR(HW_Memory, "MMIO mappings are not supported yet. phys_addr={:016X}", address); |
| 301 | return nullptr; | 305 | return nullptr; |
| 302 | } | 306 | } |
| 303 | 307 | ||
| @@ -344,9 +348,9 @@ void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached) | |||
| 344 | Core::System::GetInstance().GPU().memory_manager->GpuToCpuAddress(gpu_addr); | 348 | Core::System::GetInstance().GPU().memory_manager->GpuToCpuAddress(gpu_addr); |
| 345 | // The GPU <-> CPU virtual memory mapping is not 1:1 | 349 | // The GPU <-> CPU virtual memory mapping is not 1:1 |
| 346 | if (!maybe_vaddr) { | 350 | if (!maybe_vaddr) { |
| 347 | NGLOG_ERROR(HW_Memory, | 351 | LOG_ERROR(HW_Memory, |
| 348 | "Trying to flush a cached region to an invalid physical address {:016X}", | 352 | "Trying to flush a cached region to an invalid physical address {:016X}", |
| 349 | gpu_addr); | 353 | gpu_addr); |
| 350 | continue; | 354 | continue; |
| 351 | } | 355 | } |
| 352 | VAddr vaddr = *maybe_vaddr; | 356 | VAddr vaddr = *maybe_vaddr; |
| @@ -480,9 +484,9 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_ | |||
| 480 | 484 | ||
| 481 | switch (page_table.attributes[page_index]) { | 485 | switch (page_table.attributes[page_index]) { |
| 482 | case PageType::Unmapped: { | 486 | case PageType::Unmapped: { |
| 483 | NGLOG_ERROR(HW_Memory, | 487 | LOG_ERROR(HW_Memory, |
| 484 | "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 488 | "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| 485 | current_vaddr, src_addr, size); | 489 | current_vaddr, src_addr, size); |
| 486 | std::memset(dest_buffer, 0, copy_amount); | 490 | std::memset(dest_buffer, 0, copy_amount); |
| 487 | break; | 491 | break; |
| 488 | } | 492 | } |
| @@ -544,9 +548,9 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi | |||
| 544 | 548 | ||
| 545 | switch (page_table.attributes[page_index]) { | 549 | switch (page_table.attributes[page_index]) { |
| 546 | case PageType::Unmapped: { | 550 | case PageType::Unmapped: { |
| 547 | NGLOG_ERROR(HW_Memory, | 551 | LOG_ERROR(HW_Memory, |
| 548 | "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 552 | "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| 549 | current_vaddr, dest_addr, size); | 553 | current_vaddr, dest_addr, size); |
| 550 | break; | 554 | break; |
| 551 | } | 555 | } |
| 552 | case PageType::Memory: { | 556 | case PageType::Memory: { |
| @@ -592,9 +596,9 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const size | |||
| 592 | 596 | ||
| 593 | switch (page_table.attributes[page_index]) { | 597 | switch (page_table.attributes[page_index]) { |
| 594 | case PageType::Unmapped: { | 598 | case PageType::Unmapped: { |
| 595 | NGLOG_ERROR(HW_Memory, | 599 | LOG_ERROR(HW_Memory, |
| 596 | "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 600 | "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| 597 | current_vaddr, dest_addr, size); | 601 | current_vaddr, dest_addr, size); |
| 598 | break; | 602 | break; |
| 599 | } | 603 | } |
| 600 | case PageType::Memory: { | 604 | case PageType::Memory: { |
| @@ -633,9 +637,9 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, | |||
| 633 | 637 | ||
| 634 | switch (page_table.attributes[page_index]) { | 638 | switch (page_table.attributes[page_index]) { |
| 635 | case PageType::Unmapped: { | 639 | case PageType::Unmapped: { |
| 636 | NGLOG_ERROR(HW_Memory, | 640 | LOG_ERROR(HW_Memory, |
| 637 | "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 641 | "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| 638 | current_vaddr, src_addr, size); | 642 | current_vaddr, src_addr, size); |
| 639 | ZeroBlock(process, dest_addr, copy_amount); | 643 | ZeroBlock(process, dest_addr, copy_amount); |
| 640 | break; | 644 | break; |
| 641 | } | 645 | } |
| @@ -688,7 +692,7 @@ boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) { | |||
| 688 | PAddr VirtualToPhysicalAddress(const VAddr addr) { | 692 | PAddr VirtualToPhysicalAddress(const VAddr addr) { |
| 689 | auto paddr = TryVirtualToPhysicalAddress(addr); | 693 | auto paddr = TryVirtualToPhysicalAddress(addr); |
| 690 | if (!paddr) { | 694 | if (!paddr) { |
| 691 | NGLOG_ERROR(HW_Memory, "Unknown virtual address @ 0x{:016X}", addr); | 695 | LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x{:016X}", addr); |
| 692 | // To help with debugging, set bit on address so that it's obviously invalid. | 696 | // To help with debugging, set bit on address so that it's obviously invalid. |
| 693 | return addr | 0x80000000; | 697 | return addr | 0x80000000; |
| 694 | } | 698 | } |
diff --git a/src/core/memory.h b/src/core/memory.h index 3f56a2c6a..8d5d017a4 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -188,6 +188,11 @@ enum : VAddr { | |||
| 188 | MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END, | 188 | MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END, |
| 189 | MAP_REGION_SIZE = 0x1000000000, | 189 | MAP_REGION_SIZE = 0x1000000000, |
| 190 | MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE, | 190 | MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE, |
| 191 | |||
| 192 | /// Kernel Virtual Address Range | ||
| 193 | KERNEL_REGION_VADDR = 0xFFFFFF8000000000, | ||
| 194 | KERNEL_REGION_SIZE = 0x7FFFE00000, | ||
| 195 | KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE, | ||
| 191 | }; | 196 | }; |
| 192 | 197 | ||
| 193 | /// Currently active page table | 198 | /// Currently active page table |
| @@ -197,6 +202,8 @@ PageTable* GetCurrentPageTable(); | |||
| 197 | /// Determines if the given VAddr is valid for the specified process. | 202 | /// Determines if the given VAddr is valid for the specified process. |
| 198 | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr); | 203 | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr); |
| 199 | bool IsValidVirtualAddress(const VAddr addr); | 204 | bool IsValidVirtualAddress(const VAddr addr); |
| 205 | /// Determines if the given VAddr is a kernel address | ||
| 206 | bool IsKernelVirtualAddress(const VAddr addr); | ||
| 200 | 207 | ||
| 201 | bool IsValidPhysicalAddress(const PAddr addr); | 208 | bool IsValidPhysicalAddress(const PAddr addr); |
| 202 | 209 | ||
diff --git a/src/core/settings.h b/src/core/settings.h index a7f1e5fa0..7150d9755 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -129,6 +129,7 @@ struct Values { | |||
| 129 | // Renderer | 129 | // Renderer |
| 130 | float resolution_factor; | 130 | float resolution_factor; |
| 131 | bool toggle_framelimit; | 131 | bool toggle_framelimit; |
| 132 | bool use_accurate_framebuffers; | ||
| 132 | 133 | ||
| 133 | float bg_red; | 134 | float bg_red; |
| 134 | float bg_green; | 135 | float bg_green; |
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index a60aa1143..b9a603df3 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp | |||
| @@ -42,14 +42,14 @@ u64 GetTelemetryId() { | |||
| 42 | if (FileUtil::Exists(filename)) { | 42 | if (FileUtil::Exists(filename)) { |
| 43 | FileUtil::IOFile file(filename, "rb"); | 43 | FileUtil::IOFile file(filename, "rb"); |
| 44 | if (!file.IsOpen()) { | 44 | if (!file.IsOpen()) { |
| 45 | NGLOG_ERROR(Core, "failed to open telemetry_id: {}", filename); | 45 | LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); |
| 46 | return {}; | 46 | return {}; |
| 47 | } | 47 | } |
| 48 | file.ReadBytes(&telemetry_id, sizeof(u64)); | 48 | file.ReadBytes(&telemetry_id, sizeof(u64)); |
| 49 | } else { | 49 | } else { |
| 50 | FileUtil::IOFile file(filename, "wb"); | 50 | FileUtil::IOFile file(filename, "wb"); |
| 51 | if (!file.IsOpen()) { | 51 | if (!file.IsOpen()) { |
| 52 | NGLOG_ERROR(Core, "failed to open telemetry_id: {}", filename); | 52 | LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); |
| 53 | return {}; | 53 | return {}; |
| 54 | } | 54 | } |
| 55 | telemetry_id = GenerateTelemetryId(); | 55 | telemetry_id = GenerateTelemetryId(); |
| @@ -65,7 +65,7 @@ u64 RegenerateTelemetryId() { | |||
| 65 | 65 | ||
| 66 | FileUtil::IOFile file(filename, "wb"); | 66 | FileUtil::IOFile file(filename, "wb"); |
| 67 | if (!file.IsOpen()) { | 67 | if (!file.IsOpen()) { |
| 68 | NGLOG_ERROR(Core, "failed to open telemetry_id: {}", filename); | 68 | LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); |
| 69 | return {}; | 69 | return {}; |
| 70 | } | 70 | } |
| 71 | file.WriteBytes(&new_telemetry_id, sizeof(u64)); | 71 | file.WriteBytes(&new_telemetry_id, sizeof(u64)); |
| @@ -161,6 +161,8 @@ TelemetrySession::TelemetrySession() { | |||
| 161 | Settings::values.resolution_factor); | 161 | Settings::values.resolution_factor); |
| 162 | AddField(Telemetry::FieldType::UserConfig, "Renderer_ToggleFramelimit", | 162 | AddField(Telemetry::FieldType::UserConfig, "Renderer_ToggleFramelimit", |
| 163 | Settings::values.toggle_framelimit); | 163 | Settings::values.toggle_framelimit); |
| 164 | AddField(Telemetry::FieldType::UserConfig, "Renderer_UseAccurateFramebuffers", | ||
| 165 | Settings::values.use_accurate_framebuffers); | ||
| 164 | AddField(Telemetry::FieldType::UserConfig, "System_UseDockedMode", | 166 | AddField(Telemetry::FieldType::UserConfig, "System_UseDockedMode", |
| 165 | Settings::values.use_docked_mode); | 167 | Settings::values.use_docked_mode); |
| 166 | } | 168 | } |
diff --git a/src/core/tracer/recorder.cpp b/src/core/tracer/recorder.cpp index 2f848c994..af032f0c9 100644 --- a/src/core/tracer/recorder.cpp +++ b/src/core/tracer/recorder.cpp | |||
| @@ -159,7 +159,7 @@ void Recorder::Finish(const std::string& filename) { | |||
| 159 | throw "Failed to write stream element"; | 159 | throw "Failed to write stream element"; |
| 160 | } | 160 | } |
| 161 | } catch (const char* str) { | 161 | } catch (const char* str) { |
| 162 | NGLOG_ERROR(HW_GPU, "Writing CiTrace file failed: {}", str); | 162 | LOG_ERROR(HW_GPU, "Writing CiTrace file failed: {}", str); |
| 163 | } | 163 | } |
| 164 | } | 164 | } |
| 165 | 165 | ||
diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp index 231a0f7af..8d117c2d4 100644 --- a/src/input_common/sdl/sdl.cpp +++ b/src/input_common/sdl/sdl.cpp | |||
| @@ -32,7 +32,7 @@ public: | |||
| 32 | explicit SDLJoystick(int joystick_index) | 32 | explicit SDLJoystick(int joystick_index) |
| 33 | : joystick{SDL_JoystickOpen(joystick_index), SDL_JoystickClose} { | 33 | : joystick{SDL_JoystickOpen(joystick_index), SDL_JoystickClose} { |
| 34 | if (!joystick) { | 34 | if (!joystick) { |
| 35 | NGLOG_ERROR(Input, "failed to open joystick {}", joystick_index); | 35 | LOG_ERROR(Input, "failed to open joystick {}", joystick_index); |
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | 38 | ||
| @@ -204,7 +204,7 @@ public: | |||
| 204 | trigger_if_greater = false; | 204 | trigger_if_greater = false; |
| 205 | } else { | 205 | } else { |
| 206 | trigger_if_greater = true; | 206 | trigger_if_greater = true; |
| 207 | NGLOG_ERROR(Input, "Unknown direction '{}'", direction_name); | 207 | LOG_ERROR(Input, "Unknown direction '{}'", direction_name); |
| 208 | } | 208 | } |
| 209 | return std::make_unique<SDLAxisButton>(GetJoystick(joystick_index), axis, threshold, | 209 | return std::make_unique<SDLAxisButton>(GetJoystick(joystick_index), axis, threshold, |
| 210 | trigger_if_greater); | 210 | trigger_if_greater); |
| @@ -235,7 +235,7 @@ public: | |||
| 235 | 235 | ||
| 236 | void Init() { | 236 | void Init() { |
| 237 | if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { | 237 | if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { |
| 238 | NGLOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); | 238 | LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); |
| 239 | } else { | 239 | } else { |
| 240 | using namespace Input; | 240 | using namespace Input; |
| 241 | RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>()); | 241 | RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>()); |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 281810357..c6431e722 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -9,6 +9,8 @@ add_library(video_core STATIC | |||
| 9 | engines/maxwell_3d.h | 9 | engines/maxwell_3d.h |
| 10 | engines/maxwell_compute.cpp | 10 | engines/maxwell_compute.cpp |
| 11 | engines/maxwell_compute.h | 11 | engines/maxwell_compute.h |
| 12 | engines/maxwell_dma.cpp | ||
| 13 | engines/maxwell_dma.h | ||
| 12 | engines/shader_bytecode.h | 14 | engines/shader_bytecode.h |
| 13 | gpu.cpp | 15 | gpu.cpp |
| 14 | gpu.h | 16 | gpu.h |
| @@ -39,6 +41,8 @@ add_library(video_core STATIC | |||
| 39 | renderer_opengl/maxwell_to_gl.h | 41 | renderer_opengl/maxwell_to_gl.h |
| 40 | renderer_opengl/renderer_opengl.cpp | 42 | renderer_opengl/renderer_opengl.cpp |
| 41 | renderer_opengl/renderer_opengl.h | 43 | renderer_opengl/renderer_opengl.h |
| 44 | textures/astc.cpp | ||
| 45 | textures/astc.h | ||
| 42 | textures/decoders.cpp | 46 | textures/decoders.cpp |
| 43 | textures/decoders.h | 47 | textures/decoders.h |
| 44 | textures/texture.h | 48 | textures/texture.h |
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index d72d6f760..31ea3adad 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "video_core/engines/fermi_2d.h" | 16 | #include "video_core/engines/fermi_2d.h" |
| 17 | #include "video_core/engines/maxwell_3d.h" | 17 | #include "video_core/engines/maxwell_3d.h" |
| 18 | #include "video_core/engines/maxwell_compute.h" | 18 | #include "video_core/engines/maxwell_compute.h" |
| 19 | #include "video_core/engines/maxwell_dma.h" | ||
| 19 | #include "video_core/gpu.h" | 20 | #include "video_core/gpu.h" |
| 20 | #include "video_core/renderer_base.h" | 21 | #include "video_core/renderer_base.h" |
| 21 | #include "video_core/video_core.h" | 22 | #include "video_core/video_core.h" |
| @@ -28,21 +29,21 @@ enum class BufferMethods { | |||
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| 30 | void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) { | 31 | void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) { |
| 31 | NGLOG_WARNING(HW_GPU, | 32 | LOG_WARNING(HW_GPU, |
| 32 | "Processing method {:08X} on subchannel {} value " | 33 | "Processing method {:08X} on subchannel {} value " |
| 33 | "{:08X} remaining params {}", | 34 | "{:08X} remaining params {}", |
| 34 | method, subchannel, value, remaining_params); | 35 | method, subchannel, value, remaining_params); |
| 35 | 36 | ||
| 36 | if (method == static_cast<u32>(BufferMethods::BindObject)) { | 37 | if (method == static_cast<u32>(BufferMethods::BindObject)) { |
| 37 | // Bind the current subchannel to the desired engine id. | 38 | // Bind the current subchannel to the desired engine id. |
| 38 | NGLOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value); | 39 | LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value); |
| 39 | bound_engines[subchannel] = static_cast<EngineID>(value); | 40 | bound_engines[subchannel] = static_cast<EngineID>(value); |
| 40 | return; | 41 | return; |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) { | 44 | if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) { |
| 44 | // TODO(Subv): Research and implement these methods. | 45 | // TODO(Subv): Research and implement these methods. |
| 45 | NGLOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented"); | 46 | LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented"); |
| 46 | return; | 47 | return; |
| 47 | } | 48 | } |
| 48 | 49 | ||
| @@ -60,8 +61,11 @@ void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) | |||
| 60 | case EngineID::MAXWELL_COMPUTE_B: | 61 | case EngineID::MAXWELL_COMPUTE_B: |
| 61 | maxwell_compute->WriteReg(method, value); | 62 | maxwell_compute->WriteReg(method, value); |
| 62 | break; | 63 | break; |
| 64 | case EngineID::MAXWELL_DMA_COPY_A: | ||
| 65 | maxwell_dma->WriteReg(method, value); | ||
| 66 | break; | ||
| 63 | default: | 67 | default: |
| 64 | UNIMPLEMENTED(); | 68 | UNIMPLEMENTED_MSG("Unimplemented engine"); |
| 65 | } | 69 | } |
| 66 | } | 70 | } |
| 67 | 71 | ||
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h index bbba8e380..9382a75e5 100644 --- a/src/video_core/debug_utils/debug_utils.h +++ b/src/video_core/debug_utils/debug_utils.h | |||
| @@ -55,8 +55,10 @@ public: | |||
| 55 | virtual ~BreakPointObserver() { | 55 | virtual ~BreakPointObserver() { |
| 56 | auto context = context_weak.lock(); | 56 | auto context = context_weak.lock(); |
| 57 | if (context) { | 57 | if (context) { |
| 58 | std::unique_lock<std::mutex> lock(context->breakpoint_mutex); | 58 | { |
| 59 | context->breakpoint_observers.remove(this); | 59 | std::unique_lock<std::mutex> lock(context->breakpoint_mutex); |
| 60 | context->breakpoint_observers.remove(this); | ||
| 61 | } | ||
| 60 | 62 | ||
| 61 | // If we are the last observer to be destroyed, tell the debugger context that | 63 | // If we are the last observer to be destroyed, tell the debugger context that |
| 62 | // it is free to continue. In particular, this is required for a proper yuzu | 64 | // it is free to continue. In particular, this is required for a proper yuzu |
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 6b9382f06..34053e393 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp | |||
| @@ -26,8 +26,8 @@ void Fermi2D::WriteReg(u32 method, u32 value) { | |||
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | void Fermi2D::HandleSurfaceCopy() { | 28 | void Fermi2D::HandleSurfaceCopy() { |
| 29 | NGLOG_WARNING(HW_GPU, "Requested a surface copy with operation {}", | 29 | LOG_WARNING(HW_GPU, "Requested a surface copy with operation {}", |
| 30 | static_cast<u32>(regs.operation)); | 30 | static_cast<u32>(regs.operation)); |
| 31 | 31 | ||
| 32 | const GPUVAddr source = regs.src.Address(); | 32 | const GPUVAddr source = regs.src.Address(); |
| 33 | const GPUVAddr dest = regs.dst.Address(); | 33 | const GPUVAddr dest = regs.dst.Address(); |
| @@ -47,6 +47,7 @@ void Fermi2D::HandleSurfaceCopy() { | |||
| 47 | 47 | ||
| 48 | if (regs.src.linear == regs.dst.linear) { | 48 | if (regs.src.linear == regs.dst.linear) { |
| 49 | // If the input layout and the output layout are the same, just perform a raw copy. | 49 | // If the input layout and the output layout are the same, just perform a raw copy. |
| 50 | ASSERT(regs.src.BlockHeight() == regs.dst.BlockHeight()); | ||
| 50 | Memory::CopyBlock(dest_cpu, source_cpu, | 51 | Memory::CopyBlock(dest_cpu, source_cpu, |
| 51 | src_bytes_per_pixel * regs.dst.width * regs.dst.height); | 52 | src_bytes_per_pixel * regs.dst.width * regs.dst.height); |
| 52 | return; | 53 | return; |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 86e9dc998..3bca16364 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -126,6 +126,10 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { | |||
| 126 | DrawArrays(); | 126 | DrawArrays(); |
| 127 | break; | 127 | break; |
| 128 | } | 128 | } |
| 129 | case MAXWELL3D_REG_INDEX(clear_buffers): { | ||
| 130 | ProcessClearBuffers(); | ||
| 131 | break; | ||
| 132 | } | ||
| 129 | case MAXWELL3D_REG_INDEX(query.query_get): { | 133 | case MAXWELL3D_REG_INDEX(query.query_get): { |
| 130 | ProcessQueryGet(); | 134 | ProcessQueryGet(); |
| 131 | break; | 135 | break; |
| @@ -207,8 +211,8 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 207 | } | 211 | } |
| 208 | 212 | ||
| 209 | void Maxwell3D::DrawArrays() { | 213 | void Maxwell3D::DrawArrays() { |
| 210 | NGLOG_DEBUG(HW_GPU, "called, topology={}, count={}", | 214 | LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()), |
| 211 | static_cast<u32>(regs.draw.topology.Value()), regs.vertex_buffer.count); | 215 | regs.vertex_buffer.count); |
| 212 | ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?"); | 216 | ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?"); |
| 213 | 217 | ||
| 214 | auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); | 218 | auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); |
| @@ -328,8 +332,9 @@ std::vector<Texture::FullTextureInfo> Maxwell3D::GetStageTextures(Regs::ShaderSt | |||
| 328 | 332 | ||
| 329 | Texture::FullTextureInfo tex_info{}; | 333 | Texture::FullTextureInfo tex_info{}; |
| 330 | // TODO(Subv): Use the shader to determine which textures are actually accessed. | 334 | // TODO(Subv): Use the shader to determine which textures are actually accessed. |
| 331 | tex_info.index = (current_texture - tex_info_buffer.address - TextureInfoOffset) / | 335 | tex_info.index = |
| 332 | sizeof(Texture::TextureHandle); | 336 | static_cast<u32>(current_texture - tex_info_buffer.address - TextureInfoOffset) / |
| 337 | sizeof(Texture::TextureHandle); | ||
| 333 | 338 | ||
| 334 | // Load the TIC data. | 339 | // Load the TIC data. |
| 335 | if (tex_handle.tic_id != 0) { | 340 | if (tex_handle.tic_id != 0) { |
| @@ -414,5 +419,13 @@ bool Maxwell3D::IsShaderStageEnabled(Regs::ShaderStage stage) const { | |||
| 414 | UNREACHABLE(); | 419 | UNREACHABLE(); |
| 415 | } | 420 | } |
| 416 | 421 | ||
| 422 | void Maxwell3D::ProcessClearBuffers() { | ||
| 423 | ASSERT(regs.clear_buffers.R == regs.clear_buffers.G && | ||
| 424 | regs.clear_buffers.R == regs.clear_buffers.B && | ||
| 425 | regs.clear_buffers.R == regs.clear_buffers.A); | ||
| 426 | |||
| 427 | VideoCore::g_renderer->Rasterizer()->Clear(); | ||
| 428 | } | ||
| 429 | |||
| 417 | } // namespace Engines | 430 | } // namespace Engines |
| 418 | } // namespace Tegra | 431 | } // namespace Tegra |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 2dc251205..5a7cf0107 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -280,6 +280,46 @@ public: | |||
| 280 | UnsignedInt = 0x2, | 280 | UnsignedInt = 0x2, |
| 281 | }; | 281 | }; |
| 282 | 282 | ||
| 283 | enum class ComparisonOp : u32 { | ||
| 284 | // These values are used by Nouveau and most games, they correspond to the OpenGL token | ||
| 285 | // values for these operations. | ||
| 286 | Never = 0x200, | ||
| 287 | Less = 0x201, | ||
| 288 | Equal = 0x202, | ||
| 289 | LessEqual = 0x203, | ||
| 290 | Greater = 0x204, | ||
| 291 | NotEqual = 0x205, | ||
| 292 | GreaterEqual = 0x206, | ||
| 293 | Always = 0x207, | ||
| 294 | |||
| 295 | // These values are used by some games, they seem to be NV04 values. | ||
| 296 | NeverOld = 1, | ||
| 297 | LessOld = 2, | ||
| 298 | EqualOld = 3, | ||
| 299 | LessEqualOld = 4, | ||
| 300 | GreaterOld = 5, | ||
| 301 | NotEqualOld = 6, | ||
| 302 | GreaterEqualOld = 7, | ||
| 303 | AlwaysOld = 8, | ||
| 304 | }; | ||
| 305 | |||
| 306 | struct Cull { | ||
| 307 | enum class FrontFace : u32 { | ||
| 308 | ClockWise = 0x0900, | ||
| 309 | CounterClockWise = 0x0901, | ||
| 310 | }; | ||
| 311 | |||
| 312 | enum class CullFace : u32 { | ||
| 313 | Front = 0x0404, | ||
| 314 | Back = 0x0405, | ||
| 315 | FrontAndBack = 0x0408, | ||
| 316 | }; | ||
| 317 | |||
| 318 | u32 enabled; | ||
| 319 | FrontFace front_face; | ||
| 320 | CullFace cull_face; | ||
| 321 | }; | ||
| 322 | |||
| 283 | struct Blend { | 323 | struct Blend { |
| 284 | enum class Equation : u32 { | 324 | enum class Equation : u32 { |
| 285 | Add = 1, | 325 | Add = 1, |
| @@ -321,6 +361,24 @@ public: | |||
| 321 | INSERT_PADDING_WORDS(1); | 361 | INSERT_PADDING_WORDS(1); |
| 322 | }; | 362 | }; |
| 323 | 363 | ||
| 364 | struct RenderTargetConfig { | ||
| 365 | u32 address_high; | ||
| 366 | u32 address_low; | ||
| 367 | u32 width; | ||
| 368 | u32 height; | ||
| 369 | Tegra::RenderTargetFormat format; | ||
| 370 | u32 block_dimensions; | ||
| 371 | u32 array_mode; | ||
| 372 | u32 layer_stride; | ||
| 373 | u32 base_layer; | ||
| 374 | INSERT_PADDING_WORDS(7); | ||
| 375 | |||
| 376 | GPUVAddr Address() const { | ||
| 377 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | | ||
| 378 | address_low); | ||
| 379 | } | ||
| 380 | }; | ||
| 381 | |||
| 324 | union { | 382 | union { |
| 325 | struct { | 383 | struct { |
| 326 | INSERT_PADDING_WORDS(0x45); | 384 | INSERT_PADDING_WORDS(0x45); |
| @@ -333,23 +391,7 @@ public: | |||
| 333 | 391 | ||
| 334 | INSERT_PADDING_WORDS(0x1B8); | 392 | INSERT_PADDING_WORDS(0x1B8); |
| 335 | 393 | ||
| 336 | struct { | 394 | RenderTargetConfig rt[NumRenderTargets]; |
| 337 | u32 address_high; | ||
| 338 | u32 address_low; | ||
| 339 | u32 width; | ||
| 340 | u32 height; | ||
| 341 | Tegra::RenderTargetFormat format; | ||
| 342 | u32 block_dimensions; | ||
| 343 | u32 array_mode; | ||
| 344 | u32 layer_stride; | ||
| 345 | u32 base_layer; | ||
| 346 | INSERT_PADDING_WORDS(7); | ||
| 347 | |||
| 348 | GPUVAddr Address() const { | ||
| 349 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | | ||
| 350 | address_low); | ||
| 351 | } | ||
| 352 | } rt[NumRenderTargets]; | ||
| 353 | 395 | ||
| 354 | struct { | 396 | struct { |
| 355 | f32 scale_x; | 397 | f32 scale_x; |
| @@ -406,12 +448,17 @@ public: | |||
| 406 | u32 count; | 448 | u32 count; |
| 407 | } vertex_buffer; | 449 | } vertex_buffer; |
| 408 | 450 | ||
| 409 | INSERT_PADDING_WORDS(0x99); | 451 | INSERT_PADDING_WORDS(1); |
| 452 | |||
| 453 | float clear_color[4]; | ||
| 454 | float clear_depth; | ||
| 455 | |||
| 456 | INSERT_PADDING_WORDS(0x93); | ||
| 410 | 457 | ||
| 411 | struct { | 458 | struct { |
| 412 | u32 address_high; | 459 | u32 address_high; |
| 413 | u32 address_low; | 460 | u32 address_low; |
| 414 | u32 format; | 461 | Tegra::DepthFormat format; |
| 415 | u32 block_dimensions; | 462 | u32 block_dimensions; |
| 416 | u32 layer_stride; | 463 | u32 layer_stride; |
| 417 | 464 | ||
| @@ -433,11 +480,23 @@ public: | |||
| 433 | }; | 480 | }; |
| 434 | } rt_control; | 481 | } rt_control; |
| 435 | 482 | ||
| 436 | INSERT_PADDING_WORDS(0x31); | 483 | INSERT_PADDING_WORDS(0x2B); |
| 484 | |||
| 485 | u32 depth_test_enable; | ||
| 486 | |||
| 487 | INSERT_PADDING_WORDS(0x5); | ||
| 437 | 488 | ||
| 438 | u32 independent_blend_enable; | 489 | u32 independent_blend_enable; |
| 439 | 490 | ||
| 440 | INSERT_PADDING_WORDS(0x15); | 491 | u32 depth_write_enabled; |
| 492 | |||
| 493 | INSERT_PADDING_WORDS(0x7); | ||
| 494 | |||
| 495 | u32 d3d_cull_mode; | ||
| 496 | |||
| 497 | ComparisonOp depth_test_func; | ||
| 498 | |||
| 499 | INSERT_PADDING_WORDS(0xB); | ||
| 441 | 500 | ||
| 442 | struct { | 501 | struct { |
| 443 | u32 separate_alpha; | 502 | u32 separate_alpha; |
| @@ -453,7 +512,17 @@ public: | |||
| 453 | u32 enable[NumRenderTargets]; | 512 | u32 enable[NumRenderTargets]; |
| 454 | } blend; | 513 | } blend; |
| 455 | 514 | ||
| 456 | INSERT_PADDING_WORDS(0x77); | 515 | INSERT_PADDING_WORDS(0xB); |
| 516 | |||
| 517 | union { | ||
| 518 | BitField<4, 1, u32> triangle_rast_flip; | ||
| 519 | } screen_y_control; | ||
| 520 | |||
| 521 | INSERT_PADDING_WORDS(0x21); | ||
| 522 | |||
| 523 | u32 vb_element_base; | ||
| 524 | |||
| 525 | INSERT_PADDING_WORDS(0x49); | ||
| 457 | 526 | ||
| 458 | struct { | 527 | struct { |
| 459 | u32 tsc_address_high; | 528 | u32 tsc_address_high; |
| @@ -479,7 +548,12 @@ public: | |||
| 479 | } | 548 | } |
| 480 | } tic; | 549 | } tic; |
| 481 | 550 | ||
| 482 | INSERT_PADDING_WORDS(0x22); | 551 | INSERT_PADDING_WORDS(0x21); |
| 552 | |||
| 553 | union { | ||
| 554 | BitField<2, 1, u32> coord_origin; | ||
| 555 | BitField<3, 10, u32> enable; | ||
| 556 | } point_coord_replace; | ||
| 483 | 557 | ||
| 484 | struct { | 558 | struct { |
| 485 | u32 code_address_high; | 559 | u32 code_address_high; |
| @@ -534,7 +608,27 @@ public: | |||
| 534 | } | 608 | } |
| 535 | } index_array; | 609 | } index_array; |
| 536 | 610 | ||
| 537 | INSERT_PADDING_WORDS(0xC7); | 611 | INSERT_PADDING_WORDS(0x7); |
| 612 | |||
| 613 | INSERT_PADDING_WORDS(0x46); | ||
| 614 | |||
| 615 | Cull cull; | ||
| 616 | |||
| 617 | INSERT_PADDING_WORDS(0x2B); | ||
| 618 | |||
| 619 | union { | ||
| 620 | u32 raw; | ||
| 621 | BitField<0, 1, u32> Z; | ||
| 622 | BitField<1, 1, u32> S; | ||
| 623 | BitField<2, 1, u32> R; | ||
| 624 | BitField<3, 1, u32> G; | ||
| 625 | BitField<4, 1, u32> B; | ||
| 626 | BitField<5, 1, u32> A; | ||
| 627 | BitField<6, 4, u32> RT; | ||
| 628 | BitField<10, 11, u32> layer; | ||
| 629 | } clear_buffers; | ||
| 630 | |||
| 631 | INSERT_PADDING_WORDS(0x4B); | ||
| 538 | 632 | ||
| 539 | struct { | 633 | struct { |
| 540 | u32 query_address_high; | 634 | u32 query_address_high; |
| @@ -716,6 +810,9 @@ private: | |||
| 716 | /// Handles writes to the macro uploading registers. | 810 | /// Handles writes to the macro uploading registers. |
| 717 | void ProcessMacroUpload(u32 data); | 811 | void ProcessMacroUpload(u32 data); |
| 718 | 812 | ||
| 813 | /// Handles a write to the CLEAR_BUFFERS register. | ||
| 814 | void ProcessClearBuffers(); | ||
| 815 | |||
| 719 | /// Handles a write to the QUERY_GET register. | 816 | /// Handles a write to the QUERY_GET register. |
| 720 | void ProcessQueryGet(); | 817 | void ProcessQueryGet(); |
| 721 | 818 | ||
| @@ -738,16 +835,27 @@ ASSERT_REG_POSITION(rt, 0x200); | |||
| 738 | ASSERT_REG_POSITION(viewport_transform[0], 0x280); | 835 | ASSERT_REG_POSITION(viewport_transform[0], 0x280); |
| 739 | ASSERT_REG_POSITION(viewport, 0x300); | 836 | ASSERT_REG_POSITION(viewport, 0x300); |
| 740 | ASSERT_REG_POSITION(vertex_buffer, 0x35D); | 837 | ASSERT_REG_POSITION(vertex_buffer, 0x35D); |
| 838 | ASSERT_REG_POSITION(clear_color[0], 0x360); | ||
| 839 | ASSERT_REG_POSITION(clear_depth, 0x364); | ||
| 741 | ASSERT_REG_POSITION(zeta, 0x3F8); | 840 | ASSERT_REG_POSITION(zeta, 0x3F8); |
| 742 | ASSERT_REG_POSITION(vertex_attrib_format[0], 0x458); | 841 | ASSERT_REG_POSITION(vertex_attrib_format[0], 0x458); |
| 743 | ASSERT_REG_POSITION(rt_control, 0x487); | 842 | ASSERT_REG_POSITION(rt_control, 0x487); |
| 843 | ASSERT_REG_POSITION(depth_test_enable, 0x4B3); | ||
| 744 | ASSERT_REG_POSITION(independent_blend_enable, 0x4B9); | 844 | ASSERT_REG_POSITION(independent_blend_enable, 0x4B9); |
| 845 | ASSERT_REG_POSITION(depth_write_enabled, 0x4BA); | ||
| 846 | ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); | ||
| 847 | ASSERT_REG_POSITION(depth_test_func, 0x4C3); | ||
| 745 | ASSERT_REG_POSITION(blend, 0x4CF); | 848 | ASSERT_REG_POSITION(blend, 0x4CF); |
| 849 | ASSERT_REG_POSITION(screen_y_control, 0x4EB); | ||
| 850 | ASSERT_REG_POSITION(vb_element_base, 0x50D); | ||
| 746 | ASSERT_REG_POSITION(tsc, 0x557); | 851 | ASSERT_REG_POSITION(tsc, 0x557); |
| 747 | ASSERT_REG_POSITION(tic, 0x55D); | 852 | ASSERT_REG_POSITION(tic, 0x55D); |
| 853 | ASSERT_REG_POSITION(point_coord_replace, 0x581); | ||
| 748 | ASSERT_REG_POSITION(code_address, 0x582); | 854 | ASSERT_REG_POSITION(code_address, 0x582); |
| 749 | ASSERT_REG_POSITION(draw, 0x585); | 855 | ASSERT_REG_POSITION(draw, 0x585); |
| 750 | ASSERT_REG_POSITION(index_array, 0x5F2); | 856 | ASSERT_REG_POSITION(index_array, 0x5F2); |
| 857 | ASSERT_REG_POSITION(cull, 0x646); | ||
| 858 | ASSERT_REG_POSITION(clear_buffers, 0x674); | ||
| 751 | ASSERT_REG_POSITION(query, 0x6C0); | 859 | ASSERT_REG_POSITION(query, 0x6C0); |
| 752 | ASSERT_REG_POSITION(vertex_array[0], 0x700); | 860 | ASSERT_REG_POSITION(vertex_array[0], 0x700); |
| 753 | ASSERT_REG_POSITION(independent_blend, 0x780); | 861 | ASSERT_REG_POSITION(independent_blend, 0x780); |
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp new file mode 100644 index 000000000..6e740713f --- /dev/null +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/memory.h" | ||
| 6 | #include "video_core/engines/maxwell_dma.h" | ||
| 7 | #include "video_core/textures/decoders.h" | ||
| 8 | |||
| 9 | namespace Tegra { | ||
| 10 | namespace Engines { | ||
| 11 | |||
| 12 | MaxwellDMA::MaxwellDMA(MemoryManager& memory_manager) : memory_manager(memory_manager) {} | ||
| 13 | |||
| 14 | void MaxwellDMA::WriteReg(u32 method, u32 value) { | ||
| 15 | ASSERT_MSG(method < Regs::NUM_REGS, | ||
| 16 | "Invalid MaxwellDMA register, increase the size of the Regs structure"); | ||
| 17 | |||
| 18 | regs.reg_array[method] = value; | ||
| 19 | |||
| 20 | #define MAXWELLDMA_REG_INDEX(field_name) \ | ||
| 21 | (offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32)) | ||
| 22 | |||
| 23 | switch (method) { | ||
| 24 | case MAXWELLDMA_REG_INDEX(exec): { | ||
| 25 | HandleCopy(); | ||
| 26 | break; | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | #undef MAXWELLDMA_REG_INDEX | ||
| 31 | } | ||
| 32 | |||
| 33 | void MaxwellDMA::HandleCopy() { | ||
| 34 | LOG_WARNING(HW_GPU, "Requested a DMA copy"); | ||
| 35 | |||
| 36 | const GPUVAddr source = regs.src_address.Address(); | ||
| 37 | const GPUVAddr dest = regs.dst_address.Address(); | ||
| 38 | |||
| 39 | const VAddr source_cpu = *memory_manager.GpuToCpuAddress(source); | ||
| 40 | const VAddr dest_cpu = *memory_manager.GpuToCpuAddress(dest); | ||
| 41 | |||
| 42 | // TODO(Subv): Perform more research and implement all features of this engine. | ||
| 43 | ASSERT(regs.exec.enable_swizzle == 0); | ||
| 44 | ASSERT(regs.exec.enable_2d == 1); | ||
| 45 | ASSERT(regs.exec.query_mode == Regs::QueryMode::None); | ||
| 46 | ASSERT(regs.exec.query_intr == Regs::QueryIntr::None); | ||
| 47 | ASSERT(regs.exec.copy_mode == Regs::CopyMode::Unk2); | ||
| 48 | ASSERT(regs.src_params.pos_x == 0); | ||
| 49 | ASSERT(regs.src_params.pos_y == 0); | ||
| 50 | ASSERT(regs.dst_params.pos_x == 0); | ||
| 51 | ASSERT(regs.dst_params.pos_y == 0); | ||
| 52 | |||
| 53 | if (regs.exec.is_dst_linear == regs.exec.is_src_linear) { | ||
| 54 | Memory::CopyBlock(dest_cpu, source_cpu, regs.x_count * regs.y_count); | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | |||
| 58 | u8* src_buffer = Memory::GetPointer(source_cpu); | ||
| 59 | u8* dst_buffer = Memory::GetPointer(dest_cpu); | ||
| 60 | |||
| 61 | if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) { | ||
| 62 | // If the input is tiled and the output is linear, deswizzle the input and copy it over. | ||
| 63 | Texture::CopySwizzledData(regs.src_params.size_x, regs.src_params.size_y, 1, 1, src_buffer, | ||
| 64 | dst_buffer, true, regs.src_params.BlockHeight()); | ||
| 65 | } else { | ||
| 66 | // If the input is linear and the output is tiled, swizzle the input and copy it over. | ||
| 67 | Texture::CopySwizzledData(regs.dst_params.size_x, regs.dst_params.size_y, 1, 1, dst_buffer, | ||
| 68 | src_buffer, false, regs.dst_params.BlockHeight()); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | } // namespace Engines | ||
| 73 | } // namespace Tegra | ||
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h new file mode 100644 index 000000000..905749bde --- /dev/null +++ b/src/video_core/engines/maxwell_dma.h | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include "common/assert.h" | ||
| 9 | #include "common/bit_field.h" | ||
| 10 | #include "common/common_funcs.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "video_core/gpu.h" | ||
| 13 | #include "video_core/memory_manager.h" | ||
| 14 | |||
| 15 | namespace Tegra { | ||
| 16 | namespace Engines { | ||
| 17 | |||
| 18 | class MaxwellDMA final { | ||
| 19 | public: | ||
| 20 | explicit MaxwellDMA(MemoryManager& memory_manager); | ||
| 21 | ~MaxwellDMA() = default; | ||
| 22 | |||
| 23 | /// Write the value to the register identified by method. | ||
| 24 | void WriteReg(u32 method, u32 value); | ||
| 25 | |||
| 26 | struct Regs { | ||
| 27 | static constexpr size_t NUM_REGS = 0x1D6; | ||
| 28 | |||
| 29 | struct Parameters { | ||
| 30 | union { | ||
| 31 | BitField<0, 4, u32> block_depth; | ||
| 32 | BitField<4, 4, u32> block_height; | ||
| 33 | BitField<8, 4, u32> block_width; | ||
| 34 | }; | ||
| 35 | u32 size_x; | ||
| 36 | u32 size_y; | ||
| 37 | u32 size_z; | ||
| 38 | u32 pos_z; | ||
| 39 | union { | ||
| 40 | BitField<0, 16, u32> pos_x; | ||
| 41 | BitField<16, 16, u32> pos_y; | ||
| 42 | }; | ||
| 43 | |||
| 44 | u32 BlockHeight() const { | ||
| 45 | return 1 << block_height; | ||
| 46 | } | ||
| 47 | }; | ||
| 48 | |||
| 49 | static_assert(sizeof(Parameters) == 24, "Parameters has wrong size"); | ||
| 50 | |||
| 51 | enum class CopyMode : u32 { | ||
| 52 | None = 0, | ||
| 53 | Unk1 = 1, | ||
| 54 | Unk2 = 2, | ||
| 55 | }; | ||
| 56 | |||
| 57 | enum class QueryMode : u32 { | ||
| 58 | None = 0, | ||
| 59 | Short = 1, | ||
| 60 | Long = 2, | ||
| 61 | }; | ||
| 62 | |||
| 63 | enum class QueryIntr : u32 { | ||
| 64 | None = 0, | ||
| 65 | Block = 1, | ||
| 66 | NonBlock = 2, | ||
| 67 | }; | ||
| 68 | |||
| 69 | union { | ||
| 70 | struct { | ||
| 71 | INSERT_PADDING_WORDS(0xC0); | ||
| 72 | |||
| 73 | struct { | ||
| 74 | union { | ||
| 75 | BitField<0, 2, CopyMode> copy_mode; | ||
| 76 | BitField<2, 1, u32> flush; | ||
| 77 | |||
| 78 | BitField<3, 2, QueryMode> query_mode; | ||
| 79 | BitField<5, 2, QueryIntr> query_intr; | ||
| 80 | |||
| 81 | BitField<7, 1, u32> is_src_linear; | ||
| 82 | BitField<8, 1, u32> is_dst_linear; | ||
| 83 | |||
| 84 | BitField<9, 1, u32> enable_2d; | ||
| 85 | BitField<10, 1, u32> enable_swizzle; | ||
| 86 | }; | ||
| 87 | } exec; | ||
| 88 | |||
| 89 | INSERT_PADDING_WORDS(0x3F); | ||
| 90 | |||
| 91 | struct { | ||
| 92 | u32 address_high; | ||
| 93 | u32 address_low; | ||
| 94 | |||
| 95 | GPUVAddr Address() const { | ||
| 96 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | | ||
| 97 | address_low); | ||
| 98 | } | ||
| 99 | } src_address; | ||
| 100 | |||
| 101 | struct { | ||
| 102 | u32 address_high; | ||
| 103 | u32 address_low; | ||
| 104 | |||
| 105 | GPUVAddr Address() const { | ||
| 106 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | | ||
| 107 | address_low); | ||
| 108 | } | ||
| 109 | } dst_address; | ||
| 110 | |||
| 111 | u32 src_pitch; | ||
| 112 | u32 dst_pitch; | ||
| 113 | u32 x_count; | ||
| 114 | u32 y_count; | ||
| 115 | |||
| 116 | INSERT_PADDING_WORDS(0xBB); | ||
| 117 | |||
| 118 | Parameters dst_params; | ||
| 119 | |||
| 120 | INSERT_PADDING_WORDS(1); | ||
| 121 | |||
| 122 | Parameters src_params; | ||
| 123 | |||
| 124 | INSERT_PADDING_WORDS(0x13); | ||
| 125 | }; | ||
| 126 | std::array<u32, NUM_REGS> reg_array; | ||
| 127 | }; | ||
| 128 | } regs{}; | ||
| 129 | |||
| 130 | MemoryManager& memory_manager; | ||
| 131 | |||
| 132 | private: | ||
| 133 | /// Performs the copy from the source buffer to the destination buffer as configured in the | ||
| 134 | /// registers. | ||
| 135 | void HandleCopy(); | ||
| 136 | }; | ||
| 137 | |||
| 138 | #define ASSERT_REG_POSITION(field_name, position) \ | ||
| 139 | static_assert(offsetof(MaxwellDMA::Regs, field_name) == position * 4, \ | ||
| 140 | "Field " #field_name " has invalid position") | ||
| 141 | |||
| 142 | ASSERT_REG_POSITION(exec, 0xC0); | ||
| 143 | ASSERT_REG_POSITION(src_address, 0x100); | ||
| 144 | ASSERT_REG_POSITION(dst_address, 0x102); | ||
| 145 | ASSERT_REG_POSITION(src_pitch, 0x104); | ||
| 146 | ASSERT_REG_POSITION(dst_pitch, 0x105); | ||
| 147 | ASSERT_REG_POSITION(x_count, 0x106); | ||
| 148 | ASSERT_REG_POSITION(y_count, 0x107); | ||
| 149 | ASSERT_REG_POSITION(dst_params, 0x1C3); | ||
| 150 | ASSERT_REG_POSITION(src_params, 0x1CA); | ||
| 151 | |||
| 152 | #undef ASSERT_REG_POSITION | ||
| 153 | |||
| 154 | } // namespace Engines | ||
| 155 | } // namespace Tegra | ||
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index ec8dbd370..2bc1782ad 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -142,6 +142,7 @@ enum class PredCondition : u64 { | |||
| 142 | GreaterThan = 4, | 142 | GreaterThan = 4, |
| 143 | NotEqual = 5, | 143 | NotEqual = 5, |
| 144 | GreaterEqual = 6, | 144 | GreaterEqual = 6, |
| 145 | NotEqualWithNan = 13, | ||
| 145 | // TODO(Subv): Other condition types | 146 | // TODO(Subv): Other condition types |
| 146 | }; | 147 | }; |
| 147 | 148 | ||
| @@ -165,7 +166,7 @@ enum class SubOp : u64 { | |||
| 165 | Lg2 = 0x3, | 166 | Lg2 = 0x3, |
| 166 | Rcp = 0x4, | 167 | Rcp = 0x4, |
| 167 | Rsq = 0x5, | 168 | Rsq = 0x5, |
| 168 | Min = 0x8, | 169 | Sqrt = 0x8, |
| 169 | }; | 170 | }; |
| 170 | 171 | ||
| 171 | enum class F2iRoundingOp : u64 { | 172 | enum class F2iRoundingOp : u64 { |
| @@ -193,6 +194,13 @@ enum class UniformType : u64 { | |||
| 193 | Double = 5, | 194 | Double = 5, |
| 194 | }; | 195 | }; |
| 195 | 196 | ||
| 197 | enum class IMinMaxExchange : u64 { | ||
| 198 | None = 0, | ||
| 199 | XLo = 1, | ||
| 200 | XMed = 2, | ||
| 201 | XHi = 3, | ||
| 202 | }; | ||
| 203 | |||
| 196 | union Instruction { | 204 | union Instruction { |
| 197 | Instruction& operator=(const Instruction& instr) { | 205 | Instruction& operator=(const Instruction& instr) { |
| 198 | value = instr.value; | 206 | value = instr.value; |
| @@ -209,20 +217,19 @@ union Instruction { | |||
| 209 | } pred; | 217 | } pred; |
| 210 | BitField<19, 1, u64> negate_pred; | 218 | BitField<19, 1, u64> negate_pred; |
| 211 | BitField<20, 8, Register> gpr20; | 219 | BitField<20, 8, Register> gpr20; |
| 212 | BitField<20, 7, SubOp> sub_op; | 220 | BitField<20, 4, SubOp> sub_op; |
| 213 | BitField<28, 8, Register> gpr28; | 221 | BitField<28, 8, Register> gpr28; |
| 214 | BitField<39, 8, Register> gpr39; | 222 | BitField<39, 8, Register> gpr39; |
| 215 | BitField<48, 16, u64> opcode; | 223 | BitField<48, 16, u64> opcode; |
| 216 | BitField<50, 1, u64> saturate_a; | ||
| 217 | 224 | ||
| 218 | union { | 225 | union { |
| 219 | BitField<20, 19, u64> imm20_19; | 226 | BitField<20, 19, u64> imm20_19; |
| 220 | BitField<20, 32, u64> imm20_32; | 227 | BitField<20, 32, s64> imm20_32; |
| 221 | BitField<45, 1, u64> negate_b; | 228 | BitField<45, 1, u64> negate_b; |
| 222 | BitField<46, 1, u64> abs_a; | 229 | BitField<46, 1, u64> abs_a; |
| 223 | BitField<48, 1, u64> negate_a; | 230 | BitField<48, 1, u64> negate_a; |
| 224 | BitField<49, 1, u64> abs_b; | 231 | BitField<49, 1, u64> abs_b; |
| 225 | BitField<50, 1, u64> abs_d; | 232 | BitField<50, 1, u64> saturate_d; |
| 226 | BitField<56, 1, u64> negate_imm; | 233 | BitField<56, 1, u64> negate_imm; |
| 227 | 234 | ||
| 228 | union { | 235 | union { |
| @@ -231,10 +238,18 @@ union Instruction { | |||
| 231 | } fmnmx; | 238 | } fmnmx; |
| 232 | 239 | ||
| 233 | union { | 240 | union { |
| 241 | BitField<39, 1, u64> invert_a; | ||
| 242 | BitField<40, 1, u64> invert_b; | ||
| 243 | BitField<41, 2, LogicOperation> operation; | ||
| 244 | BitField<44, 2, u64> unk44; | ||
| 245 | BitField<48, 3, Pred> pred48; | ||
| 246 | } lop; | ||
| 247 | |||
| 248 | union { | ||
| 234 | BitField<53, 2, LogicOperation> operation; | 249 | BitField<53, 2, LogicOperation> operation; |
| 235 | BitField<55, 1, u64> invert_a; | 250 | BitField<55, 1, u64> invert_a; |
| 236 | BitField<56, 1, u64> invert_b; | 251 | BitField<56, 1, u64> invert_b; |
| 237 | } lop; | 252 | } lop32i; |
| 238 | 253 | ||
| 239 | float GetImm20_19() const { | 254 | float GetImm20_19() const { |
| 240 | float result{}; | 255 | float result{}; |
| @@ -247,7 +262,7 @@ union Instruction { | |||
| 247 | 262 | ||
| 248 | float GetImm20_32() const { | 263 | float GetImm20_32() const { |
| 249 | float result{}; | 264 | float result{}; |
| 250 | u32 imm{static_cast<u32>(imm20_32)}; | 265 | s32 imm{static_cast<s32>(imm20_32)}; |
| 251 | std::memcpy(&result, &imm, sizeof(imm)); | 266 | std::memcpy(&result, &imm, sizeof(imm)); |
| 252 | return result; | 267 | return result; |
| 253 | } | 268 | } |
| @@ -271,6 +286,18 @@ union Instruction { | |||
| 271 | } alu_integer; | 286 | } alu_integer; |
| 272 | 287 | ||
| 273 | union { | 288 | union { |
| 289 | BitField<39, 3, u64> pred; | ||
| 290 | BitField<42, 1, u64> negate_pred; | ||
| 291 | BitField<43, 2, IMinMaxExchange> exchange; | ||
| 292 | BitField<48, 1, u64> is_signed; | ||
| 293 | } imnmx; | ||
| 294 | |||
| 295 | union { | ||
| 296 | BitField<54, 1, u64> saturate; | ||
| 297 | BitField<56, 1, u64> negate_a; | ||
| 298 | } iadd32i; | ||
| 299 | |||
| 300 | union { | ||
| 274 | BitField<20, 8, u64> shift_position; | 301 | BitField<20, 8, u64> shift_position; |
| 275 | BitField<28, 8, u64> shift_length; | 302 | BitField<28, 8, u64> shift_length; |
| 276 | BitField<48, 1, u64> negate_b; | 303 | BitField<48, 1, u64> negate_b; |
| @@ -316,6 +343,19 @@ union Instruction { | |||
| 316 | } isetp; | 343 | } isetp; |
| 317 | 344 | ||
| 318 | union { | 345 | union { |
| 346 | BitField<0, 3, u64> pred0; | ||
| 347 | BitField<3, 3, u64> pred3; | ||
| 348 | BitField<12, 3, u64> pred12; | ||
| 349 | BitField<15, 1, u64> neg_pred12; | ||
| 350 | BitField<24, 2, PredOperation> cond; | ||
| 351 | BitField<29, 3, u64> pred29; | ||
| 352 | BitField<32, 1, u64> neg_pred29; | ||
| 353 | BitField<39, 3, u64> pred39; | ||
| 354 | BitField<42, 1, u64> neg_pred39; | ||
| 355 | BitField<45, 2, PredOperation> op; | ||
| 356 | } psetp; | ||
| 357 | |||
| 358 | union { | ||
| 319 | BitField<39, 3, u64> pred39; | 359 | BitField<39, 3, u64> pred39; |
| 320 | BitField<42, 1, u64> neg_pred; | 360 | BitField<42, 1, u64> neg_pred; |
| 321 | BitField<43, 1, u64> neg_a; | 361 | BitField<43, 1, u64> neg_a; |
| @@ -339,7 +379,8 @@ union Instruction { | |||
| 339 | } iset; | 379 | } iset; |
| 340 | 380 | ||
| 341 | union { | 381 | union { |
| 342 | BitField<10, 2, Register::Size> size; | 382 | BitField<8, 2, Register::Size> dest_size; |
| 383 | BitField<10, 2, Register::Size> src_size; | ||
| 343 | BitField<12, 1, u64> is_output_signed; | 384 | BitField<12, 1, u64> is_output_signed; |
| 344 | BitField<13, 1, u64> is_input_signed; | 385 | BitField<13, 1, u64> is_input_signed; |
| 345 | BitField<41, 2, u64> selector; | 386 | BitField<41, 2, u64> selector; |
| @@ -359,7 +400,7 @@ union Instruction { | |||
| 359 | BitField<31, 4, u64> component_mask; | 400 | BitField<31, 4, u64> component_mask; |
| 360 | 401 | ||
| 361 | bool IsComponentEnabled(size_t component) const { | 402 | bool IsComponentEnabled(size_t component) const { |
| 362 | return ((1 << component) & component_mask) != 0; | 403 | return ((1ull << component) & component_mask) != 0; |
| 363 | } | 404 | } |
| 364 | } tex; | 405 | } tex; |
| 365 | 406 | ||
| @@ -378,7 +419,7 @@ union Instruction { | |||
| 378 | 419 | ||
| 379 | ASSERT(component_mask_selector < mask.size()); | 420 | ASSERT(component_mask_selector < mask.size()); |
| 380 | 421 | ||
| 381 | return ((1 << component) & mask[component_mask_selector]) != 0; | 422 | return ((1ull << component) & mask[component_mask_selector]) != 0; |
| 382 | } | 423 | } |
| 383 | } texs; | 424 | } texs; |
| 384 | 425 | ||
| @@ -424,6 +465,8 @@ public: | |||
| 424 | enum class Id { | 465 | enum class Id { |
| 425 | KIL, | 466 | KIL, |
| 426 | SSY, | 467 | SSY, |
| 468 | SYNC, | ||
| 469 | DEPBAR, | ||
| 427 | BFE_C, | 470 | BFE_C, |
| 428 | BFE_R, | 471 | BFE_R, |
| 429 | BFE_IMM, | 472 | BFE_IMM, |
| @@ -451,6 +494,7 @@ public: | |||
| 451 | IADD_C, | 494 | IADD_C, |
| 452 | IADD_R, | 495 | IADD_R, |
| 453 | IADD_IMM, | 496 | IADD_IMM, |
| 497 | IADD32I, | ||
| 454 | ISCADD_C, // Scale and Add | 498 | ISCADD_C, // Scale and Add |
| 455 | ISCADD_R, | 499 | ISCADD_R, |
| 456 | ISCADD_IMM, | 500 | ISCADD_IMM, |
| @@ -470,6 +514,9 @@ public: | |||
| 470 | I2I_C, | 514 | I2I_C, |
| 471 | I2I_R, | 515 | I2I_R, |
| 472 | I2I_IMM, | 516 | I2I_IMM, |
| 517 | LOP_C, | ||
| 518 | LOP_R, | ||
| 519 | LOP_IMM, | ||
| 473 | LOP32I, | 520 | LOP32I, |
| 474 | MOV_C, | 521 | MOV_C, |
| 475 | MOV_R, | 522 | MOV_R, |
| @@ -509,12 +556,14 @@ public: | |||
| 509 | enum class Type { | 556 | enum class Type { |
| 510 | Trivial, | 557 | Trivial, |
| 511 | Arithmetic, | 558 | Arithmetic, |
| 559 | ArithmeticImmediate, | ||
| 512 | ArithmeticInteger, | 560 | ArithmeticInteger, |
| 561 | ArithmeticIntegerImmediate, | ||
| 513 | Bfe, | 562 | Bfe, |
| 514 | Logic, | ||
| 515 | Shift, | 563 | Shift, |
| 516 | Ffma, | 564 | Ffma, |
| 517 | Flow, | 565 | Flow, |
| 566 | Synch, | ||
| 518 | Memory, | 567 | Memory, |
| 519 | FloatSet, | 568 | FloatSet, |
| 520 | FloatSetPredicate, | 569 | FloatSetPredicate, |
| @@ -619,10 +668,12 @@ private: | |||
| 619 | INST("111000110011----", Id::KIL, Type::Flow, "KIL"), | 668 | INST("111000110011----", Id::KIL, Type::Flow, "KIL"), |
| 620 | INST("111000101001----", Id::SSY, Type::Flow, "SSY"), | 669 | INST("111000101001----", Id::SSY, Type::Flow, "SSY"), |
| 621 | INST("111000100100----", Id::BRA, Type::Flow, "BRA"), | 670 | INST("111000100100----", Id::BRA, Type::Flow, "BRA"), |
| 671 | INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"), | ||
| 672 | INST("1111000011111---", Id::SYNC, Type::Synch, "SYNC"), | ||
| 622 | INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), | 673 | INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), |
| 623 | INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"), | 674 | INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"), |
| 624 | INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), | 675 | INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), |
| 625 | INST("1100000000111---", Id::TEX, Type::Memory, "TEX"), | 676 | INST("110000----111---", Id::TEX, Type::Memory, "TEX"), |
| 626 | INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"), | 677 | INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"), |
| 627 | INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"), | 678 | INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"), |
| 628 | INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"), | 679 | INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"), |
| @@ -638,10 +689,11 @@ private: | |||
| 638 | INST("0100110001101---", Id::FMUL_C, Type::Arithmetic, "FMUL_C"), | 689 | INST("0100110001101---", Id::FMUL_C, Type::Arithmetic, "FMUL_C"), |
| 639 | INST("0101110001101---", Id::FMUL_R, Type::Arithmetic, "FMUL_R"), | 690 | INST("0101110001101---", Id::FMUL_R, Type::Arithmetic, "FMUL_R"), |
| 640 | INST("0011100-01101---", Id::FMUL_IMM, Type::Arithmetic, "FMUL_IMM"), | 691 | INST("0011100-01101---", Id::FMUL_IMM, Type::Arithmetic, "FMUL_IMM"), |
| 641 | INST("00011110--------", Id::FMUL32_IMM, Type::Arithmetic, "FMUL32_IMM"), | 692 | INST("00011110--------", Id::FMUL32_IMM, Type::ArithmeticImmediate, "FMUL32_IMM"), |
| 642 | INST("0100110000010---", Id::IADD_C, Type::ArithmeticInteger, "IADD_C"), | 693 | INST("0100110000010---", Id::IADD_C, Type::ArithmeticInteger, "IADD_C"), |
| 643 | INST("0101110000010---", Id::IADD_R, Type::ArithmeticInteger, "IADD_R"), | 694 | INST("0101110000010---", Id::IADD_R, Type::ArithmeticInteger, "IADD_R"), |
| 644 | INST("0011100-00010---", Id::IADD_IMM, Type::ArithmeticInteger, "IADD_IMM"), | 695 | INST("0011100-00010---", Id::IADD_IMM, Type::ArithmeticInteger, "IADD_IMM"), |
| 696 | INST("0001110---------", Id::IADD32I, Type::ArithmeticIntegerImmediate, "IADD32I"), | ||
| 645 | INST("0100110000011---", Id::ISCADD_C, Type::ArithmeticInteger, "ISCADD_C"), | 697 | INST("0100110000011---", Id::ISCADD_C, Type::ArithmeticInteger, "ISCADD_C"), |
| 646 | INST("0101110000011---", Id::ISCADD_R, Type::ArithmeticInteger, "ISCADD_R"), | 698 | INST("0101110000011---", Id::ISCADD_R, Type::ArithmeticInteger, "ISCADD_R"), |
| 647 | INST("0011100-00011---", Id::ISCADD_IMM, Type::ArithmeticInteger, "ISCADD_IMM"), | 699 | INST("0011100-00011---", Id::ISCADD_IMM, Type::ArithmeticInteger, "ISCADD_IMM"), |
| @@ -658,17 +710,20 @@ private: | |||
| 658 | INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"), | 710 | INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"), |
| 659 | INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"), | 711 | INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"), |
| 660 | INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"), | 712 | INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"), |
| 661 | INST("000000010000----", Id::MOV32_IMM, Type::Arithmetic, "MOV32_IMM"), | 713 | INST("000000010000----", Id::MOV32_IMM, Type::ArithmeticImmediate, "MOV32_IMM"), |
| 662 | INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"), | 714 | INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"), |
| 663 | INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"), | 715 | INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"), |
| 664 | INST("0011100-01100---", Id::FMNMX_IMM, Type::Arithmetic, "FMNMX_IMM"), | 716 | INST("0011100-01100---", Id::FMNMX_IMM, Type::Arithmetic, "FMNMX_IMM"), |
| 665 | INST("0100110000100---", Id::IMNMX_C, Type::Arithmetic, "FMNMX_IMM"), | 717 | INST("0100110000100---", Id::IMNMX_C, Type::ArithmeticInteger, "IMNMX_C"), |
| 666 | INST("0101110000100---", Id::IMNMX_R, Type::Arithmetic, "FMNMX_IMM"), | 718 | INST("0101110000100---", Id::IMNMX_R, Type::ArithmeticInteger, "IMNMX_R"), |
| 667 | INST("0011100-00100---", Id::IMNMX_IMM, Type::Arithmetic, "FMNMX_IMM"), | 719 | INST("0011100-00100---", Id::IMNMX_IMM, Type::ArithmeticInteger, "IMNMX_IMM"), |
| 668 | INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"), | 720 | INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"), |
| 669 | INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"), | 721 | INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"), |
| 670 | INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"), | 722 | INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"), |
| 671 | INST("000001----------", Id::LOP32I, Type::Logic, "LOP32I"), | 723 | INST("0100110001000---", Id::LOP_C, Type::ArithmeticInteger, "LOP_C"), |
| 724 | INST("0101110001000---", Id::LOP_R, Type::ArithmeticInteger, "LOP_R"), | ||
| 725 | INST("0011100001000---", Id::LOP_IMM, Type::ArithmeticInteger, "LOP_IMM"), | ||
| 726 | INST("000001----------", Id::LOP32I, Type::ArithmeticIntegerImmediate, "LOP32I"), | ||
| 672 | INST("0100110001001---", Id::SHL_C, Type::Shift, "SHL_C"), | 727 | INST("0100110001001---", Id::SHL_C, Type::Shift, "SHL_C"), |
| 673 | INST("0101110001001---", Id::SHL_R, Type::Shift, "SHL_R"), | 728 | INST("0101110001001---", Id::SHL_R, Type::Shift, "SHL_R"), |
| 674 | INST("0011100-01001---", Id::SHL_IMM, Type::Shift, "SHL_IMM"), | 729 | INST("0011100-01001---", Id::SHL_IMM, Type::Shift, "SHL_IMM"), |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 66351fe6e..e36483145 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include "video_core/engines/fermi_2d.h" | 5 | #include "video_core/engines/fermi_2d.h" |
| 6 | #include "video_core/engines/maxwell_3d.h" | 6 | #include "video_core/engines/maxwell_3d.h" |
| 7 | #include "video_core/engines/maxwell_compute.h" | 7 | #include "video_core/engines/maxwell_compute.h" |
| 8 | #include "video_core/engines/maxwell_dma.h" | ||
| 8 | #include "video_core/gpu.h" | 9 | #include "video_core/gpu.h" |
| 9 | 10 | ||
| 10 | namespace Tegra { | 11 | namespace Tegra { |
| @@ -14,6 +15,7 @@ GPU::GPU() { | |||
| 14 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(*memory_manager); | 15 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(*memory_manager); |
| 15 | fermi_2d = std::make_unique<Engines::Fermi2D>(*memory_manager); | 16 | fermi_2d = std::make_unique<Engines::Fermi2D>(*memory_manager); |
| 16 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); | 17 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); |
| 18 | maxwell_dma = std::make_unique<Engines::MaxwellDMA>(*memory_manager); | ||
| 17 | } | 19 | } |
| 18 | 20 | ||
| 19 | GPU::~GPU() = default; | 21 | GPU::~GPU() = default; |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 5852b9619..cc5ca656e 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -16,6 +16,7 @@ namespace Tegra { | |||
| 16 | enum class RenderTargetFormat : u32 { | 16 | enum class RenderTargetFormat : u32 { |
| 17 | NONE = 0x0, | 17 | NONE = 0x0, |
| 18 | RGBA32_FLOAT = 0xC0, | 18 | RGBA32_FLOAT = 0xC0, |
| 19 | RGBA32_UINT = 0xC2, | ||
| 19 | RGBA16_FLOAT = 0xCA, | 20 | RGBA16_FLOAT = 0xCA, |
| 20 | RGB10_A2_UNORM = 0xD1, | 21 | RGB10_A2_UNORM = 0xD1, |
| 21 | RGBA8_UNORM = 0xD5, | 22 | RGBA8_UNORM = 0xD5, |
| @@ -23,6 +24,15 @@ enum class RenderTargetFormat : u32 { | |||
| 23 | R11G11B10_FLOAT = 0xE0, | 24 | R11G11B10_FLOAT = 0xE0, |
| 24 | }; | 25 | }; |
| 25 | 26 | ||
| 27 | enum class DepthFormat : u32 { | ||
| 28 | Z32_FLOAT = 0xA, | ||
| 29 | Z16_UNORM = 0x13, | ||
| 30 | S8_Z24_UNORM = 0x14, | ||
| 31 | Z24_X8_UNORM = 0x15, | ||
| 32 | Z24_S8_UNORM = 0x16, | ||
| 33 | Z24_C8_UNORM = 0x18, | ||
| 34 | }; | ||
| 35 | |||
| 26 | /// Returns the number of bytes per pixel of each rendertarget format. | 36 | /// Returns the number of bytes per pixel of each rendertarget format. |
| 27 | u32 RenderTargetBytesPerPixel(RenderTargetFormat format); | 37 | u32 RenderTargetBytesPerPixel(RenderTargetFormat format); |
| 28 | 38 | ||
| @@ -63,6 +73,7 @@ namespace Engines { | |||
| 63 | class Fermi2D; | 73 | class Fermi2D; |
| 64 | class Maxwell3D; | 74 | class Maxwell3D; |
| 65 | class MaxwellCompute; | 75 | class MaxwellCompute; |
| 76 | class MaxwellDMA; | ||
| 66 | } // namespace Engines | 77 | } // namespace Engines |
| 67 | 78 | ||
| 68 | enum class EngineID { | 79 | enum class EngineID { |
| @@ -103,6 +114,8 @@ private: | |||
| 103 | std::unique_ptr<Engines::Fermi2D> fermi_2d; | 114 | std::unique_ptr<Engines::Fermi2D> fermi_2d; |
| 104 | /// Compute engine | 115 | /// Compute engine |
| 105 | std::unique_ptr<Engines::MaxwellCompute> maxwell_compute; | 116 | std::unique_ptr<Engines::MaxwellCompute> maxwell_compute; |
| 117 | /// DMA engine | ||
| 118 | std::unique_ptr<Engines::MaxwellDMA> maxwell_dma; | ||
| 106 | }; | 119 | }; |
| 107 | 120 | ||
| 108 | } // namespace Tegra | 121 | } // namespace Tegra |
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 5cefce9fc..2f814a184 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -100,9 +100,9 @@ boost::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) { | |||
| 100 | 100 | ||
| 101 | boost::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) { | 101 | boost::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) { |
| 102 | VAddr base_addr = PageSlot(gpu_addr); | 102 | VAddr base_addr = PageSlot(gpu_addr); |
| 103 | ASSERT(base_addr != static_cast<u64>(PageStatus::Unmapped)); | ||
| 104 | 103 | ||
| 105 | if (base_addr == static_cast<u64>(PageStatus::Allocated)) { | 104 | if (base_addr == static_cast<u64>(PageStatus::Allocated) || |
| 105 | base_addr == static_cast<u64>(PageStatus::Unmapped)) { | ||
| 106 | return {}; | 106 | return {}; |
| 107 | } | 107 | } |
| 108 | 108 | ||
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index f0e48a802..499e84b89 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -19,6 +19,9 @@ public: | |||
| 19 | /// Draw the current batch of vertex arrays | 19 | /// Draw the current batch of vertex arrays |
| 20 | virtual void DrawArrays() = 0; | 20 | virtual void DrawArrays() = 0; |
| 21 | 21 | ||
| 22 | /// Clear the current framebuffer | ||
| 23 | virtual void Clear() = 0; | ||
| 24 | |||
| 22 | /// Notify rasterizer that the specified Maxwell register has been changed | 25 | /// Notify rasterizer that the specified Maxwell register has been changed |
| 23 | virtual void NotifyMaxwellRegisterChanged(u32 method) = 0; | 26 | virtual void NotifyMaxwellRegisterChanged(u32 method) = 0; |
| 24 | 27 | ||
| @@ -51,9 +54,8 @@ public: | |||
| 51 | } | 54 | } |
| 52 | 55 | ||
| 53 | /// Attempt to use a faster method to display the framebuffer to screen | 56 | /// Attempt to use a faster method to display the framebuffer to screen |
| 54 | virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, | 57 | virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, |
| 55 | VAddr framebuffer_addr, u32 pixel_stride, | 58 | u32 pixel_stride, ScreenInfo& screen_info) { |
| 56 | ScreenInfo& screen_info) { | ||
| 57 | return false; | 59 | return false; |
| 58 | } | 60 | } |
| 59 | 61 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 6f05f24a0..ea138d402 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -112,7 +112,7 @@ RasterizerOpenGL::RasterizerOpenGL() { | |||
| 112 | 112 | ||
| 113 | glEnable(GL_BLEND); | 113 | glEnable(GL_BLEND); |
| 114 | 114 | ||
| 115 | NGLOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); | 115 | LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | RasterizerOpenGL::~RasterizerOpenGL() { | 118 | RasterizerOpenGL::~RasterizerOpenGL() { |
| @@ -146,7 +146,6 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, | |||
| 146 | u64 size = end - start + 1; | 146 | u64 size = end - start + 1; |
| 147 | 147 | ||
| 148 | // Copy vertex array data | 148 | // Copy vertex array data |
| 149 | res_cache.FlushRegion(start, size, nullptr); | ||
| 150 | Memory::ReadBlock(*memory_manager->GpuToCpuAddress(start), array_ptr, size); | 149 | Memory::ReadBlock(*memory_manager->GpuToCpuAddress(start), array_ptr, size); |
| 151 | 150 | ||
| 152 | // Bind the vertex array to the buffer at the current offset. | 151 | // Bind the vertex array to the buffer at the current offset. |
| @@ -166,9 +165,9 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, | |||
| 166 | // assume every shader uses them all. | 165 | // assume every shader uses them all. |
| 167 | for (unsigned index = 0; index < 16; ++index) { | 166 | for (unsigned index = 0; index < 16; ++index) { |
| 168 | auto& attrib = regs.vertex_attrib_format[index]; | 167 | auto& attrib = regs.vertex_attrib_format[index]; |
| 169 | NGLOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}", | 168 | LOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}", |
| 170 | index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(), | 169 | index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(), |
| 171 | attrib.offset.Value(), attrib.IsNormalized()); | 170 | attrib.offset.Value(), attrib.IsNormalized()); |
| 172 | 171 | ||
| 173 | auto& buffer = regs.vertex_array[attrib.buffer]; | 172 | auto& buffer = regs.vertex_array[attrib.buffer]; |
| 174 | ASSERT(buffer.IsEnabled()); | 173 | ASSERT(buffer.IsEnabled()); |
| @@ -197,8 +196,8 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { | |||
| 197 | ASSERT_MSG(!gpu.regs.shader_config[0].enable, "VertexA is unsupported!"); | 196 | ASSERT_MSG(!gpu.regs.shader_config[0].enable, "VertexA is unsupported!"); |
| 198 | 197 | ||
| 199 | // Next available bindpoints to use when uploading the const buffers and textures to the GLSL | 198 | // Next available bindpoints to use when uploading the const buffers and textures to the GLSL |
| 200 | // shaders. | 199 | // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points. |
| 201 | u32 current_constbuffer_bindpoint = 0; | 200 | u32 current_constbuffer_bindpoint = uniform_buffers.size(); |
| 202 | u32 current_texture_bindpoint = 0; | 201 | u32 current_texture_bindpoint = 0; |
| 203 | 202 | ||
| 204 | for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) { | 203 | for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) { |
| @@ -252,8 +251,8 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { | |||
| 252 | break; | 251 | break; |
| 253 | } | 252 | } |
| 254 | default: | 253 | default: |
| 255 | NGLOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset=0x{:08X}", | 254 | LOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset=0x{:08X}", index, |
| 256 | index, shader_config.enable.Value(), shader_config.offset); | 255 | shader_config.enable.Value(), shader_config.offset); |
| 257 | UNREACHABLE(); | 256 | UNREACHABLE(); |
| 258 | } | 257 | } |
| 259 | 258 | ||
| @@ -298,17 +297,16 @@ bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) { | |||
| 298 | return true; | 297 | return true; |
| 299 | } | 298 | } |
| 300 | 299 | ||
| 301 | void RasterizerOpenGL::DrawArrays() { | 300 | std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, |
| 302 | if (accelerate_draw == AccelDraw::Disabled) | 301 | bool using_depth_fb) { |
| 303 | return; | ||
| 304 | |||
| 305 | MICROPROFILE_SCOPE(OpenGL_Drawing); | ||
| 306 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | 302 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 307 | 303 | ||
| 308 | // TODO(bunnei): Implement these | 304 | // Sync the depth test state before configuring the framebuffer surfaces. |
| 305 | SyncDepthTestState(); | ||
| 306 | |||
| 307 | // TODO(bunnei): Implement this | ||
| 309 | const bool has_stencil = false; | 308 | const bool has_stencil = false; |
| 310 | const bool using_color_fb = true; | 309 | |
| 311 | const bool using_depth_fb = false; | ||
| 312 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; | 310 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; |
| 313 | 311 | ||
| 314 | const bool write_color_fb = | 312 | const bool write_color_fb = |
| @@ -325,35 +323,21 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 325 | std::tie(color_surface, depth_surface, surfaces_rect) = | 323 | std::tie(color_surface, depth_surface, surfaces_rect) = |
| 326 | res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect); | 324 | res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect); |
| 327 | 325 | ||
| 328 | const u16 res_scale = color_surface != nullptr | ||
| 329 | ? color_surface->res_scale | ||
| 330 | : (depth_surface == nullptr ? 1u : depth_surface->res_scale); | ||
| 331 | |||
| 332 | MathUtil::Rectangle<u32> draw_rect{ | 326 | MathUtil::Rectangle<u32> draw_rect{ |
| 327 | static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left, | ||
| 328 | surfaces_rect.left, surfaces_rect.right)), // Left | ||
| 329 | static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top, | ||
| 330 | surfaces_rect.bottom, surfaces_rect.top)), // Top | ||
| 331 | static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.right, | ||
| 332 | surfaces_rect.left, surfaces_rect.right)), // Right | ||
| 333 | static_cast<u32>( | 333 | static_cast<u32>( |
| 334 | std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left * res_scale, | 334 | std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.bottom, |
| 335 | surfaces_rect.left, surfaces_rect.right)), // Left | 335 | surfaces_rect.bottom, surfaces_rect.top))}; // Bottom |
| 336 | static_cast<u32>( | ||
| 337 | std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top * res_scale, | ||
| 338 | surfaces_rect.bottom, surfaces_rect.top)), // Top | ||
| 339 | static_cast<u32>( | ||
| 340 | std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.right * res_scale, | ||
| 341 | surfaces_rect.left, surfaces_rect.right)), // Right | ||
| 342 | static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + | ||
| 343 | viewport_rect.bottom * res_scale, | ||
| 344 | surfaces_rect.bottom, surfaces_rect.top))}; // Bottom | ||
| 345 | 336 | ||
| 346 | // Bind the framebuffer surfaces | 337 | // Bind the framebuffer surfaces |
| 347 | BindFramebufferSurfaces(color_surface, depth_surface, has_stencil); | 338 | BindFramebufferSurfaces(color_surface, depth_surface, has_stencil); |
| 348 | 339 | ||
| 349 | // Sync the viewport | 340 | SyncViewport(surfaces_rect); |
| 350 | SyncViewport(surfaces_rect, res_scale); | ||
| 351 | |||
| 352 | // Sync the blend state registers | ||
| 353 | SyncBlendState(); | ||
| 354 | |||
| 355 | // TODO(bunnei): Sync framebuffer_scale uniform here | ||
| 356 | // TODO(bunnei): Sync scissorbox uniform(s) here | ||
| 357 | 341 | ||
| 358 | // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable | 342 | // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable |
| 359 | // scissor test to prevent drawing outside of the framebuffer region | 343 | // scissor test to prevent drawing outside of the framebuffer region |
| @@ -364,6 +348,66 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 364 | state.scissor.height = draw_rect.GetHeight(); | 348 | state.scissor.height = draw_rect.GetHeight(); |
| 365 | state.Apply(); | 349 | state.Apply(); |
| 366 | 350 | ||
| 351 | // Only return the surface to be marked as dirty if writing to it is enabled. | ||
| 352 | return std::make_pair(write_color_fb ? color_surface : nullptr, | ||
| 353 | write_depth_fb ? depth_surface : nullptr); | ||
| 354 | } | ||
| 355 | |||
| 356 | void RasterizerOpenGL::Clear() { | ||
| 357 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | ||
| 358 | |||
| 359 | bool use_color_fb = false; | ||
| 360 | bool use_depth_fb = false; | ||
| 361 | |||
| 362 | GLbitfield clear_mask = 0; | ||
| 363 | if (regs.clear_buffers.R && regs.clear_buffers.G && regs.clear_buffers.B && | ||
| 364 | regs.clear_buffers.A) { | ||
| 365 | clear_mask |= GL_COLOR_BUFFER_BIT; | ||
| 366 | use_color_fb = true; | ||
| 367 | } | ||
| 368 | if (regs.clear_buffers.Z) { | ||
| 369 | clear_mask |= GL_DEPTH_BUFFER_BIT; | ||
| 370 | use_depth_fb = true; | ||
| 371 | } | ||
| 372 | |||
| 373 | if (clear_mask == 0) | ||
| 374 | return; | ||
| 375 | |||
| 376 | auto [dirty_color_surface, dirty_depth_surface] = | ||
| 377 | ConfigureFramebuffers(use_color_fb, use_depth_fb); | ||
| 378 | |||
| 379 | // TODO(Subv): Support clearing only partial colors. | ||
| 380 | glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2], | ||
| 381 | regs.clear_color[3]); | ||
| 382 | glClearDepth(regs.clear_depth); | ||
| 383 | |||
| 384 | glClear(clear_mask); | ||
| 385 | |||
| 386 | // Mark framebuffer surfaces as dirty | ||
| 387 | if (dirty_color_surface != nullptr) { | ||
| 388 | res_cache.MarkSurfaceAsDirty(dirty_color_surface); | ||
| 389 | } | ||
| 390 | if (dirty_depth_surface != nullptr) { | ||
| 391 | res_cache.MarkSurfaceAsDirty(dirty_depth_surface); | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | void RasterizerOpenGL::DrawArrays() { | ||
| 396 | if (accelerate_draw == AccelDraw::Disabled) | ||
| 397 | return; | ||
| 398 | |||
| 399 | MICROPROFILE_SCOPE(OpenGL_Drawing); | ||
| 400 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | ||
| 401 | |||
| 402 | auto [dirty_color_surface, dirty_depth_surface] = | ||
| 403 | ConfigureFramebuffers(true, regs.zeta.Address() != 0); | ||
| 404 | |||
| 405 | SyncBlendState(); | ||
| 406 | SyncCullMode(); | ||
| 407 | |||
| 408 | // TODO(bunnei): Sync framebuffer_scale uniform here | ||
| 409 | // TODO(bunnei): Sync scissorbox uniform(s) here | ||
| 410 | |||
| 367 | // Draw the vertex batch | 411 | // Draw the vertex batch |
| 368 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; | 412 | const bool is_indexed = accelerate_draw == AccelDraw::Indexed; |
| 369 | const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()}; | 413 | const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()}; |
| @@ -420,14 +464,16 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 420 | 464 | ||
| 421 | const GLenum primitive_mode{MaxwellToGL::PrimitiveTopology(regs.draw.topology)}; | 465 | const GLenum primitive_mode{MaxwellToGL::PrimitiveTopology(regs.draw.topology)}; |
| 422 | if (is_indexed) { | 466 | if (is_indexed) { |
| 423 | const GLint index_min{static_cast<GLint>(regs.index_array.first)}; | 467 | const GLint base_vertex{static_cast<GLint>(regs.vb_element_base)}; |
| 424 | const GLint index_max{static_cast<GLint>(regs.index_array.first + regs.index_array.count)}; | 468 | |
| 425 | glDrawRangeElementsBaseVertex(primitive_mode, index_min, index_max, regs.index_array.count, | 469 | // Adjust the index buffer offset so it points to the first desired index. |
| 426 | MaxwellToGL::IndexFormat(regs.index_array.format), | 470 | index_buffer_offset += regs.index_array.first * regs.index_array.FormatSizeInBytes(); |
| 427 | reinterpret_cast<const void*>(index_buffer_offset), | 471 | |
| 428 | -index_min); | 472 | glDrawElementsBaseVertex(primitive_mode, regs.index_array.count, |
| 473 | MaxwellToGL::IndexFormat(regs.index_array.format), | ||
| 474 | reinterpret_cast<const void*>(index_buffer_offset), base_vertex); | ||
| 429 | } else { | 475 | } else { |
| 430 | glDrawArrays(primitive_mode, 0, regs.vertex_buffer.count); | 476 | glDrawArrays(primitive_mode, regs.vertex_buffer.first, regs.vertex_buffer.count); |
| 431 | } | 477 | } |
| 432 | 478 | ||
| 433 | // Disable scissor test | 479 | // Disable scissor test |
| @@ -437,24 +483,16 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 437 | 483 | ||
| 438 | // Unbind textures for potential future use as framebuffer attachments | 484 | // Unbind textures for potential future use as framebuffer attachments |
| 439 | for (auto& texture_unit : state.texture_units) { | 485 | for (auto& texture_unit : state.texture_units) { |
| 440 | texture_unit.texture_2d = 0; | 486 | texture_unit.Unbind(); |
| 441 | } | 487 | } |
| 442 | state.Apply(); | 488 | state.Apply(); |
| 443 | 489 | ||
| 444 | // Mark framebuffer surfaces as dirty | 490 | // Mark framebuffer surfaces as dirty |
| 445 | MathUtil::Rectangle<u32> draw_rect_unscaled{ | 491 | if (dirty_color_surface != nullptr) { |
| 446 | draw_rect.left / res_scale, draw_rect.top / res_scale, draw_rect.right / res_scale, | 492 | res_cache.MarkSurfaceAsDirty(dirty_color_surface); |
| 447 | draw_rect.bottom / res_scale}; | ||
| 448 | |||
| 449 | if (color_surface != nullptr && write_color_fb) { | ||
| 450 | auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled); | ||
| 451 | res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval), | ||
| 452 | color_surface); | ||
| 453 | } | 493 | } |
| 454 | if (depth_surface != nullptr && write_depth_fb) { | 494 | if (dirty_depth_surface != nullptr) { |
| 455 | auto interval = depth_surface->GetSubRectInterval(draw_rect_unscaled); | 495 | res_cache.MarkSurfaceAsDirty(dirty_depth_surface); |
| 456 | res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval), | ||
| 457 | depth_surface); | ||
| 458 | } | 496 | } |
| 459 | } | 497 | } |
| 460 | 498 | ||
| @@ -462,7 +500,7 @@ void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {} | |||
| 462 | 500 | ||
| 463 | void RasterizerOpenGL::FlushAll() { | 501 | void RasterizerOpenGL::FlushAll() { |
| 464 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); | 502 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); |
| 465 | res_cache.FlushAll(); | 503 | res_cache.FlushRegion(0, Kernel::VMManager::MAX_ADDRESS); |
| 466 | } | 504 | } |
| 467 | 505 | ||
| 468 | void RasterizerOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size) { | 506 | void RasterizerOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size) { |
| @@ -472,13 +510,13 @@ void RasterizerOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size) { | |||
| 472 | 510 | ||
| 473 | void RasterizerOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size) { | 511 | void RasterizerOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size) { |
| 474 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); | 512 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); |
| 475 | res_cache.InvalidateRegion(addr, size, nullptr); | 513 | res_cache.InvalidateRegion(addr, size); |
| 476 | } | 514 | } |
| 477 | 515 | ||
| 478 | void RasterizerOpenGL::FlushAndInvalidateRegion(Tegra::GPUVAddr addr, u64 size) { | 516 | void RasterizerOpenGL::FlushAndInvalidateRegion(Tegra::GPUVAddr addr, u64 size) { |
| 479 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); | 517 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); |
| 480 | res_cache.FlushRegion(addr, size); | 518 | res_cache.FlushRegion(addr, size); |
| 481 | res_cache.InvalidateRegion(addr, size, nullptr); | 519 | res_cache.InvalidateRegion(addr, size); |
| 482 | } | 520 | } |
| 483 | 521 | ||
| 484 | bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { | 522 | bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { |
| @@ -497,45 +535,28 @@ bool RasterizerOpenGL::AccelerateFill(const void* config) { | |||
| 497 | return true; | 535 | return true; |
| 498 | } | 536 | } |
| 499 | 537 | ||
| 500 | bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, | 538 | bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, |
| 501 | VAddr framebuffer_addr, u32 pixel_stride, | 539 | VAddr framebuffer_addr, u32 pixel_stride, |
| 502 | ScreenInfo& screen_info) { | 540 | ScreenInfo& screen_info) { |
| 503 | if (framebuffer_addr == 0) { | 541 | if (!framebuffer_addr) { |
| 504 | return false; | 542 | return {}; |
| 505 | } | 543 | } |
| 544 | |||
| 506 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); | 545 | MICROPROFILE_SCOPE(OpenGL_CacheManagement); |
| 507 | 546 | ||
| 508 | SurfaceParams src_params; | 547 | const auto& surface{res_cache.TryFindFramebufferSurface(framebuffer_addr)}; |
| 509 | src_params.cpu_addr = framebuffer_addr; | 548 | if (!surface) { |
| 510 | src_params.addr = res_cache.TryFindFramebufferGpuAddress(framebuffer_addr).get_value_or(0); | 549 | return {}; |
| 511 | src_params.width = std::min(framebuffer.width, pixel_stride); | ||
| 512 | src_params.height = framebuffer.height; | ||
| 513 | src_params.stride = pixel_stride; | ||
| 514 | src_params.is_tiled = true; | ||
| 515 | src_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight; | ||
| 516 | src_params.pixel_format = | ||
| 517 | SurfaceParams::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format); | ||
| 518 | src_params.component_type = | ||
| 519 | SurfaceParams::ComponentTypeFromGPUPixelFormat(framebuffer.pixel_format); | ||
| 520 | src_params.UpdateParams(); | ||
| 521 | |||
| 522 | MathUtil::Rectangle<u32> src_rect; | ||
| 523 | Surface src_surface; | ||
| 524 | std::tie(src_surface, src_rect) = | ||
| 525 | res_cache.GetSurfaceSubRect(src_params, ScaleMatch::Ignore, true); | ||
| 526 | |||
| 527 | if (src_surface == nullptr) { | ||
| 528 | return false; | ||
| 529 | } | 550 | } |
| 530 | 551 | ||
| 531 | u32 scaled_width = src_surface->GetScaledWidth(); | 552 | // Verify that the cached surface is the same size and format as the requested framebuffer |
| 532 | u32 scaled_height = src_surface->GetScaledHeight(); | 553 | const auto& params{surface->GetSurfaceParams()}; |
| 554 | const auto& pixel_format{SurfaceParams::PixelFormatFromGPUPixelFormat(config.pixel_format)}; | ||
| 555 | ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); | ||
| 556 | ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); | ||
| 557 | ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different"); | ||
| 533 | 558 | ||
| 534 | screen_info.display_texcoords = MathUtil::Rectangle<float>( | 559 | screen_info.display_texture = surface->Texture().handle; |
| 535 | (float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width, | ||
| 536 | (float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width); | ||
| 537 | |||
| 538 | screen_info.display_texture = src_surface->texture.handle; | ||
| 539 | 560 | ||
| 540 | return true; | 561 | return true; |
| 541 | } | 562 | } |
| @@ -608,32 +629,44 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr | |||
| 608 | 629 | ||
| 609 | boost::optional<VAddr> addr = gpu.memory_manager->GpuToCpuAddress(buffer.address); | 630 | boost::optional<VAddr> addr = gpu.memory_manager->GpuToCpuAddress(buffer.address); |
| 610 | 631 | ||
| 611 | std::vector<u8> data; | 632 | size_t size = 0; |
| 633 | |||
| 612 | if (used_buffer.IsIndirect()) { | 634 | if (used_buffer.IsIndirect()) { |
| 613 | // Buffer is accessed indirectly, so upload the entire thing | 635 | // Buffer is accessed indirectly, so upload the entire thing |
| 614 | data.resize(buffer.size * sizeof(float)); | 636 | size = buffer.size * sizeof(float); |
| 637 | |||
| 638 | if (size > MaxConstbufferSize) { | ||
| 639 | LOG_ERROR(HW_GPU, "indirect constbuffer size {} exceeds maximum {}", size, | ||
| 640 | MaxConstbufferSize); | ||
| 641 | size = MaxConstbufferSize; | ||
| 642 | } | ||
| 615 | } else { | 643 | } else { |
| 616 | // Buffer is accessed directly, upload just what we use | 644 | // Buffer is accessed directly, upload just what we use |
| 617 | data.resize(used_buffer.GetSize() * sizeof(float)); | 645 | size = used_buffer.GetSize() * sizeof(float); |
| 618 | } | 646 | } |
| 619 | 647 | ||
| 648 | // Align the actual size so it ends up being a multiple of vec4 to meet the OpenGL std140 | ||
| 649 | // UBO alignment requirements. | ||
| 650 | size = Common::AlignUp(size, sizeof(GLvec4)); | ||
| 651 | ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big"); | ||
| 652 | |||
| 653 | std::vector<u8> data(size); | ||
| 620 | Memory::ReadBlock(*addr, data.data(), data.size()); | 654 | Memory::ReadBlock(*addr, data.data(), data.size()); |
| 621 | 655 | ||
| 622 | glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer_draw_state.ssbo); | 656 | glBindBuffer(GL_UNIFORM_BUFFER, buffer_draw_state.ssbo); |
| 623 | glBufferData(GL_SHADER_STORAGE_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW); | 657 | glBufferData(GL_UNIFORM_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW); |
| 624 | glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); | 658 | glBindBuffer(GL_UNIFORM_BUFFER, 0); |
| 625 | 659 | ||
| 626 | // Now configure the bindpoint of the buffer inside the shader | 660 | // Now configure the bindpoint of the buffer inside the shader |
| 627 | std::string buffer_name = used_buffer.GetName(); | 661 | std::string buffer_name = used_buffer.GetName(); |
| 628 | GLuint index = | 662 | GLuint index = glGetProgramResourceIndex(program, GL_UNIFORM_BLOCK, buffer_name.c_str()); |
| 629 | glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, buffer_name.c_str()); | ||
| 630 | if (index != -1) | 663 | if (index != -1) |
| 631 | glShaderStorageBlockBinding(program, index, buffer_draw_state.bindpoint); | 664 | glUniformBlockBinding(program, index, buffer_draw_state.bindpoint); |
| 632 | } | 665 | } |
| 633 | 666 | ||
| 634 | state.Apply(); | 667 | state.Apply(); |
| 635 | 668 | ||
| 636 | return current_bindpoint + entries.size(); | 669 | return current_bindpoint + static_cast<u32>(entries.size()); |
| 637 | } | 670 | } |
| 638 | 671 | ||
| 639 | u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit, | 672 | u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit, |
| @@ -653,16 +686,23 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, | |||
| 653 | 686 | ||
| 654 | // Bind the uniform to the sampler. | 687 | // Bind the uniform to the sampler. |
| 655 | GLint uniform = glGetUniformLocation(program, entry.GetName().c_str()); | 688 | GLint uniform = glGetUniformLocation(program, entry.GetName().c_str()); |
| 656 | ASSERT(uniform != -1); | 689 | if (uniform == -1) { |
| 690 | continue; | ||
| 691 | } | ||
| 692 | |||
| 657 | glProgramUniform1i(program, uniform, current_bindpoint); | 693 | glProgramUniform1i(program, uniform, current_bindpoint); |
| 658 | 694 | ||
| 659 | const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); | 695 | const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); |
| 660 | ASSERT(texture.enabled); | 696 | |
| 697 | if (!texture.enabled) { | ||
| 698 | state.texture_units[current_bindpoint].texture_2d = 0; | ||
| 699 | continue; | ||
| 700 | } | ||
| 661 | 701 | ||
| 662 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); | 702 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); |
| 663 | Surface surface = res_cache.GetTextureSurface(texture); | 703 | Surface surface = res_cache.GetTextureSurface(texture); |
| 664 | if (surface != nullptr) { | 704 | if (surface != nullptr) { |
| 665 | state.texture_units[current_bindpoint].texture_2d = surface->texture.handle; | 705 | state.texture_units[current_bindpoint].texture_2d = surface->Texture().handle; |
| 666 | state.texture_units[current_bindpoint].swizzle.r = | 706 | state.texture_units[current_bindpoint].swizzle.r = |
| 667 | MaxwellToGL::SwizzleSource(texture.tic.x_source); | 707 | MaxwellToGL::SwizzleSource(texture.tic.x_source); |
| 668 | state.texture_units[current_bindpoint].swizzle.g = | 708 | state.texture_units[current_bindpoint].swizzle.g = |
| @@ -679,7 +719,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, | |||
| 679 | 719 | ||
| 680 | state.Apply(); | 720 | state.Apply(); |
| 681 | 721 | ||
| 682 | return current_unit + entries.size(); | 722 | return current_unit + static_cast<u32>(entries.size()); |
| 683 | } | 723 | } |
| 684 | 724 | ||
| 685 | void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, | 725 | void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, |
| @@ -688,16 +728,16 @@ void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, | |||
| 688 | state.Apply(); | 728 | state.Apply(); |
| 689 | 729 | ||
| 690 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | 730 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| 691 | color_surface != nullptr ? color_surface->texture.handle : 0, 0); | 731 | color_surface != nullptr ? color_surface->Texture().handle : 0, 0); |
| 692 | if (depth_surface != nullptr) { | 732 | if (depth_surface != nullptr) { |
| 693 | if (has_stencil) { | 733 | if (has_stencil) { |
| 694 | // attach both depth and stencil | 734 | // attach both depth and stencil |
| 695 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 735 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 696 | depth_surface->texture.handle, 0); | 736 | depth_surface->Texture().handle, 0); |
| 697 | } else { | 737 | } else { |
| 698 | // attach depth | 738 | // attach depth |
| 699 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | 739 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, |
| 700 | depth_surface->texture.handle, 0); | 740 | depth_surface->Texture().handle, 0); |
| 701 | // clear stencil attachment | 741 | // clear stencil attachment |
| 702 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | 742 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); |
| 703 | } | 743 | } |
| @@ -708,14 +748,14 @@ void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, | |||
| 708 | } | 748 | } |
| 709 | } | 749 | } |
| 710 | 750 | ||
| 711 | void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale) { | 751 | void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect) { |
| 712 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | 752 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 713 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; | 753 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; |
| 714 | 754 | ||
| 715 | state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left * res_scale; | 755 | state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left; |
| 716 | state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom * res_scale; | 756 | state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom; |
| 717 | state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth() * res_scale); | 757 | state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); |
| 718 | state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight() * res_scale); | 758 | state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); |
| 719 | } | 759 | } |
| 720 | 760 | ||
| 721 | void RasterizerOpenGL::SyncClipEnabled() { | 761 | void RasterizerOpenGL::SyncClipEnabled() { |
| @@ -727,7 +767,27 @@ void RasterizerOpenGL::SyncClipCoef() { | |||
| 727 | } | 767 | } |
| 728 | 768 | ||
| 729 | void RasterizerOpenGL::SyncCullMode() { | 769 | void RasterizerOpenGL::SyncCullMode() { |
| 730 | UNREACHABLE(); | 770 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 771 | |||
| 772 | state.cull.enabled = regs.cull.enabled != 0; | ||
| 773 | |||
| 774 | if (state.cull.enabled) { | ||
| 775 | state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face); | ||
| 776 | state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face); | ||
| 777 | |||
| 778 | const bool flip_triangles{regs.screen_y_control.triangle_rast_flip == 0 || | ||
| 779 | regs.viewport_transform[0].scale_y < 0.0f}; | ||
| 780 | |||
| 781 | // If the GPU is configured to flip the rasterized triangles, then we need to flip the | ||
| 782 | // notion of front and back. Note: We flip the triangles when the value of the register is 0 | ||
| 783 | // because OpenGL already does it for us. | ||
| 784 | if (flip_triangles) { | ||
| 785 | if (state.cull.front_face == GL_CCW) | ||
| 786 | state.cull.front_face = GL_CW; | ||
| 787 | else if (state.cull.front_face == GL_CW) | ||
| 788 | state.cull.front_face = GL_CCW; | ||
| 789 | } | ||
| 790 | } | ||
| 731 | } | 791 | } |
| 732 | 792 | ||
| 733 | void RasterizerOpenGL::SyncDepthScale() { | 793 | void RasterizerOpenGL::SyncDepthScale() { |
| @@ -738,9 +798,20 @@ void RasterizerOpenGL::SyncDepthOffset() { | |||
| 738 | UNREACHABLE(); | 798 | UNREACHABLE(); |
| 739 | } | 799 | } |
| 740 | 800 | ||
| 801 | void RasterizerOpenGL::SyncDepthTestState() { | ||
| 802 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | ||
| 803 | |||
| 804 | state.depth.test_enabled = regs.depth_test_enable != 0; | ||
| 805 | state.depth.write_mask = regs.depth_write_enabled ? GL_TRUE : GL_FALSE; | ||
| 806 | |||
| 807 | if (!state.depth.test_enabled) | ||
| 808 | return; | ||
| 809 | |||
| 810 | state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func); | ||
| 811 | } | ||
| 812 | |||
| 741 | void RasterizerOpenGL::SyncBlendState() { | 813 | void RasterizerOpenGL::SyncBlendState() { |
| 742 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | 814 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 743 | ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented"); | ||
| 744 | 815 | ||
| 745 | // TODO(Subv): Support more than just render target 0. | 816 | // TODO(Subv): Support more than just render target 0. |
| 746 | state.blend.enabled = regs.blend.enable[0] != 0; | 817 | state.blend.enabled = regs.blend.enable[0] != 0; |
| @@ -748,6 +819,7 @@ void RasterizerOpenGL::SyncBlendState() { | |||
| 748 | if (!state.blend.enabled) | 819 | if (!state.blend.enabled) |
| 749 | return; | 820 | return; |
| 750 | 821 | ||
| 822 | ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented"); | ||
| 751 | ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented"); | 823 | ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented"); |
| 752 | state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb); | 824 | state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb); |
| 753 | state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb); | 825 | state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index b7c8cf843..c406142e4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <utility> | ||
| 10 | #include <vector> | 11 | #include <vector> |
| 11 | #include <glad/glad.h> | 12 | #include <glad/glad.h> |
| 12 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| @@ -28,6 +29,7 @@ public: | |||
| 28 | ~RasterizerOpenGL() override; | 29 | ~RasterizerOpenGL() override; |
| 29 | 30 | ||
| 30 | void DrawArrays() override; | 31 | void DrawArrays() override; |
| 32 | void Clear() override; | ||
| 31 | void NotifyMaxwellRegisterChanged(u32 method) override; | 33 | void NotifyMaxwellRegisterChanged(u32 method) override; |
| 32 | void FlushAll() override; | 34 | void FlushAll() override; |
| 33 | void FlushRegion(Tegra::GPUVAddr addr, u64 size) override; | 35 | void FlushRegion(Tegra::GPUVAddr addr, u64 size) override; |
| @@ -54,6 +56,11 @@ public: | |||
| 54 | OGLShader shader; | 56 | OGLShader shader; |
| 55 | }; | 57 | }; |
| 56 | 58 | ||
| 59 | /// Maximum supported size that a constbuffer can have in bytes. | ||
| 60 | static constexpr size_t MaxConstbufferSize = 0x10000; | ||
| 61 | static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0, | ||
| 62 | "The maximum size of a constbuffer must be a multiple of the size of GLvec4"); | ||
| 63 | |||
| 57 | private: | 64 | private: |
| 58 | class SamplerInfo { | 65 | class SamplerInfo { |
| 59 | public: | 66 | public: |
| @@ -76,6 +83,10 @@ private: | |||
| 76 | u32 border_color_a; | 83 | u32 border_color_a; |
| 77 | }; | 84 | }; |
| 78 | 85 | ||
| 86 | /// Configures the color and depth framebuffer states and returns the dirty <Color, Depth> | ||
| 87 | /// surfaces if writing was enabled. | ||
| 88 | std::pair<Surface, Surface> ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb); | ||
| 89 | |||
| 79 | /// Binds the framebuffer color and depth surface | 90 | /// Binds the framebuffer color and depth surface |
| 80 | void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface, | 91 | void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface, |
| 81 | bool has_stencil); | 92 | bool has_stencil); |
| @@ -104,7 +115,7 @@ private: | |||
| 104 | u32 current_unit, const std::vector<GLShader::SamplerEntry>& entries); | 115 | u32 current_unit, const std::vector<GLShader::SamplerEntry>& entries); |
| 105 | 116 | ||
| 106 | /// Syncs the viewport to match the guest state | 117 | /// Syncs the viewport to match the guest state |
| 107 | void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale); | 118 | void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect); |
| 108 | 119 | ||
| 109 | /// Syncs the clip enabled status to match the guest state | 120 | /// Syncs the clip enabled status to match the guest state |
| 110 | void SyncClipEnabled(); | 121 | void SyncClipEnabled(); |
| @@ -121,6 +132,9 @@ private: | |||
| 121 | /// Syncs the depth offset to match the guest state | 132 | /// Syncs the depth offset to match the guest state |
| 122 | void SyncDepthOffset(); | 133 | void SyncDepthOffset(); |
| 123 | 134 | ||
| 135 | /// Syncs the depth test state to match the guest state | ||
| 136 | void SyncDepthTestState(); | ||
| 137 | |||
| 124 | /// Syncs the blend state to match the guest state | 138 | /// Syncs the blend state to match the guest state |
| 125 | void SyncBlendState(); | 139 | void SyncBlendState(); |
| 126 | 140 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index ff48a2669..323ff7408 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -1,36 +1,23 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | 1 | // Copyright 2018 yuzu Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <atomic> | ||
| 7 | #include <cstring> | ||
| 8 | #include <iterator> | ||
| 9 | #include <memory> | ||
| 10 | #include <utility> | ||
| 11 | #include <vector> | ||
| 12 | #include <boost/optional.hpp> | ||
| 13 | #include <boost/range/iterator_range.hpp> | ||
| 14 | #include <glad/glad.h> | 6 | #include <glad/glad.h> |
| 7 | |||
| 15 | #include "common/alignment.h" | 8 | #include "common/alignment.h" |
| 16 | #include "common/bit_field.h" | 9 | #include "common/assert.h" |
| 17 | #include "common/color.h" | ||
| 18 | #include "common/logging/log.h" | ||
| 19 | #include "common/math_util.h" | ||
| 20 | #include "common/microprofile.h" | 10 | #include "common/microprofile.h" |
| 21 | #include "common/scope_exit.h" | 11 | #include "common/scope_exit.h" |
| 22 | #include "core/core.h" | 12 | #include "core/core.h" |
| 23 | #include "core/frontend/emu_window.h" | ||
| 24 | #include "core/hle/kernel/process.h" | 13 | #include "core/hle/kernel/process.h" |
| 25 | #include "core/hle/kernel/vm_manager.h" | ||
| 26 | #include "core/memory.h" | 14 | #include "core/memory.h" |
| 27 | #include "core/settings.h" | 15 | #include "core/settings.h" |
| 28 | #include "video_core/engines/maxwell_3d.h" | 16 | #include "video_core/engines/maxwell_3d.h" |
| 29 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 17 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 30 | #include "video_core/renderer_opengl/gl_state.h" | 18 | #include "video_core/textures/astc.h" |
| 31 | #include "video_core/textures/decoders.h" | 19 | #include "video_core/textures/decoders.h" |
| 32 | #include "video_core/utils.h" | 20 | #include "video_core/utils.h" |
| 33 | #include "video_core/video_core.h" | ||
| 34 | 21 | ||
| 35 | using SurfaceType = SurfaceParams::SurfaceType; | 22 | using SurfaceType = SurfaceParams::SurfaceType; |
| 36 | using PixelFormat = SurfaceParams::PixelFormat; | 23 | using PixelFormat = SurfaceParams::PixelFormat; |
| @@ -40,89 +27,178 @@ struct FormatTuple { | |||
| 40 | GLint internal_format; | 27 | GLint internal_format; |
| 41 | GLenum format; | 28 | GLenum format; |
| 42 | GLenum type; | 29 | GLenum type; |
| 30 | ComponentType component_type; | ||
| 43 | bool compressed; | 31 | bool compressed; |
| 44 | }; | 32 | }; |
| 45 | 33 | ||
| 34 | /*static*/ SurfaceParams SurfaceParams::CreateForTexture( | ||
| 35 | const Tegra::Texture::FullTextureInfo& config) { | ||
| 36 | |||
| 37 | SurfaceParams params{}; | ||
| 38 | params.addr = config.tic.Address(); | ||
| 39 | params.is_tiled = config.tic.IsTiled(); | ||
| 40 | params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, | ||
| 41 | params.pixel_format = PixelFormatFromTextureFormat(config.tic.format); | ||
| 42 | params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); | ||
| 43 | params.type = GetFormatType(params.pixel_format); | ||
| 44 | params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); | ||
| 45 | params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); | ||
| 46 | params.unaligned_height = config.tic.Height(); | ||
| 47 | params.size_in_bytes = params.SizeInBytes(); | ||
| 48 | return params; | ||
| 49 | } | ||
| 50 | |||
| 51 | /*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer( | ||
| 52 | const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config) { | ||
| 53 | |||
| 54 | SurfaceParams params{}; | ||
| 55 | params.addr = config.Address(); | ||
| 56 | params.is_tiled = true; | ||
| 57 | params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight; | ||
| 58 | params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); | ||
| 59 | params.component_type = ComponentTypeFromRenderTarget(config.format); | ||
| 60 | params.type = GetFormatType(params.pixel_format); | ||
| 61 | params.width = config.width; | ||
| 62 | params.height = config.height; | ||
| 63 | params.unaligned_height = config.height; | ||
| 64 | params.size_in_bytes = params.SizeInBytes(); | ||
| 65 | return params; | ||
| 66 | } | ||
| 67 | |||
| 68 | /*static*/ SurfaceParams SurfaceParams::CreateForDepthBuffer( | ||
| 69 | const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config, Tegra::GPUVAddr zeta_address, | ||
| 70 | Tegra::DepthFormat format) { | ||
| 71 | |||
| 72 | SurfaceParams params{}; | ||
| 73 | params.addr = zeta_address; | ||
| 74 | params.is_tiled = true; | ||
| 75 | params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight; | ||
| 76 | params.pixel_format = PixelFormatFromDepthFormat(format); | ||
| 77 | params.component_type = ComponentTypeFromDepthFormat(format); | ||
| 78 | params.type = GetFormatType(params.pixel_format); | ||
| 79 | params.size_in_bytes = params.SizeInBytes(); | ||
| 80 | params.width = config.width; | ||
| 81 | params.height = config.height; | ||
| 82 | params.unaligned_height = config.height; | ||
| 83 | params.size_in_bytes = params.SizeInBytes(); | ||
| 84 | return params; | ||
| 85 | } | ||
| 86 | |||
| 46 | static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{ | 87 | static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{ |
| 47 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // ABGR8 | 88 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8 |
| 48 | {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false}, // B5G6R5 | 89 | {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5 |
| 49 | {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false}, // A2B10G10R10 | 90 | {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm, |
| 50 | {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false}, // A1B5G5R5 | 91 | false}, // A2B10G10R10 |
| 51 | {GL_R8, GL_RED, GL_UNSIGNED_BYTE, false}, // R8 | 92 | {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5 |
| 52 | {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, false}, // RGBA16F | 93 | {GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8 |
| 53 | {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, false}, // R11FG11FB10F | 94 | {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBA16F |
| 54 | {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT1 | 95 | {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float, |
| 55 | {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT23 | 96 | false}, // R11FG11FB10F |
| 56 | {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT45 | 97 | {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI |
| 57 | {GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, true}, // DXN1 | 98 | {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 99 | true}, // DXT1 | ||
| 100 | {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 101 | true}, // DXT23 | ||
| 102 | {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 103 | true}, // DXT45 | ||
| 104 | {GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXN1 | ||
| 105 | {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 106 | true}, // BC7U | ||
| 107 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 | ||
| 108 | |||
| 109 | // DepthStencil formats | ||
| 110 | {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, | ||
| 111 | false}, // Z24S8 | ||
| 112 | {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, | ||
| 113 | false}, // S8Z24 | ||
| 114 | {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F | ||
| 58 | }}; | 115 | }}; |
| 59 | 116 | ||
| 60 | static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { | 117 | static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { |
| 61 | const SurfaceType type = SurfaceParams::GetFormatType(pixel_format); | 118 | ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size()); |
| 62 | if (type == SurfaceType::ColorTexture) { | 119 | auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)]; |
| 63 | ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size()); | 120 | ASSERT(component_type == format.component_type); |
| 64 | // For now only UNORM components are supported, or either R11FG11FB10F or RGBA16F which are | ||
| 65 | // type FLOAT | ||
| 66 | ASSERT(component_type == ComponentType::UNorm || pixel_format == PixelFormat::RGBA16F || | ||
| 67 | pixel_format == PixelFormat::R11FG11FB10F); | ||
| 68 | return tex_format_tuples[static_cast<unsigned int>(pixel_format)]; | ||
| 69 | } else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) { | ||
| 70 | // TODO(Subv): Implement depth formats | ||
| 71 | ASSERT_MSG(false, "Unimplemented"); | ||
| 72 | } | ||
| 73 | 121 | ||
| 74 | UNREACHABLE(); | 122 | return format; |
| 75 | return {}; | ||
| 76 | } | 123 | } |
| 77 | 124 | ||
| 78 | template <typename Map, typename Interval> | 125 | VAddr SurfaceParams::GetCpuAddr() const { |
| 79 | constexpr auto RangeFromInterval(Map& map, const Interval& interval) { | 126 | const auto& gpu = Core::System::GetInstance().GPU(); |
| 80 | return boost::make_iterator_range(map.equal_range(interval)); | 127 | return *gpu.memory_manager->GpuToCpuAddress(addr); |
| 81 | } | 128 | } |
| 82 | 129 | ||
| 83 | static u16 GetResolutionScaleFactor() { | 130 | static bool IsPixelFormatASTC(PixelFormat format) { |
| 84 | return static_cast<u16>(!Settings::values.resolution_factor | 131 | switch (format) { |
| 85 | ? VideoCore::g_emu_window->GetFramebufferLayout().GetScalingRatio() | 132 | case PixelFormat::ASTC_2D_4X4: |
| 86 | : Settings::values.resolution_factor); | 133 | return true; |
| 134 | default: | ||
| 135 | return false; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) { | ||
| 140 | switch (format) { | ||
| 141 | case PixelFormat::ASTC_2D_4X4: | ||
| 142 | return {4, 4}; | ||
| 143 | default: | ||
| 144 | LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format)); | ||
| 145 | UNREACHABLE(); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | MathUtil::Rectangle<u32> SurfaceParams::GetRect() const { | ||
| 150 | u32 actual_height{unaligned_height}; | ||
| 151 | if (IsPixelFormatASTC(pixel_format)) { | ||
| 152 | // ASTC formats must stop at the ATSC block size boundary | ||
| 153 | actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second); | ||
| 154 | } | ||
| 155 | return {0, actual_height, width, 0}; | ||
| 87 | } | 156 | } |
| 88 | 157 | ||
| 89 | template <bool morton_to_gl, PixelFormat format> | 158 | template <bool morton_to_gl, PixelFormat format> |
| 90 | void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, Tegra::GPUVAddr base, | 159 | void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, Tegra::GPUVAddr addr) { |
| 91 | Tegra::GPUVAddr start, Tegra::GPUVAddr end) { | ||
| 92 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; | 160 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; |
| 93 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); | 161 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); |
| 94 | const auto& gpu = Core::System::GetInstance().GPU(); | 162 | const auto& gpu = Core::System::GetInstance().GPU(); |
| 95 | 163 | ||
| 96 | if (morton_to_gl) { | 164 | if (morton_to_gl) { |
| 97 | auto data = Tegra::Texture::UnswizzleTexture( | 165 | if (SurfaceParams::GetFormatType(format) == SurfaceType::ColorTexture) { |
| 98 | *gpu.memory_manager->GpuToCpuAddress(base), | 166 | auto data = Tegra::Texture::UnswizzleTexture( |
| 99 | SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height); | 167 | *gpu.memory_manager->GpuToCpuAddress(addr), |
| 100 | std::memcpy(gl_buffer, data.data(), data.size()); | 168 | SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height); |
| 169 | std::memcpy(gl_buffer, data.data(), data.size()); | ||
| 170 | } else { | ||
| 171 | auto data = Tegra::Texture::UnswizzleDepthTexture( | ||
| 172 | *gpu.memory_manager->GpuToCpuAddress(addr), | ||
| 173 | SurfaceParams::DepthFormatFromPixelFormat(format), stride, height, block_height); | ||
| 174 | std::memcpy(gl_buffer, data.data(), data.size()); | ||
| 175 | } | ||
| 101 | } else { | 176 | } else { |
| 102 | // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check | 177 | // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should |
| 103 | // the configuration for this and perform more generic un/swizzle | 178 | // check the configuration for this and perform more generic un/swizzle |
| 104 | NGLOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); | 179 | LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); |
| 105 | VideoCore::MortonCopyPixels128( | 180 | VideoCore::MortonCopyPixels128( |
| 106 | stride, height, bytes_per_pixel, gl_bytes_per_pixel, | 181 | stride, height, bytes_per_pixel, gl_bytes_per_pixel, |
| 107 | Memory::GetPointer(*gpu.memory_manager->GpuToCpuAddress(base)), gl_buffer, | 182 | Memory::GetPointer(*gpu.memory_manager->GpuToCpuAddress(addr)), gl_buffer, |
| 108 | morton_to_gl); | 183 | morton_to_gl); |
| 109 | } | 184 | } |
| 110 | } | 185 | } |
| 111 | 186 | ||
| 112 | static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr, Tegra::GPUVAddr, | 187 | static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr), |
| 113 | Tegra::GPUVAddr), | ||
| 114 | SurfaceParams::MaxPixelFormat> | 188 | SurfaceParams::MaxPixelFormat> |
| 115 | morton_to_gl_fns = { | 189 | morton_to_gl_fns = { |
| 116 | MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>, | 190 | MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>, |
| 117 | MortonCopy<true, PixelFormat::A2B10G10R10>, MortonCopy<true, PixelFormat::A1B5G5R5>, | 191 | MortonCopy<true, PixelFormat::A2B10G10R10>, MortonCopy<true, PixelFormat::A1B5G5R5>, |
| 118 | MortonCopy<true, PixelFormat::R8>, MortonCopy<true, PixelFormat::RGBA16F>, | 192 | MortonCopy<true, PixelFormat::R8>, MortonCopy<true, PixelFormat::RGBA16F>, |
| 119 | MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::DXT1>, | 193 | MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::RGBA32UI>, |
| 120 | MortonCopy<true, PixelFormat::DXT23>, MortonCopy<true, PixelFormat::DXT45>, | 194 | MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>, |
| 121 | MortonCopy<true, PixelFormat::DXN1>, | 195 | MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>, |
| 196 | MortonCopy<true, PixelFormat::BC7U>, MortonCopy<true, PixelFormat::ASTC_2D_4X4>, | ||
| 197 | MortonCopy<true, PixelFormat::Z24S8>, MortonCopy<true, PixelFormat::S8Z24>, | ||
| 198 | MortonCopy<true, PixelFormat::Z32F>, | ||
| 122 | }; | 199 | }; |
| 123 | 200 | ||
| 124 | static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr, Tegra::GPUVAddr, | 201 | static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr), |
| 125 | Tegra::GPUVAddr), | ||
| 126 | SurfaceParams::MaxPixelFormat> | 202 | SurfaceParams::MaxPixelFormat> |
| 127 | gl_to_morton_fns = { | 203 | gl_to_morton_fns = { |
| 128 | MortonCopy<false, PixelFormat::ABGR8>, | 204 | MortonCopy<false, PixelFormat::ABGR8>, |
| @@ -132,11 +208,17 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr, Tegra: | |||
| 132 | MortonCopy<false, PixelFormat::R8>, | 208 | MortonCopy<false, PixelFormat::R8>, |
| 133 | MortonCopy<false, PixelFormat::RGBA16F>, | 209 | MortonCopy<false, PixelFormat::RGBA16F>, |
| 134 | MortonCopy<false, PixelFormat::R11FG11FB10F>, | 210 | MortonCopy<false, PixelFormat::R11FG11FB10F>, |
| 135 | // TODO(Subv): Swizzling the DXT1/DXT23/DXT45/DXN1 formats is not yet supported | 211 | MortonCopy<false, PixelFormat::RGBA32UI>, |
| 212 | // TODO(Subv): Swizzling the DXT1/DXT23/DXT45/DXN1/BC7U formats is not yet supported | ||
| 213 | nullptr, | ||
| 136 | nullptr, | 214 | nullptr, |
| 137 | nullptr, | 215 | nullptr, |
| 138 | nullptr, | 216 | nullptr, |
| 139 | nullptr, | 217 | nullptr, |
| 218 | MortonCopy<false, PixelFormat::ABGR8>, | ||
| 219 | MortonCopy<false, PixelFormat::Z24S8>, | ||
| 220 | MortonCopy<false, PixelFormat::S8Z24>, | ||
| 221 | MortonCopy<false, PixelFormat::Z32F>, | ||
| 140 | }; | 222 | }; |
| 141 | 223 | ||
| 142 | // Allocate an uninitialized texture of appropriate size and format for the surface | 224 | // Allocate an uninitialized texture of appropriate size and format for the surface |
| @@ -166,374 +248,144 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup | |||
| 166 | cur_state.Apply(); | 248 | cur_state.Apply(); |
| 167 | } | 249 | } |
| 168 | 250 | ||
| 169 | static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex, | 251 | CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) { |
| 170 | const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type, | 252 | texture.Create(); |
| 171 | GLuint read_fb_handle, GLuint draw_fb_handle) { | 253 | const auto& rect{params.GetRect()}; |
| 172 | 254 | AllocateSurfaceTexture(texture.handle, | |
| 173 | glCopyImageSubData(src_tex, GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom, 0, dst_tex, | 255 | GetFormatTuple(params.pixel_format, params.component_type), |
| 174 | GL_TEXTURE_2D, 0, dst_rect.left, dst_rect.bottom, 0, src_rect.GetWidth(), | 256 | rect.GetWidth(), rect.GetHeight()); |
| 175 | src_rect.GetHeight(), 0); | 257 | } |
| 176 | return true; | 258 | |
| 177 | } | 259 | static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { |
| 178 | 260 | union S8Z24 { | |
| 179 | static bool FillSurface(const Surface& surface, const u8* fill_data, | 261 | BitField<0, 24, u32> z24; |
| 180 | const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) { | 262 | BitField<24, 8, u32> s8; |
| 181 | UNREACHABLE(); | 263 | }; |
| 182 | return {}; | 264 | static_assert(sizeof(S8Z24) == 4, "S8Z24 is incorrect size"); |
| 183 | } | 265 | |
| 184 | 266 | union Z24S8 { | |
| 185 | SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const { | 267 | BitField<0, 8, u32> s8; |
| 186 | SurfaceParams params = *this; | 268 | BitField<8, 24, u32> z24; |
| 187 | const u32 tiled_size = is_tiled ? 8 : 1; | 269 | }; |
| 188 | const u64 stride_tiled_bytes = BytesInPixels(stride * tiled_size); | 270 | static_assert(sizeof(Z24S8) == 4, "Z24S8 is incorrect size"); |
| 189 | Tegra::GPUVAddr aligned_start = | 271 | |
| 190 | addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes); | 272 | S8Z24 input_pixel{}; |
| 191 | Tegra::GPUVAddr aligned_end = | 273 | Z24S8 output_pixel{}; |
| 192 | addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes); | 274 | for (size_t y = 0; y < height; ++y) { |
| 193 | 275 | for (size_t x = 0; x < width; ++x) { | |
| 194 | if (aligned_end - aligned_start > stride_tiled_bytes) { | 276 | const size_t offset{y * width + x}; |
| 195 | params.addr = aligned_start; | 277 | std::memcpy(&input_pixel, &data[offset], sizeof(S8Z24)); |
| 196 | params.height = static_cast<u32>((aligned_end - aligned_start) / BytesInPixels(stride)); | 278 | output_pixel.s8.Assign(input_pixel.s8); |
| 197 | } else { | 279 | output_pixel.z24.Assign(input_pixel.z24); |
| 198 | // 1 row | 280 | std::memcpy(&data[offset], &output_pixel, sizeof(Z24S8)); |
| 199 | ASSERT(aligned_end - aligned_start == stride_tiled_bytes); | ||
| 200 | const u64 tiled_alignment = BytesInPixels(is_tiled ? 8 * 8 : 1); | ||
| 201 | aligned_start = | ||
| 202 | addr + Common::AlignDown(boost::icl::first(interval) - addr, tiled_alignment); | ||
| 203 | aligned_end = | ||
| 204 | addr + Common::AlignUp(boost::icl::last_next(interval) - addr, tiled_alignment); | ||
| 205 | params.addr = aligned_start; | ||
| 206 | params.width = static_cast<u32>(PixelsInBytes(aligned_end - aligned_start) / tiled_size); | ||
| 207 | params.stride = params.width; | ||
| 208 | params.height = tiled_size; | ||
| 209 | } | ||
| 210 | params.UpdateParams(); | ||
| 211 | |||
| 212 | return params; | ||
| 213 | } | ||
| 214 | |||
| 215 | SurfaceInterval SurfaceParams::GetSubRectInterval(MathUtil::Rectangle<u32> unscaled_rect) const { | ||
| 216 | if (unscaled_rect.GetHeight() == 0 || unscaled_rect.GetWidth() == 0) { | ||
| 217 | return {}; | ||
| 218 | } | ||
| 219 | |||
| 220 | if (is_tiled) { | ||
| 221 | unscaled_rect.left = Common::AlignDown(unscaled_rect.left, 8) * 8; | ||
| 222 | unscaled_rect.bottom = Common::AlignDown(unscaled_rect.bottom, 8) / 8; | ||
| 223 | unscaled_rect.right = Common::AlignUp(unscaled_rect.right, 8) * 8; | ||
| 224 | unscaled_rect.top = Common::AlignUp(unscaled_rect.top, 8) / 8; | ||
| 225 | } | ||
| 226 | |||
| 227 | const u32 stride_tiled = !is_tiled ? stride : stride * 8; | ||
| 228 | |||
| 229 | const u32 pixel_offset = | ||
| 230 | stride_tiled * (!is_tiled ? unscaled_rect.bottom : (height / 8) - unscaled_rect.top) + | ||
| 231 | unscaled_rect.left; | ||
| 232 | |||
| 233 | const u32 pixels = (unscaled_rect.GetHeight() - 1) * stride_tiled + unscaled_rect.GetWidth(); | ||
| 234 | |||
| 235 | return {addr + BytesInPixels(pixel_offset), addr + BytesInPixels(pixel_offset + pixels)}; | ||
| 236 | } | ||
| 237 | |||
| 238 | MathUtil::Rectangle<u32> SurfaceParams::GetSubRect(const SurfaceParams& sub_surface) const { | ||
| 239 | const u32 begin_pixel_index = static_cast<u32>(PixelsInBytes(sub_surface.addr - addr)); | ||
| 240 | |||
| 241 | if (is_tiled) { | ||
| 242 | const int x0 = (begin_pixel_index % (stride * 8)) / 8; | ||
| 243 | const int y0 = (begin_pixel_index / (stride * 8)) * 8; | ||
| 244 | // Top to bottom | ||
| 245 | return MathUtil::Rectangle<u32>(x0, height - y0, x0 + sub_surface.width, | ||
| 246 | height - (y0 + sub_surface.height)); | ||
| 247 | } | ||
| 248 | |||
| 249 | const int x0 = begin_pixel_index % stride; | ||
| 250 | const int y0 = begin_pixel_index / stride; | ||
| 251 | // Bottom to top | ||
| 252 | return MathUtil::Rectangle<u32>(x0, y0 + sub_surface.height, x0 + sub_surface.width, y0); | ||
| 253 | } | ||
| 254 | |||
| 255 | MathUtil::Rectangle<u32> SurfaceParams::GetScaledSubRect(const SurfaceParams& sub_surface) const { | ||
| 256 | auto rect = GetSubRect(sub_surface); | ||
| 257 | rect.left = rect.left * res_scale; | ||
| 258 | rect.right = rect.right * res_scale; | ||
| 259 | rect.top = rect.top * res_scale; | ||
| 260 | rect.bottom = rect.bottom * res_scale; | ||
| 261 | return rect; | ||
| 262 | } | ||
| 263 | |||
| 264 | bool SurfaceParams::ExactMatch(const SurfaceParams& other_surface) const { | ||
| 265 | return std::tie(other_surface.addr, other_surface.width, other_surface.height, | ||
| 266 | other_surface.stride, other_surface.block_height, other_surface.pixel_format, | ||
| 267 | other_surface.component_type, | ||
| 268 | other_surface.is_tiled) == std::tie(addr, width, height, stride, block_height, | ||
| 269 | pixel_format, component_type, is_tiled) && | ||
| 270 | pixel_format != PixelFormat::Invalid; | ||
| 271 | } | ||
| 272 | |||
| 273 | bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const { | ||
| 274 | return sub_surface.addr >= addr && sub_surface.end <= end && | ||
| 275 | sub_surface.pixel_format == pixel_format && pixel_format != PixelFormat::Invalid && | ||
| 276 | sub_surface.is_tiled == is_tiled && sub_surface.block_height == block_height && | ||
| 277 | sub_surface.component_type == component_type && | ||
| 278 | (sub_surface.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 && | ||
| 279 | (sub_surface.stride == stride || sub_surface.height <= (is_tiled ? 8u : 1u)) && | ||
| 280 | GetSubRect(sub_surface).left + sub_surface.width <= stride; | ||
| 281 | } | ||
| 282 | |||
| 283 | bool SurfaceParams::CanExpand(const SurfaceParams& expanded_surface) const { | ||
| 284 | return pixel_format != PixelFormat::Invalid && pixel_format == expanded_surface.pixel_format && | ||
| 285 | addr <= expanded_surface.end && expanded_surface.addr <= end && | ||
| 286 | is_tiled == expanded_surface.is_tiled && block_height == expanded_surface.block_height && | ||
| 287 | component_type == expanded_surface.component_type && stride == expanded_surface.stride && | ||
| 288 | (std::max(expanded_surface.addr, addr) - std::min(expanded_surface.addr, addr)) % | ||
| 289 | BytesInPixels(stride * (is_tiled ? 8 : 1)) == | ||
| 290 | 0; | ||
| 291 | } | ||
| 292 | |||
| 293 | bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const { | ||
| 294 | if (pixel_format == PixelFormat::Invalid || addr > texcopy_params.addr || | ||
| 295 | end < texcopy_params.end) { | ||
| 296 | return false; | ||
| 297 | } | ||
| 298 | if (texcopy_params.block_height != block_height || | ||
| 299 | texcopy_params.component_type != component_type) | ||
| 300 | return false; | ||
| 301 | |||
| 302 | if (texcopy_params.width != texcopy_params.stride) { | ||
| 303 | const u32 tile_stride = static_cast<u32>(BytesInPixels(stride * (is_tiled ? 8 : 1))); | ||
| 304 | return (texcopy_params.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 && | ||
| 305 | texcopy_params.width % BytesInPixels(is_tiled ? 64 : 1) == 0 && | ||
| 306 | (texcopy_params.height == 1 || texcopy_params.stride == tile_stride) && | ||
| 307 | ((texcopy_params.addr - addr) % tile_stride) + texcopy_params.width <= tile_stride; | ||
| 308 | } | ||
| 309 | return FromInterval(texcopy_params.GetInterval()).GetInterval() == texcopy_params.GetInterval(); | ||
| 310 | } | ||
| 311 | |||
| 312 | VAddr SurfaceParams::GetCpuAddr() const { | ||
| 313 | // When this function is used, only cpu_addr or (GPU) addr should be set, not both | ||
| 314 | ASSERT(!(cpu_addr && addr)); | ||
| 315 | const auto& gpu = Core::System::GetInstance().GPU(); | ||
| 316 | return cpu_addr.get_value_or(*gpu.memory_manager->GpuToCpuAddress(addr)); | ||
| 317 | } | ||
| 318 | |||
| 319 | bool CachedSurface::CanFill(const SurfaceParams& dest_surface, | ||
| 320 | SurfaceInterval fill_interval) const { | ||
| 321 | if (type == SurfaceType::Fill && IsRegionValid(fill_interval) && | ||
| 322 | boost::icl::first(fill_interval) >= addr && | ||
| 323 | boost::icl::last_next(fill_interval) <= end && // dest_surface is within our fill range | ||
| 324 | dest_surface.FromInterval(fill_interval).GetInterval() == | ||
| 325 | fill_interval) { // make sure interval is a rectangle in dest surface | ||
| 326 | if (fill_size * CHAR_BIT != dest_surface.GetFormatBpp()) { | ||
| 327 | // Check if bits repeat for our fill_size | ||
| 328 | const u32 dest_bytes_per_pixel = std::max(dest_surface.GetFormatBpp() / CHAR_BIT, 1u); | ||
| 329 | std::vector<u8> fill_test(fill_size * dest_bytes_per_pixel); | ||
| 330 | |||
| 331 | for (u32 i = 0; i < dest_bytes_per_pixel; ++i) | ||
| 332 | std::memcpy(&fill_test[i * fill_size], &fill_data[0], fill_size); | ||
| 333 | |||
| 334 | for (u32 i = 0; i < fill_size; ++i) | ||
| 335 | if (std::memcmp(&fill_test[dest_bytes_per_pixel * i], &fill_test[0], | ||
| 336 | dest_bytes_per_pixel) != 0) | ||
| 337 | return false; | ||
| 338 | |||
| 339 | if (dest_surface.GetFormatBpp() == 4 && (fill_test[0] & 0xF) != (fill_test[0] >> 4)) | ||
| 340 | return false; | ||
| 341 | } | 281 | } |
| 342 | return true; | ||
| 343 | } | 282 | } |
| 344 | return false; | ||
| 345 | } | ||
| 346 | |||
| 347 | bool CachedSurface::CanCopy(const SurfaceParams& dest_surface, | ||
| 348 | SurfaceInterval copy_interval) const { | ||
| 349 | SurfaceParams subrect_params = dest_surface.FromInterval(copy_interval); | ||
| 350 | ASSERT(subrect_params.GetInterval() == copy_interval); | ||
| 351 | if (CanSubRect(subrect_params)) | ||
| 352 | return true; | ||
| 353 | |||
| 354 | if (CanFill(dest_surface, copy_interval)) | ||
| 355 | return true; | ||
| 356 | |||
| 357 | return false; | ||
| 358 | } | 283 | } |
| 359 | 284 | /** | |
| 360 | SurfaceInterval SurfaceParams::GetCopyableInterval(const Surface& src_surface) const { | 285 | * Helper function to perform software conversion (as needed) when loading a buffer from Switch |
| 361 | SurfaceInterval result{}; | 286 | * memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with |
| 362 | const auto valid_regions = | 287 | * typical desktop GPUs. |
| 363 | SurfaceRegions(GetInterval() & src_surface->GetInterval()) - src_surface->invalid_regions; | 288 | */ |
| 364 | for (auto& valid_interval : valid_regions) { | 289 | static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format, |
| 365 | const SurfaceInterval aligned_interval{ | 290 | u32 width, u32 height) { |
| 366 | addr + Common::AlignUp(boost::icl::first(valid_interval) - addr, | 291 | switch (pixel_format) { |
| 367 | BytesInPixels(is_tiled ? 8 * 8 : 1)), | 292 | case PixelFormat::ASTC_2D_4X4: { |
| 368 | addr + Common::AlignDown(boost::icl::last_next(valid_interval) - addr, | 293 | // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC. |
| 369 | BytesInPixels(is_tiled ? 8 * 8 : 1))}; | 294 | u32 block_width{}; |
| 370 | 295 | u32 block_height{}; | |
| 371 | if (BytesInPixels(is_tiled ? 8 * 8 : 1) > boost::icl::length(valid_interval) || | 296 | std::tie(block_width, block_height) = GetASTCBlockSize(pixel_format); |
| 372 | boost::icl::length(aligned_interval) == 0) { | 297 | data = Tegra::Texture::ASTC::Decompress(data, width, height, block_width, block_height); |
| 373 | continue; | 298 | break; |
| 374 | } | 299 | } |
| 375 | 300 | case PixelFormat::S8Z24: | |
| 376 | // Get the rectangle within aligned_interval | 301 | // Convert the S8Z24 depth format to Z24S8, as OpenGL does not support S8Z24. |
| 377 | const u32 stride_bytes = static_cast<u32>(BytesInPixels(stride)) * (is_tiled ? 8 : 1); | 302 | ConvertS8Z24ToZ24S8(data, width, height); |
| 378 | SurfaceInterval rect_interval{ | 303 | break; |
| 379 | addr + Common::AlignUp(boost::icl::first(aligned_interval) - addr, stride_bytes), | 304 | } |
| 380 | addr + Common::AlignDown(boost::icl::last_next(aligned_interval) - addr, stride_bytes), | 305 | } |
| 381 | }; | 306 | |
| 382 | if (boost::icl::first(rect_interval) > boost::icl::last_next(rect_interval)) { | 307 | /** |
| 383 | // 1 row | 308 | * Helper function to perform software conversion (as needed) when flushing a buffer to Switch |
| 384 | rect_interval = aligned_interval; | 309 | * memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with |
| 385 | } else if (boost::icl::length(rect_interval) == 0) { | 310 | * typical desktop GPUs. |
| 386 | // 2 rows that do not make a rectangle, return the larger one | 311 | */ |
| 387 | const SurfaceInterval row1{boost::icl::first(aligned_interval), | 312 | static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& /*data*/, PixelFormat pixel_format, |
| 388 | boost::icl::first(rect_interval)}; | 313 | u32 /*width*/, u32 /*height*/) { |
| 389 | const SurfaceInterval row2{boost::icl::first(rect_interval), | 314 | switch (pixel_format) { |
| 390 | boost::icl::last_next(aligned_interval)}; | 315 | case PixelFormat::ASTC_2D_4X4: |
| 391 | rect_interval = (boost::icl::length(row1) > boost::icl::length(row2)) ? row1 : row2; | 316 | case PixelFormat::S8Z24: |
| 392 | } | 317 | LOG_CRITICAL(Render_OpenGL, "Unimplemented pixel_format={}", |
| 393 | 318 | static_cast<u32>(pixel_format)); | |
| 394 | if (boost::icl::length(rect_interval) > boost::icl::length(result)) { | 319 | UNREACHABLE(); |
| 395 | result = rect_interval; | 320 | break; |
| 396 | } | ||
| 397 | } | 321 | } |
| 398 | return result; | ||
| 399 | } | ||
| 400 | |||
| 401 | void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surface& dst_surface, | ||
| 402 | SurfaceInterval copy_interval) { | ||
| 403 | SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval); | ||
| 404 | ASSERT(subrect_params.GetInterval() == copy_interval); | ||
| 405 | |||
| 406 | ASSERT(src_surface != dst_surface); | ||
| 407 | |||
| 408 | // This is only called when CanCopy is true, no need to run checks here | ||
| 409 | if (src_surface->type == SurfaceType::Fill) { | ||
| 410 | // FillSurface needs a 4 bytes buffer | ||
| 411 | const u64 fill_offset = | ||
| 412 | (boost::icl::first(copy_interval) - src_surface->addr) % src_surface->fill_size; | ||
| 413 | std::array<u8, 4> fill_buffer; | ||
| 414 | |||
| 415 | u64 fill_buff_pos = fill_offset; | ||
| 416 | for (int i : {0, 1, 2, 3}) | ||
| 417 | fill_buffer[i] = src_surface->fill_data[fill_buff_pos++ % src_surface->fill_size]; | ||
| 418 | |||
| 419 | FillSurface(dst_surface, &fill_buffer[0], dst_surface->GetScaledSubRect(subrect_params), | ||
| 420 | draw_framebuffer.handle); | ||
| 421 | return; | ||
| 422 | } | ||
| 423 | if (src_surface->CanSubRect(subrect_params)) { | ||
| 424 | BlitTextures(src_surface->texture.handle, src_surface->GetScaledSubRect(subrect_params), | ||
| 425 | dst_surface->texture.handle, dst_surface->GetScaledSubRect(subrect_params), | ||
| 426 | src_surface->type, read_framebuffer.handle, draw_framebuffer.handle); | ||
| 427 | return; | ||
| 428 | } | ||
| 429 | UNREACHABLE(); | ||
| 430 | } | 322 | } |
| 431 | 323 | ||
| 432 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); | 324 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); |
| 433 | void CachedSurface::LoadGLBuffer(Tegra::GPUVAddr load_start, Tegra::GPUVAddr load_end) { | 325 | void CachedSurface::LoadGLBuffer() { |
| 434 | ASSERT(type != SurfaceType::Fill); | 326 | ASSERT(params.type != SurfaceType::Fill); |
| 435 | 327 | ||
| 436 | u8* const texture_src_data = Memory::GetPointer(GetCpuAddr()); | 328 | u8* const texture_src_data = Memory::GetPointer(params.GetCpuAddr()); |
| 437 | if (texture_src_data == nullptr) | ||
| 438 | return; | ||
| 439 | 329 | ||
| 440 | if (gl_buffer == nullptr) { | 330 | ASSERT(texture_src_data); |
| 441 | gl_buffer_size = GetActualWidth() * GetActualHeight() * GetGLBytesPerPixel(pixel_format); | ||
| 442 | gl_buffer.reset(new u8[gl_buffer_size]); | ||
| 443 | } | ||
| 444 | 331 | ||
| 445 | MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); | 332 | gl_buffer.resize(params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); |
| 446 | 333 | ||
| 447 | ASSERT(load_start >= addr && load_end <= end); | 334 | MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); |
| 448 | const u64 start_offset = load_start - addr; | ||
| 449 | 335 | ||
| 450 | if (!is_tiled) { | 336 | if (!params.is_tiled) { |
| 451 | const u32 bytes_per_pixel{GetFormatBpp() >> 3}; | 337 | const u32 bytes_per_pixel{params.GetFormatBpp() >> 3}; |
| 452 | 338 | ||
| 453 | std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset, | 339 | std::memcpy(gl_buffer.data(), texture_src_data, |
| 454 | bytes_per_pixel * width * height); | 340 | bytes_per_pixel * params.width * params.height); |
| 455 | } else { | 341 | } else { |
| 456 | morton_to_gl_fns[static_cast<size_t>(pixel_format)](GetActualWidth(), block_height, | 342 | morton_to_gl_fns[static_cast<size_t>(params.pixel_format)]( |
| 457 | GetActualHeight(), &gl_buffer[0], addr, | 343 | params.width, params.block_height, params.height, gl_buffer.data(), params.addr); |
| 458 | load_start, load_end); | ||
| 459 | } | 344 | } |
| 345 | |||
| 346 | ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height); | ||
| 460 | } | 347 | } |
| 461 | 348 | ||
| 462 | MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); | 349 | MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); |
| 463 | void CachedSurface::FlushGLBuffer(Tegra::GPUVAddr flush_start, Tegra::GPUVAddr flush_end) { | 350 | void CachedSurface::FlushGLBuffer() { |
| 464 | u8* const dst_buffer = Memory::GetPointer(GetCpuAddr()); | 351 | u8* const dst_buffer = Memory::GetPointer(params.GetCpuAddr()); |
| 465 | if (dst_buffer == nullptr) | ||
| 466 | return; | ||
| 467 | |||
| 468 | ASSERT(gl_buffer_size == width * height * GetGLBytesPerPixel(pixel_format)); | ||
| 469 | 352 | ||
| 470 | // TODO: Should probably be done in ::Memory:: and check for other regions too | 353 | ASSERT(dst_buffer); |
| 471 | // same as loadglbuffer() | 354 | ASSERT(gl_buffer.size() == |
| 472 | if (flush_start < Memory::VRAM_VADDR_END && flush_end > Memory::VRAM_VADDR_END) | 355 | params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); |
| 473 | flush_end = Memory::VRAM_VADDR_END; | ||
| 474 | |||
| 475 | if (flush_start < Memory::VRAM_VADDR && flush_end > Memory::VRAM_VADDR) | ||
| 476 | flush_start = Memory::VRAM_VADDR; | ||
| 477 | 356 | ||
| 478 | MICROPROFILE_SCOPE(OpenGL_SurfaceFlush); | 357 | MICROPROFILE_SCOPE(OpenGL_SurfaceFlush); |
| 479 | 358 | ||
| 480 | ASSERT(flush_start >= addr && flush_end <= end); | 359 | ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, |
| 481 | const u64 start_offset = flush_start - addr; | 360 | params.height); |
| 482 | const u64 end_offset = flush_end - addr; | ||
| 483 | |||
| 484 | if (type == SurfaceType::Fill) { | ||
| 485 | const u64 coarse_start_offset = start_offset - (start_offset % fill_size); | ||
| 486 | const u64 backup_bytes = start_offset % fill_size; | ||
| 487 | std::array<u8, 4> backup_data; | ||
| 488 | if (backup_bytes) | ||
| 489 | std::memcpy(&backup_data[0], &dst_buffer[coarse_start_offset], backup_bytes); | ||
| 490 | |||
| 491 | for (u64 offset = coarse_start_offset; offset < end_offset; offset += fill_size) { | ||
| 492 | std::memcpy(&dst_buffer[offset], &fill_data[0], | ||
| 493 | std::min(fill_size, end_offset - offset)); | ||
| 494 | } | ||
| 495 | 361 | ||
| 496 | if (backup_bytes) | 362 | if (!params.is_tiled) { |
| 497 | std::memcpy(&dst_buffer[coarse_start_offset], &backup_data[0], backup_bytes); | 363 | std::memcpy(dst_buffer, gl_buffer.data(), params.size_in_bytes); |
| 498 | } else if (!is_tiled) { | ||
| 499 | std::memcpy(dst_buffer + start_offset, &gl_buffer[start_offset], flush_end - flush_start); | ||
| 500 | } else { | 364 | } else { |
| 501 | gl_to_morton_fns[static_cast<size_t>(pixel_format)]( | 365 | gl_to_morton_fns[static_cast<size_t>(params.pixel_format)]( |
| 502 | stride, block_height, height, &gl_buffer[0], addr, flush_start, flush_end); | 366 | params.width, params.block_height, params.height, gl_buffer.data(), params.addr); |
| 503 | } | 367 | } |
| 504 | } | 368 | } |
| 505 | 369 | ||
| 506 | MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); | 370 | MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); |
| 507 | void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle, | 371 | void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { |
| 508 | GLuint draw_fb_handle) { | 372 | if (params.type == SurfaceType::Fill) |
| 509 | if (type == SurfaceType::Fill) | ||
| 510 | return; | 373 | return; |
| 511 | 374 | ||
| 512 | MICROPROFILE_SCOPE(OpenGL_TextureUL); | 375 | MICROPROFILE_SCOPE(OpenGL_TextureUL); |
| 513 | 376 | ||
| 514 | ASSERT(gl_buffer_size == | 377 | ASSERT(gl_buffer.size() == |
| 515 | GetActualWidth() * GetActualHeight() * GetGLBytesPerPixel(pixel_format)); | 378 | params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); |
| 379 | |||
| 380 | const auto& rect{params.GetRect()}; | ||
| 516 | 381 | ||
| 517 | // Load data from memory to the surface | 382 | // Load data from memory to the surface |
| 518 | GLint x0 = static_cast<GLint>(rect.left); | 383 | GLint x0 = static_cast<GLint>(rect.left); |
| 519 | GLint y0 = static_cast<GLint>(rect.bottom); | 384 | GLint y0 = static_cast<GLint>(rect.bottom); |
| 520 | size_t buffer_offset = (y0 * stride + x0) * GetGLBytesPerPixel(pixel_format); | 385 | size_t buffer_offset = (y0 * params.width + x0) * GetGLBytesPerPixel(params.pixel_format); |
| 521 | 386 | ||
| 522 | const FormatTuple& tuple = GetFormatTuple(pixel_format, component_type); | 387 | const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); |
| 523 | GLuint target_tex = texture.handle; | 388 | GLuint target_tex = texture.handle; |
| 524 | |||
| 525 | // If not 1x scale, create 1x texture that we will blit from to replace texture subrect in | ||
| 526 | // surface | ||
| 527 | OGLTexture unscaled_tex; | ||
| 528 | if (res_scale != 1) { | ||
| 529 | x0 = 0; | ||
| 530 | y0 = 0; | ||
| 531 | |||
| 532 | unscaled_tex.Create(); | ||
| 533 | AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth(), rect.GetHeight()); | ||
| 534 | target_tex = unscaled_tex.handle; | ||
| 535 | } | ||
| 536 | |||
| 537 | OpenGLState cur_state = OpenGLState::GetCurState(); | 389 | OpenGLState cur_state = OpenGLState::GetCurState(); |
| 538 | 390 | ||
| 539 | GLuint old_tex = cur_state.texture_units[0].texture_2d; | 391 | GLuint old_tex = cur_state.texture_units[0].texture_2d; |
| @@ -541,15 +393,15 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint | |||
| 541 | cur_state.Apply(); | 393 | cur_state.Apply(); |
| 542 | 394 | ||
| 543 | // Ensure no bad interactions with GL_UNPACK_ALIGNMENT | 395 | // Ensure no bad interactions with GL_UNPACK_ALIGNMENT |
| 544 | ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0); | 396 | ASSERT(params.width * GetGLBytesPerPixel(params.pixel_format) % 4 == 0); |
| 545 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(stride)); | 397 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.width)); |
| 546 | 398 | ||
| 547 | glActiveTexture(GL_TEXTURE0); | 399 | glActiveTexture(GL_TEXTURE0); |
| 548 | if (tuple.compressed) { | 400 | if (tuple.compressed) { |
| 549 | glCompressedTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, | 401 | glCompressedTexImage2D( |
| 550 | static_cast<GLsizei>(rect.GetWidth() * GetCompresssionFactor()), | 402 | GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), |
| 551 | static_cast<GLsizei>(rect.GetHeight() * GetCompresssionFactor()), 0, | 403 | static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes), |
| 552 | size, &gl_buffer[buffer_offset]); | 404 | &gl_buffer[buffer_offset]); |
| 553 | } else { | 405 | } else { |
| 554 | glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), | 406 | glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), |
| 555 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, | 407 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, |
| @@ -560,845 +412,250 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint | |||
| 560 | 412 | ||
| 561 | cur_state.texture_units[0].texture_2d = old_tex; | 413 | cur_state.texture_units[0].texture_2d = old_tex; |
| 562 | cur_state.Apply(); | 414 | cur_state.Apply(); |
| 563 | |||
| 564 | if (res_scale != 1) { | ||
| 565 | auto scaled_rect = rect; | ||
| 566 | scaled_rect.left *= res_scale; | ||
| 567 | scaled_rect.top *= res_scale; | ||
| 568 | scaled_rect.right *= res_scale; | ||
| 569 | scaled_rect.bottom *= res_scale; | ||
| 570 | |||
| 571 | BlitTextures(unscaled_tex.handle, {0, rect.GetHeight(), rect.GetWidth(), 0}, texture.handle, | ||
| 572 | scaled_rect, type, read_fb_handle, draw_fb_handle); | ||
| 573 | } | ||
| 574 | } | 415 | } |
| 575 | 416 | ||
| 576 | MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64)); | 417 | MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64)); |
| 577 | void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle, | 418 | void CachedSurface::DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { |
| 578 | GLuint draw_fb_handle) { | 419 | if (params.type == SurfaceType::Fill) |
| 579 | if (type == SurfaceType::Fill) | ||
| 580 | return; | 420 | return; |
| 581 | 421 | ||
| 582 | MICROPROFILE_SCOPE(OpenGL_TextureDL); | 422 | MICROPROFILE_SCOPE(OpenGL_TextureDL); |
| 583 | 423 | ||
| 584 | if (gl_buffer == nullptr) { | 424 | gl_buffer.resize(params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); |
| 585 | gl_buffer_size = width * height * GetGLBytesPerPixel(pixel_format); | ||
| 586 | gl_buffer.reset(new u8[gl_buffer_size]); | ||
| 587 | } | ||
| 588 | 425 | ||
| 589 | OpenGLState state = OpenGLState::GetCurState(); | 426 | OpenGLState state = OpenGLState::GetCurState(); |
| 590 | OpenGLState prev_state = state; | 427 | OpenGLState prev_state = state; |
| 591 | SCOPE_EXIT({ prev_state.Apply(); }); | 428 | SCOPE_EXIT({ prev_state.Apply(); }); |
| 592 | 429 | ||
| 593 | const FormatTuple& tuple = GetFormatTuple(pixel_format, component_type); | 430 | const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); |
| 594 | 431 | ||
| 595 | // Ensure no bad interactions with GL_PACK_ALIGNMENT | 432 | // Ensure no bad interactions with GL_PACK_ALIGNMENT |
| 596 | ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0); | 433 | ASSERT(params.width * GetGLBytesPerPixel(params.pixel_format) % 4 == 0); |
| 597 | glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(stride)); | 434 | glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width)); |
| 598 | size_t buffer_offset = (rect.bottom * stride + rect.left) * GetGLBytesPerPixel(pixel_format); | ||
| 599 | |||
| 600 | // If not 1x scale, blit scaled texture to a new 1x texture and use that to flush | ||
| 601 | if (res_scale != 1) { | ||
| 602 | auto scaled_rect = rect; | ||
| 603 | scaled_rect.left *= res_scale; | ||
| 604 | scaled_rect.top *= res_scale; | ||
| 605 | scaled_rect.right *= res_scale; | ||
| 606 | scaled_rect.bottom *= res_scale; | ||
| 607 | |||
| 608 | OGLTexture unscaled_tex; | ||
| 609 | unscaled_tex.Create(); | ||
| 610 | |||
| 611 | MathUtil::Rectangle<u32> unscaled_tex_rect{0, rect.GetHeight(), rect.GetWidth(), 0}; | ||
| 612 | AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth(), rect.GetHeight()); | ||
| 613 | BlitTextures(texture.handle, scaled_rect, unscaled_tex.handle, unscaled_tex_rect, type, | ||
| 614 | read_fb_handle, draw_fb_handle); | ||
| 615 | |||
| 616 | state.texture_units[0].texture_2d = unscaled_tex.handle; | ||
| 617 | state.Apply(); | ||
| 618 | |||
| 619 | glActiveTexture(GL_TEXTURE0); | ||
| 620 | glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, &gl_buffer[buffer_offset]); | ||
| 621 | } else { | ||
| 622 | state.ResetTexture(texture.handle); | ||
| 623 | state.draw.read_framebuffer = read_fb_handle; | ||
| 624 | state.Apply(); | ||
| 625 | |||
| 626 | if (type == SurfaceType::ColorTexture) { | ||
| 627 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | ||
| 628 | texture.handle, 0); | ||
| 629 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||
| 630 | 0, 0); | ||
| 631 | } else if (type == SurfaceType::Depth) { | ||
| 632 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | ||
| 633 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | ||
| 634 | texture.handle, 0); | ||
| 635 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | ||
| 636 | } else { | ||
| 637 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | ||
| 638 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||
| 639 | texture.handle, 0); | ||
| 640 | } | ||
| 641 | glReadPixels(static_cast<GLint>(rect.left), static_cast<GLint>(rect.bottom), | ||
| 642 | static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()), | ||
| 643 | tuple.format, tuple.type, &gl_buffer[buffer_offset]); | ||
| 644 | } | ||
| 645 | 435 | ||
| 646 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); | 436 | const auto& rect{params.GetRect()}; |
| 647 | } | 437 | size_t buffer_offset = |
| 648 | 438 | (rect.bottom * params.width + rect.left) * GetGLBytesPerPixel(params.pixel_format); | |
| 649 | enum class MatchFlags { | ||
| 650 | None = 0, | ||
| 651 | Invalid = 1, // Flag that can be applied to other match types, invalid matches require | ||
| 652 | // validation before they can be used | ||
| 653 | Exact = 1 << 1, // Surfaces perfectly match | ||
| 654 | SubRect = 1 << 2, // Surface encompasses params | ||
| 655 | Copy = 1 << 3, // Surface we can copy from | ||
| 656 | Expand = 1 << 4, // Surface that can expand params | ||
| 657 | TexCopy = 1 << 5 // Surface that will match a display transfer "texture copy" parameters | ||
| 658 | }; | ||
| 659 | |||
| 660 | constexpr MatchFlags operator|(MatchFlags lhs, MatchFlags rhs) { | ||
| 661 | return static_cast<MatchFlags>(static_cast<int>(lhs) | static_cast<int>(rhs)); | ||
| 662 | } | ||
| 663 | 439 | ||
| 664 | constexpr MatchFlags operator&(MatchFlags lhs, MatchFlags rhs) { | 440 | state.UnbindTexture(texture.handle); |
| 665 | return static_cast<MatchFlags>(static_cast<int>(lhs) & static_cast<int>(rhs)); | 441 | state.draw.read_framebuffer = read_fb_handle; |
| 666 | } | 442 | state.Apply(); |
| 667 | 443 | ||
| 668 | /// Get the best surface match (and its match type) for the given flags | 444 | if (params.type == SurfaceType::ColorTexture) { |
| 669 | template <MatchFlags find_flags> | 445 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| 670 | Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params, | 446 | texture.handle, 0); |
| 671 | ScaleMatch match_scale_type, | 447 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, |
| 672 | boost::optional<SurfaceInterval> validate_interval = boost::none) { | 448 | 0); |
| 673 | Surface match_surface = nullptr; | 449 | } else if (params.type == SurfaceType::Depth) { |
| 674 | bool match_valid = false; | 450 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); |
| 675 | u32 match_scale = 0; | 451 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, |
| 676 | SurfaceInterval match_interval{}; | 452 | texture.handle, 0); |
| 677 | 453 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | |
| 678 | for (auto& pair : RangeFromInterval(surface_cache, params.GetInterval())) { | 454 | } else { |
| 679 | for (auto& surface : pair.second) { | 455 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); |
| 680 | bool res_scale_matched = match_scale_type == ScaleMatch::Exact | 456 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 681 | ? (params.res_scale == surface->res_scale) | 457 | texture.handle, 0); |
| 682 | : (params.res_scale <= surface->res_scale); | ||
| 683 | // validity will be checked in GetCopyableInterval | ||
| 684 | bool is_valid = | ||
| 685 | (find_flags & MatchFlags::Copy) != MatchFlags::None | ||
| 686 | ? true | ||
| 687 | : surface->IsRegionValid(validate_interval.value_or(params.GetInterval())); | ||
| 688 | |||
| 689 | if ((find_flags & MatchFlags::Invalid) == MatchFlags::None && !is_valid) | ||
| 690 | continue; | ||
| 691 | |||
| 692 | auto IsMatch_Helper = [&](auto check_type, auto match_fn) { | ||
| 693 | if ((find_flags & check_type) == MatchFlags::None) | ||
| 694 | return; | ||
| 695 | |||
| 696 | bool matched; | ||
| 697 | SurfaceInterval surface_interval; | ||
| 698 | std::tie(matched, surface_interval) = match_fn(); | ||
| 699 | if (!matched) | ||
| 700 | return; | ||
| 701 | |||
| 702 | if (!res_scale_matched && match_scale_type != ScaleMatch::Ignore && | ||
| 703 | surface->type != SurfaceType::Fill) | ||
| 704 | return; | ||
| 705 | |||
| 706 | // Found a match, update only if this is better than the previous one | ||
| 707 | auto UpdateMatch = [&] { | ||
| 708 | match_surface = surface; | ||
| 709 | match_valid = is_valid; | ||
| 710 | match_scale = surface->res_scale; | ||
| 711 | match_interval = surface_interval; | ||
| 712 | }; | ||
| 713 | |||
| 714 | if (surface->res_scale > match_scale) { | ||
| 715 | UpdateMatch(); | ||
| 716 | return; | ||
| 717 | } else if (surface->res_scale < match_scale) { | ||
| 718 | return; | ||
| 719 | } | ||
| 720 | |||
| 721 | if (is_valid && !match_valid) { | ||
| 722 | UpdateMatch(); | ||
| 723 | return; | ||
| 724 | } else if (is_valid != match_valid) { | ||
| 725 | return; | ||
| 726 | } | ||
| 727 | |||
| 728 | if (boost::icl::length(surface_interval) > boost::icl::length(match_interval)) { | ||
| 729 | UpdateMatch(); | ||
| 730 | } | ||
| 731 | }; | ||
| 732 | IsMatch_Helper(std::integral_constant<MatchFlags, MatchFlags::Exact>{}, [&] { | ||
| 733 | return std::make_pair(surface->ExactMatch(params), surface->GetInterval()); | ||
| 734 | }); | ||
| 735 | IsMatch_Helper(std::integral_constant<MatchFlags, MatchFlags::SubRect>{}, [&] { | ||
| 736 | return std::make_pair(surface->CanSubRect(params), surface->GetInterval()); | ||
| 737 | }); | ||
| 738 | IsMatch_Helper(std::integral_constant<MatchFlags, MatchFlags::Copy>{}, [&] { | ||
| 739 | auto copy_interval = | ||
| 740 | params.FromInterval(*validate_interval).GetCopyableInterval(surface); | ||
| 741 | bool matched = boost::icl::length(copy_interval & *validate_interval) != 0 && | ||
| 742 | surface->CanCopy(params, copy_interval); | ||
| 743 | return std::make_pair(matched, copy_interval); | ||
| 744 | }); | ||
| 745 | IsMatch_Helper(std::integral_constant<MatchFlags, MatchFlags::Expand>{}, [&] { | ||
| 746 | return std::make_pair(surface->CanExpand(params), surface->GetInterval()); | ||
| 747 | }); | ||
| 748 | IsMatch_Helper(std::integral_constant<MatchFlags, MatchFlags::TexCopy>{}, [&] { | ||
| 749 | return std::make_pair(surface->CanTexCopy(params), surface->GetInterval()); | ||
| 750 | }); | ||
| 751 | } | ||
| 752 | } | 458 | } |
| 753 | return match_surface; | 459 | glReadPixels(static_cast<GLint>(rect.left), static_cast<GLint>(rect.bottom), |
| 460 | static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()), | ||
| 461 | tuple.format, tuple.type, &gl_buffer[buffer_offset]); | ||
| 462 | |||
| 463 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); | ||
| 754 | } | 464 | } |
| 755 | 465 | ||
| 756 | RasterizerCacheOpenGL::RasterizerCacheOpenGL() { | 466 | RasterizerCacheOpenGL::RasterizerCacheOpenGL() { |
| 757 | read_framebuffer.Create(); | 467 | read_framebuffer.Create(); |
| 758 | draw_framebuffer.Create(); | 468 | draw_framebuffer.Create(); |
| 759 | |||
| 760 | attributeless_vao.Create(); | ||
| 761 | |||
| 762 | d24s8_abgr_buffer.Create(); | ||
| 763 | d24s8_abgr_buffer_size = 0; | ||
| 764 | |||
| 765 | const char* vs_source = R"( | ||
| 766 | #version 330 core | ||
| 767 | const vec2 vertices[4] = vec2[4](vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0)); | ||
| 768 | void main() { | ||
| 769 | gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0); | ||
| 770 | } | ||
| 771 | )"; | ||
| 772 | const char* fs_source = R"( | ||
| 773 | #version 330 core | ||
| 774 | |||
| 775 | uniform samplerBuffer tbo; | ||
| 776 | uniform vec2 tbo_size; | ||
| 777 | uniform vec4 viewport; | ||
| 778 | |||
| 779 | out vec4 color; | ||
| 780 | |||
| 781 | void main() { | ||
| 782 | vec2 tbo_coord = (gl_FragCoord.xy - viewport.xy) * tbo_size / viewport.zw; | ||
| 783 | int tbo_offset = int(tbo_coord.y) * int(tbo_size.x) + int(tbo_coord.x); | ||
| 784 | color = texelFetch(tbo, tbo_offset).rabg; | ||
| 785 | } | ||
| 786 | )"; | ||
| 787 | d24s8_abgr_shader.CreateFromSource(vs_source, nullptr, fs_source); | ||
| 788 | |||
| 789 | OpenGLState state = OpenGLState::GetCurState(); | ||
| 790 | GLuint old_program = state.draw.shader_program; | ||
| 791 | state.draw.shader_program = d24s8_abgr_shader.handle; | ||
| 792 | state.Apply(); | ||
| 793 | |||
| 794 | GLint tbo_u_id = glGetUniformLocation(d24s8_abgr_shader.handle, "tbo"); | ||
| 795 | ASSERT(tbo_u_id != -1); | ||
| 796 | glUniform1i(tbo_u_id, 0); | ||
| 797 | |||
| 798 | state.draw.shader_program = old_program; | ||
| 799 | state.Apply(); | ||
| 800 | |||
| 801 | d24s8_abgr_tbo_size_u_id = glGetUniformLocation(d24s8_abgr_shader.handle, "tbo_size"); | ||
| 802 | ASSERT(d24s8_abgr_tbo_size_u_id != -1); | ||
| 803 | d24s8_abgr_viewport_u_id = glGetUniformLocation(d24s8_abgr_shader.handle, "viewport"); | ||
| 804 | ASSERT(d24s8_abgr_viewport_u_id != -1); | ||
| 805 | } | 469 | } |
| 806 | 470 | ||
| 807 | RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { | 471 | RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { |
| 808 | FlushAll(); | 472 | while (!surface_cache.empty()) { |
| 809 | while (!surface_cache.empty()) | 473 | UnregisterSurface(surface_cache.begin()->second); |
| 810 | UnregisterSurface(*surface_cache.begin()->second.begin()); | ||
| 811 | } | ||
| 812 | |||
| 813 | bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface, | ||
| 814 | const MathUtil::Rectangle<u32>& src_rect, | ||
| 815 | const Surface& dst_surface, | ||
| 816 | const MathUtil::Rectangle<u32>& dst_rect) { | ||
| 817 | if (!SurfaceParams::CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) | ||
| 818 | return false; | ||
| 819 | |||
| 820 | return BlitTextures(src_surface->texture.handle, src_rect, dst_surface->texture.handle, | ||
| 821 | dst_rect, src_surface->type, read_framebuffer.handle, | ||
| 822 | draw_framebuffer.handle); | ||
| 823 | } | ||
| 824 | |||
| 825 | void RasterizerCacheOpenGL::ConvertD24S8toABGR(GLuint src_tex, | ||
| 826 | const MathUtil::Rectangle<u32>& src_rect, | ||
| 827 | GLuint dst_tex, | ||
| 828 | const MathUtil::Rectangle<u32>& dst_rect) { | ||
| 829 | OpenGLState prev_state = OpenGLState::GetCurState(); | ||
| 830 | SCOPE_EXIT({ prev_state.Apply(); }); | ||
| 831 | |||
| 832 | OpenGLState state; | ||
| 833 | state.draw.read_framebuffer = read_framebuffer.handle; | ||
| 834 | state.draw.draw_framebuffer = draw_framebuffer.handle; | ||
| 835 | state.Apply(); | ||
| 836 | |||
| 837 | glBindBuffer(GL_PIXEL_PACK_BUFFER, d24s8_abgr_buffer.handle); | ||
| 838 | |||
| 839 | GLsizeiptr target_pbo_size = src_rect.GetWidth() * src_rect.GetHeight() * 4; | ||
| 840 | if (target_pbo_size > d24s8_abgr_buffer_size) { | ||
| 841 | d24s8_abgr_buffer_size = target_pbo_size * 2; | ||
| 842 | glBufferData(GL_PIXEL_PACK_BUFFER, d24s8_abgr_buffer_size, nullptr, GL_STREAM_COPY); | ||
| 843 | } | ||
| 844 | |||
| 845 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | ||
| 846 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, src_tex, | ||
| 847 | 0); | ||
| 848 | glReadPixels(static_cast<GLint>(src_rect.left), static_cast<GLint>(src_rect.bottom), | ||
| 849 | static_cast<GLsizei>(src_rect.GetWidth()), | ||
| 850 | static_cast<GLsizei>(src_rect.GetHeight()), GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, | ||
| 851 | 0); | ||
| 852 | |||
| 853 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); | ||
| 854 | |||
| 855 | // PBO now contains src_tex in RABG format | ||
| 856 | state.draw.shader_program = d24s8_abgr_shader.handle; | ||
| 857 | state.draw.vertex_array = attributeless_vao.handle; | ||
| 858 | state.viewport.x = static_cast<GLint>(dst_rect.left); | ||
| 859 | state.viewport.y = static_cast<GLint>(dst_rect.bottom); | ||
| 860 | state.viewport.width = static_cast<GLsizei>(dst_rect.GetWidth()); | ||
| 861 | state.viewport.height = static_cast<GLsizei>(dst_rect.GetHeight()); | ||
| 862 | state.Apply(); | ||
| 863 | |||
| 864 | OGLTexture tbo; | ||
| 865 | tbo.Create(); | ||
| 866 | glActiveTexture(GL_TEXTURE0); | ||
| 867 | glBindTexture(GL_TEXTURE_BUFFER, tbo.handle); | ||
| 868 | glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA8, d24s8_abgr_buffer.handle); | ||
| 869 | |||
| 870 | glUniform2f(d24s8_abgr_tbo_size_u_id, static_cast<GLfloat>(src_rect.GetWidth()), | ||
| 871 | static_cast<GLfloat>(src_rect.GetHeight())); | ||
| 872 | glUniform4f(d24s8_abgr_viewport_u_id, static_cast<GLfloat>(state.viewport.x), | ||
| 873 | static_cast<GLfloat>(state.viewport.y), static_cast<GLfloat>(state.viewport.width), | ||
| 874 | static_cast<GLfloat>(state.viewport.height)); | ||
| 875 | |||
| 876 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, 0); | ||
| 877 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | ||
| 878 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
| 879 | |||
| 880 | glBindTexture(GL_TEXTURE_BUFFER, 0); | ||
| 881 | } | ||
| 882 | |||
| 883 | Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale, | ||
| 884 | bool load_if_create) { | ||
| 885 | if (params.addr == 0 || params.height * params.width == 0) { | ||
| 886 | return nullptr; | ||
| 887 | } | ||
| 888 | // Use GetSurfaceSubRect instead | ||
| 889 | ASSERT(params.width == params.stride); | ||
| 890 | |||
| 891 | ASSERT(!params.is_tiled || | ||
| 892 | (params.GetActualWidth() % 8 == 0 && params.GetActualHeight() % 8 == 0)); | ||
| 893 | |||
| 894 | // Check for an exact match in existing surfaces | ||
| 895 | Surface surface = | ||
| 896 | FindMatch<MatchFlags::Exact | MatchFlags::Invalid>(surface_cache, params, match_res_scale); | ||
| 897 | |||
| 898 | if (surface == nullptr) { | ||
| 899 | u16 target_res_scale = params.res_scale; | ||
| 900 | if (match_res_scale != ScaleMatch::Exact) { | ||
| 901 | // This surface may have a subrect of another surface with a higher res_scale, find it | ||
| 902 | // to adjust our params | ||
| 903 | SurfaceParams find_params = params; | ||
| 904 | Surface expandable = FindMatch<MatchFlags::Expand | MatchFlags::Invalid>( | ||
| 905 | surface_cache, find_params, match_res_scale); | ||
| 906 | if (expandable != nullptr && expandable->res_scale > target_res_scale) { | ||
| 907 | target_res_scale = expandable->res_scale; | ||
| 908 | } | ||
| 909 | } | ||
| 910 | SurfaceParams new_params = params; | ||
| 911 | new_params.res_scale = target_res_scale; | ||
| 912 | surface = CreateSurface(new_params); | ||
| 913 | RegisterSurface(surface); | ||
| 914 | } | ||
| 915 | |||
| 916 | if (load_if_create) { | ||
| 917 | ValidateSurface(surface, params.addr, params.size); | ||
| 918 | } | ||
| 919 | |||
| 920 | return surface; | ||
| 921 | } | ||
| 922 | |||
| 923 | boost::optional<Tegra::GPUVAddr> RasterizerCacheOpenGL::TryFindFramebufferGpuAddress( | ||
| 924 | VAddr cpu_addr) const { | ||
| 925 | // Tries to find the GPU address of a framebuffer based on the CPU address. This is because | ||
| 926 | // final output framebuffers are specified by CPU address, but internally our GPU cache uses GPU | ||
| 927 | // addresses. We iterate through all cached framebuffers, and compare their starting CPU address | ||
| 928 | // to the one provided. This is obviously not great, and won't work if the framebuffer overlaps | ||
| 929 | // surfaces. | ||
| 930 | |||
| 931 | std::vector<Tegra::GPUVAddr> gpu_addresses; | ||
| 932 | for (const auto& pair : surface_cache) { | ||
| 933 | for (const auto& surface : pair.second) { | ||
| 934 | const VAddr surface_cpu_addr = surface->GetCpuAddr(); | ||
| 935 | if (cpu_addr >= surface_cpu_addr && cpu_addr < (surface_cpu_addr + surface->size)) { | ||
| 936 | ASSERT_MSG(cpu_addr == surface_cpu_addr, "overlapping surfaces are unsupported"); | ||
| 937 | gpu_addresses.push_back(surface->addr); | ||
| 938 | } | ||
| 939 | } | ||
| 940 | } | 474 | } |
| 941 | |||
| 942 | if (gpu_addresses.empty()) { | ||
| 943 | return {}; | ||
| 944 | } | ||
| 945 | |||
| 946 | ASSERT_MSG(gpu_addresses.size() == 1, ">1 surface is unsupported"); | ||
| 947 | return gpu_addresses[0]; | ||
| 948 | } | ||
| 949 | |||
| 950 | SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams& params, | ||
| 951 | ScaleMatch match_res_scale, | ||
| 952 | bool load_if_create) { | ||
| 953 | if (params.addr == 0 || params.height * params.width == 0) { | ||
| 954 | return std::make_tuple(nullptr, MathUtil::Rectangle<u32>{}); | ||
| 955 | } | ||
| 956 | |||
| 957 | // Attempt to find encompassing surface | ||
| 958 | Surface surface = FindMatch<MatchFlags::SubRect | MatchFlags::Invalid>(surface_cache, params, | ||
| 959 | match_res_scale); | ||
| 960 | |||
| 961 | // Check if FindMatch failed because of res scaling | ||
| 962 | // If that's the case create a new surface with | ||
| 963 | // the dimensions of the lower res_scale surface | ||
| 964 | // to suggest it should not be used again | ||
| 965 | if (surface == nullptr && match_res_scale != ScaleMatch::Ignore) { | ||
| 966 | surface = FindMatch<MatchFlags::SubRect | MatchFlags::Invalid>(surface_cache, params, | ||
| 967 | ScaleMatch::Ignore); | ||
| 968 | if (surface != nullptr) { | ||
| 969 | ASSERT(surface->res_scale < params.res_scale); | ||
| 970 | SurfaceParams new_params = *surface; | ||
| 971 | new_params.res_scale = params.res_scale; | ||
| 972 | |||
| 973 | surface = CreateSurface(new_params); | ||
| 974 | RegisterSurface(surface); | ||
| 975 | } | ||
| 976 | } | ||
| 977 | |||
| 978 | SurfaceParams aligned_params = params; | ||
| 979 | if (params.is_tiled) { | ||
| 980 | aligned_params.height = Common::AlignUp(params.height, 8); | ||
| 981 | aligned_params.width = Common::AlignUp(params.width, 8); | ||
| 982 | aligned_params.stride = Common::AlignUp(params.stride, 8); | ||
| 983 | aligned_params.UpdateParams(); | ||
| 984 | } | ||
| 985 | |||
| 986 | // Check for a surface we can expand before creating a new one | ||
| 987 | if (surface == nullptr) { | ||
| 988 | surface = FindMatch<MatchFlags::Expand | MatchFlags::Invalid>(surface_cache, aligned_params, | ||
| 989 | match_res_scale); | ||
| 990 | if (surface != nullptr) { | ||
| 991 | aligned_params.width = aligned_params.stride; | ||
| 992 | aligned_params.UpdateParams(); | ||
| 993 | |||
| 994 | SurfaceParams new_params = *surface; | ||
| 995 | new_params.addr = std::min(aligned_params.addr, surface->addr); | ||
| 996 | new_params.end = std::max(aligned_params.end, surface->end); | ||
| 997 | new_params.size = new_params.end - new_params.addr; | ||
| 998 | new_params.height = static_cast<u32>( | ||
| 999 | new_params.size / aligned_params.BytesInPixels(aligned_params.stride)); | ||
| 1000 | ASSERT(new_params.size % aligned_params.BytesInPixels(aligned_params.stride) == 0); | ||
| 1001 | |||
| 1002 | Surface new_surface = CreateSurface(new_params); | ||
| 1003 | DuplicateSurface(surface, new_surface); | ||
| 1004 | |||
| 1005 | // Delete the expanded surface, this can't be done safely yet | ||
| 1006 | // because it may still be in use | ||
| 1007 | remove_surfaces.emplace(surface); | ||
| 1008 | |||
| 1009 | surface = new_surface; | ||
| 1010 | RegisterSurface(new_surface); | ||
| 1011 | } | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | // No subrect found - create and return a new surface | ||
| 1015 | if (surface == nullptr) { | ||
| 1016 | SurfaceParams new_params = aligned_params; | ||
| 1017 | // Can't have gaps in a surface | ||
| 1018 | new_params.width = aligned_params.stride; | ||
| 1019 | new_params.UpdateParams(); | ||
| 1020 | // GetSurface will create the new surface and possibly adjust res_scale if necessary | ||
| 1021 | surface = GetSurface(new_params, match_res_scale, load_if_create); | ||
| 1022 | } else if (load_if_create) { | ||
| 1023 | ValidateSurface(surface, aligned_params.addr, aligned_params.size); | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | return std::make_tuple(surface, surface->GetScaledSubRect(params)); | ||
| 1027 | } | 475 | } |
| 1028 | 476 | ||
| 1029 | Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { | 477 | Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { |
| 1030 | auto& gpu = Core::System::GetInstance().GPU(); | 478 | return GetSurface(SurfaceParams::CreateForTexture(config)); |
| 1031 | |||
| 1032 | SurfaceParams params; | ||
| 1033 | params.addr = config.tic.Address(); | ||
| 1034 | params.is_tiled = config.tic.IsTiled(); | ||
| 1035 | params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(config.tic.format); | ||
| 1036 | |||
| 1037 | params.width = Common::AlignUp(config.tic.Width(), params.GetCompresssionFactor()) / | ||
| 1038 | params.GetCompresssionFactor(); | ||
| 1039 | params.height = Common::AlignUp(config.tic.Height(), params.GetCompresssionFactor()) / | ||
| 1040 | params.GetCompresssionFactor(); | ||
| 1041 | |||
| 1042 | // TODO(Subv): Different types per component are not supported. | ||
| 1043 | ASSERT(config.tic.r_type.Value() == config.tic.g_type.Value() && | ||
| 1044 | config.tic.r_type.Value() == config.tic.b_type.Value() && | ||
| 1045 | config.tic.r_type.Value() == config.tic.a_type.Value()); | ||
| 1046 | |||
| 1047 | params.component_type = SurfaceParams::ComponentTypeFromTexture(config.tic.r_type.Value()); | ||
| 1048 | |||
| 1049 | if (config.tic.IsTiled()) { | ||
| 1050 | params.block_height = config.tic.BlockHeight(); | ||
| 1051 | params.width = Common::AlignUp(params.width, params.block_height); | ||
| 1052 | params.height = Common::AlignUp(params.height, params.block_height); | ||
| 1053 | } else { | ||
| 1054 | // Use the texture-provided stride value if the texture isn't tiled. | ||
| 1055 | params.stride = static_cast<u32>(params.PixelsInBytes(config.tic.Pitch())); | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | params.UpdateParams(); | ||
| 1059 | |||
| 1060 | if (params.GetActualWidth() % 8 != 0 || params.GetActualHeight() % 8 != 0 || | ||
| 1061 | params.stride != params.width) { | ||
| 1062 | Surface src_surface; | ||
| 1063 | MathUtil::Rectangle<u32> rect; | ||
| 1064 | std::tie(src_surface, rect) = GetSurfaceSubRect(params, ScaleMatch::Ignore, true); | ||
| 1065 | |||
| 1066 | rect = rect.Scale(params.GetCompresssionFactor()); | ||
| 1067 | |||
| 1068 | params.res_scale = src_surface->res_scale; | ||
| 1069 | Surface tmp_surface = CreateSurface(params); | ||
| 1070 | |||
| 1071 | auto dst_rect = tmp_surface->GetScaledRect().Scale(params.GetCompresssionFactor()); | ||
| 1072 | BlitTextures(src_surface->texture.handle, rect, tmp_surface->texture.handle, dst_rect, | ||
| 1073 | SurfaceParams::GetFormatType(params.pixel_format), read_framebuffer.handle, | ||
| 1074 | draw_framebuffer.handle); | ||
| 1075 | |||
| 1076 | remove_surfaces.emplace(tmp_surface); | ||
| 1077 | return tmp_surface; | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | return GetSurface(params, ScaleMatch::Ignore, true); | ||
| 1081 | } | 479 | } |
| 1082 | 480 | ||
| 1083 | SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( | 481 | SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( |
| 1084 | bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport) { | 482 | bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport) { |
| 1085 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | 483 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 1086 | const auto& config = regs.rt[0]; | ||
| 1087 | 484 | ||
| 1088 | // TODO(bunnei): This is hard corded to use just the first render buffer | 485 | // TODO(bunnei): This is hard corded to use just the first render buffer |
| 1089 | NGLOG_WARNING(Render_OpenGL, "hard-coded for render target 0!"); | 486 | LOG_WARNING(Render_OpenGL, "hard-coded for render target 0!"); |
| 1090 | |||
| 1091 | // update resolution_scale_factor and reset cache if changed | ||
| 1092 | // TODO (bunnei): This code was ported as-is from Citra, and is technically not thread-safe. We | ||
| 1093 | // need to fix this before making the renderer multi-threaded. | ||
| 1094 | static u16 resolution_scale_factor = GetResolutionScaleFactor(); | ||
| 1095 | if (resolution_scale_factor != GetResolutionScaleFactor()) { | ||
| 1096 | resolution_scale_factor = GetResolutionScaleFactor(); | ||
| 1097 | FlushAll(); | ||
| 1098 | while (!surface_cache.empty()) | ||
| 1099 | UnregisterSurface(*surface_cache.begin()->second.begin()); | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | MathUtil::Rectangle<u32> viewport_clamped{ | ||
| 1103 | static_cast<u32>(std::clamp(viewport.left, 0, static_cast<s32>(config.width))), | ||
| 1104 | static_cast<u32>(std::clamp(viewport.top, 0, static_cast<s32>(config.height))), | ||
| 1105 | static_cast<u32>(std::clamp(viewport.right, 0, static_cast<s32>(config.width))), | ||
| 1106 | static_cast<u32>(std::clamp(viewport.bottom, 0, static_cast<s32>(config.height)))}; | ||
| 1107 | 487 | ||
| 1108 | // get color and depth surfaces | 488 | // get color and depth surfaces |
| 1109 | SurfaceParams color_params; | 489 | SurfaceParams color_params{}; |
| 1110 | color_params.is_tiled = true; | 490 | SurfaceParams depth_params{}; |
| 1111 | color_params.res_scale = resolution_scale_factor; | 491 | |
| 1112 | color_params.width = config.width; | 492 | if (using_color_fb) { |
| 1113 | color_params.height = config.height; | 493 | color_params = SurfaceParams::CreateForFramebuffer(regs.rt[0]); |
| 1114 | // TODO(Subv): Can framebuffers use a different block height? | 494 | } |
| 1115 | color_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight; | 495 | |
| 1116 | SurfaceParams depth_params = color_params; | 496 | if (using_depth_fb) { |
| 1117 | 497 | depth_params = | |
| 1118 | color_params.addr = config.Address(); | 498 | SurfaceParams::CreateForDepthBuffer(regs.rt[0], regs.zeta.Address(), regs.zeta.format); |
| 1119 | color_params.pixel_format = SurfaceParams::PixelFormatFromRenderTargetFormat(config.format); | ||
| 1120 | color_params.component_type = SurfaceParams::ComponentTypeFromRenderTarget(config.format); | ||
| 1121 | color_params.UpdateParams(); | ||
| 1122 | |||
| 1123 | ASSERT_MSG(!using_depth_fb, "depth buffer is unimplemented"); | ||
| 1124 | // depth_params.addr = config.GetDepthBufferPhysicalAddress(); | ||
| 1125 | // depth_params.pixel_format = SurfaceParams::PixelFormatFromDepthFormat(config.depth_format); | ||
| 1126 | // depth_params.UpdateParams(); | ||
| 1127 | |||
| 1128 | auto color_vp_interval = color_params.GetSubRectInterval(viewport_clamped); | ||
| 1129 | auto depth_vp_interval = depth_params.GetSubRectInterval(viewport_clamped); | ||
| 1130 | |||
| 1131 | // Make sure that framebuffers don't overlap if both color and depth are being used | ||
| 1132 | if (using_color_fb && using_depth_fb && | ||
| 1133 | boost::icl::length(color_vp_interval & depth_vp_interval)) { | ||
| 1134 | NGLOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " | ||
| 1135 | "overlapping framebuffers not supported!"); | ||
| 1136 | using_depth_fb = false; | ||
| 1137 | } | 499 | } |
| 1138 | 500 | ||
| 1139 | MathUtil::Rectangle<u32> color_rect{}; | 501 | MathUtil::Rectangle<u32> color_rect{}; |
| 1140 | Surface color_surface = nullptr; | 502 | Surface color_surface; |
| 1141 | if (using_color_fb) | 503 | if (using_color_fb) { |
| 1142 | std::tie(color_surface, color_rect) = | 504 | color_surface = GetSurface(color_params); |
| 1143 | GetSurfaceSubRect(color_params, ScaleMatch::Exact, false); | 505 | if (color_surface) { |
| 506 | color_rect = color_surface->GetSurfaceParams().GetRect(); | ||
| 507 | } | ||
| 508 | } | ||
| 1144 | 509 | ||
| 1145 | MathUtil::Rectangle<u32> depth_rect{}; | 510 | MathUtil::Rectangle<u32> depth_rect{}; |
| 1146 | Surface depth_surface = nullptr; | 511 | Surface depth_surface; |
| 1147 | if (using_depth_fb) | 512 | if (using_depth_fb) { |
| 1148 | std::tie(depth_surface, depth_rect) = | 513 | depth_surface = GetSurface(depth_params); |
| 1149 | GetSurfaceSubRect(depth_params, ScaleMatch::Exact, false); | 514 | if (depth_surface) { |
| 515 | depth_rect = depth_surface->GetSurfaceParams().GetRect(); | ||
| 516 | } | ||
| 517 | } | ||
| 1150 | 518 | ||
| 1151 | MathUtil::Rectangle<u32> fb_rect{}; | 519 | MathUtil::Rectangle<u32> fb_rect{}; |
| 1152 | if (color_surface != nullptr && depth_surface != nullptr) { | 520 | if (color_surface && depth_surface) { |
| 1153 | fb_rect = color_rect; | 521 | fb_rect = color_rect; |
| 1154 | // Color and Depth surfaces must have the same dimensions and offsets | 522 | // Color and Depth surfaces must have the same dimensions and offsets |
| 1155 | if (color_rect.bottom != depth_rect.bottom || color_rect.top != depth_rect.top || | 523 | if (color_rect.bottom != depth_rect.bottom || color_rect.top != depth_rect.top || |
| 1156 | color_rect.left != depth_rect.left || color_rect.right != depth_rect.right) { | 524 | color_rect.left != depth_rect.left || color_rect.right != depth_rect.right) { |
| 1157 | color_surface = GetSurface(color_params, ScaleMatch::Exact, false); | 525 | color_surface = GetSurface(color_params); |
| 1158 | depth_surface = GetSurface(depth_params, ScaleMatch::Exact, false); | 526 | depth_surface = GetSurface(depth_params); |
| 1159 | fb_rect = color_surface->GetScaledRect(); | 527 | fb_rect = color_surface->GetSurfaceParams().GetRect(); |
| 1160 | } | 528 | } |
| 1161 | } else if (color_surface != nullptr) { | 529 | } else if (color_surface) { |
| 1162 | fb_rect = color_rect; | 530 | fb_rect = color_rect; |
| 1163 | } else if (depth_surface != nullptr) { | 531 | } else if (depth_surface) { |
| 1164 | fb_rect = depth_rect; | 532 | fb_rect = depth_rect; |
| 1165 | } | 533 | } |
| 1166 | 534 | ||
| 1167 | if (color_surface != nullptr) { | ||
| 1168 | ValidateSurface(color_surface, boost::icl::first(color_vp_interval), | ||
| 1169 | boost::icl::length(color_vp_interval)); | ||
| 1170 | } | ||
| 1171 | if (depth_surface != nullptr) { | ||
| 1172 | ValidateSurface(depth_surface, boost::icl::first(depth_vp_interval), | ||
| 1173 | boost::icl::length(depth_vp_interval)); | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | return std::make_tuple(color_surface, depth_surface, fb_rect); | 535 | return std::make_tuple(color_surface, depth_surface, fb_rect); |
| 1177 | } | 536 | } |
| 1178 | 537 | ||
| 1179 | Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) { | 538 | void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { |
| 1180 | UNREACHABLE(); | 539 | surface->LoadGLBuffer(); |
| 1181 | return {}; | 540 | surface->UploadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); |
| 1182 | } | 541 | } |
| 1183 | 542 | ||
| 1184 | SurfaceRect_Tuple RasterizerCacheOpenGL::GetTexCopySurface(const SurfaceParams& params) { | 543 | void RasterizerCacheOpenGL::MarkSurfaceAsDirty(const Surface& surface) { |
| 1185 | MathUtil::Rectangle<u32> rect{}; | 544 | if (Settings::values.use_accurate_framebuffers) { |
| 545 | // If enabled, always flush dirty surfaces | ||
| 546 | surface->DownloadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); | ||
| 547 | surface->FlushGLBuffer(); | ||
| 548 | } else { | ||
| 549 | // Otherwise, don't mark surfaces that we write to as cached, because the resulting loads | ||
| 550 | // and flushes are very slow and do not seem to improve accuracy | ||
| 551 | const auto& params{surface->GetSurfaceParams()}; | ||
| 552 | Memory::RasterizerMarkRegionCached(params.addr, params.size_in_bytes, false); | ||
| 553 | } | ||
| 554 | } | ||
| 1186 | 555 | ||
| 1187 | Surface match_surface = FindMatch<MatchFlags::TexCopy | MatchFlags::Invalid>( | 556 | Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params) { |
| 1188 | surface_cache, params, ScaleMatch::Ignore); | 557 | if (params.addr == 0 || params.height * params.width == 0) { |
| 558 | return {}; | ||
| 559 | } | ||
| 1189 | 560 | ||
| 1190 | if (match_surface != nullptr) { | 561 | const auto& gpu = Core::System::GetInstance().GPU(); |
| 1191 | ValidateSurface(match_surface, params.addr, params.size); | 562 | // Don't try to create any entries in the cache if the address of the texture is invalid. |
| 563 | if (gpu.memory_manager->GpuToCpuAddress(params.addr) == boost::none) | ||
| 564 | return {}; | ||
| 1192 | 565 | ||
| 1193 | SurfaceParams match_subrect; | 566 | // Check for an exact match in existing surfaces |
| 1194 | if (params.width != params.stride) { | 567 | const auto& surface_key{SurfaceKey::Create(params)}; |
| 1195 | const u32 tiled_size = match_surface->is_tiled ? 8 : 1; | 568 | const auto& search{surface_cache.find(surface_key)}; |
| 1196 | match_subrect = params; | 569 | Surface surface; |
| 1197 | match_subrect.width = | 570 | if (search != surface_cache.end()) { |
| 1198 | static_cast<u32>(match_surface->PixelsInBytes(params.width) / tiled_size); | 571 | surface = search->second; |
| 1199 | match_subrect.stride = | 572 | if (Settings::values.use_accurate_framebuffers) { |
| 1200 | static_cast<u32>(match_surface->PixelsInBytes(params.stride) / tiled_size); | 573 | // Reload the surface from Switch memory |
| 1201 | match_subrect.height *= tiled_size; | 574 | LoadSurface(surface); |
| 1202 | } else { | ||
| 1203 | match_subrect = match_surface->FromInterval(params.GetInterval()); | ||
| 1204 | ASSERT(match_subrect.GetInterval() == params.GetInterval()); | ||
| 1205 | } | 575 | } |
| 1206 | 576 | } else { | |
| 1207 | rect = match_surface->GetScaledSubRect(match_subrect); | 577 | surface = std::make_shared<CachedSurface>(params); |
| 578 | RegisterSurface(surface); | ||
| 579 | LoadSurface(surface); | ||
| 1208 | } | 580 | } |
| 1209 | 581 | ||
| 1210 | return std::make_tuple(match_surface, rect); | 582 | return surface; |
| 1211 | } | 583 | } |
| 1212 | 584 | ||
| 1213 | void RasterizerCacheOpenGL::DuplicateSurface(const Surface& src_surface, | 585 | Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr cpu_addr) const { |
| 1214 | const Surface& dest_surface) { | 586 | // Tries to find the GPU address of a framebuffer based on the CPU address. This is because |
| 1215 | ASSERT(dest_surface->addr <= src_surface->addr && dest_surface->end >= src_surface->end); | 587 | // final output framebuffers are specified by CPU address, but internally our GPU cache uses |
| 1216 | 588 | // GPU addresses. We iterate through all cached framebuffers, and compare their starting CPU | |
| 1217 | BlitSurfaces(src_surface, src_surface->GetScaledRect(), dest_surface, | 589 | // address to the one provided. This is obviously not great, and won't work if the |
| 1218 | dest_surface->GetScaledSubRect(*src_surface)); | 590 | // framebuffer overlaps surfaces. |
| 1219 | 591 | ||
| 1220 | dest_surface->invalid_regions -= src_surface->GetInterval(); | 592 | std::vector<Surface> surfaces; |
| 1221 | dest_surface->invalid_regions += src_surface->invalid_regions; | 593 | for (const auto& surface : surface_cache) { |
| 1222 | 594 | const auto& params = surface.second->GetSurfaceParams(); | |
| 1223 | SurfaceRegions regions; | 595 | const VAddr surface_cpu_addr = params.GetCpuAddr(); |
| 1224 | for (auto& pair : RangeFromInterval(dirty_regions, src_surface->GetInterval())) { | 596 | if (cpu_addr >= surface_cpu_addr && cpu_addr < (surface_cpu_addr + params.size_in_bytes)) { |
| 1225 | if (pair.second == src_surface) { | 597 | ASSERT_MSG(cpu_addr == surface_cpu_addr, "overlapping surfaces are unsupported"); |
| 1226 | regions += pair.first; | 598 | surfaces.push_back(surface.second); |
| 1227 | } | 599 | } |
| 1228 | } | 600 | } |
| 1229 | for (auto& interval : regions) { | ||
| 1230 | dirty_regions.set({interval, dest_surface}); | ||
| 1231 | } | ||
| 1232 | } | ||
| 1233 | 601 | ||
| 1234 | void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, Tegra::GPUVAddr addr, | 602 | if (surfaces.empty()) { |
| 1235 | u64 size) { | 603 | return {}; |
| 1236 | if (size == 0) | ||
| 1237 | return; | ||
| 1238 | |||
| 1239 | const SurfaceInterval validate_interval(addr, addr + size); | ||
| 1240 | |||
| 1241 | if (surface->type == SurfaceType::Fill) { | ||
| 1242 | // Sanity check, fill surfaces will always be valid when used | ||
| 1243 | ASSERT(surface->IsRegionValid(validate_interval)); | ||
| 1244 | return; | ||
| 1245 | } | 604 | } |
| 1246 | 605 | ||
| 1247 | while (true) { | 606 | ASSERT_MSG(surfaces.size() == 1, ">1 surface is unsupported"); |
| 1248 | const auto it = surface->invalid_regions.find(validate_interval); | ||
| 1249 | if (it == surface->invalid_regions.end()) | ||
| 1250 | break; | ||
| 1251 | |||
| 1252 | const auto interval = *it & validate_interval; | ||
| 1253 | // Look for a valid surface to copy from | ||
| 1254 | SurfaceParams params = surface->FromInterval(interval); | ||
| 1255 | |||
| 1256 | Surface copy_surface = | ||
| 1257 | FindMatch<MatchFlags::Copy>(surface_cache, params, ScaleMatch::Ignore, interval); | ||
| 1258 | if (copy_surface != nullptr) { | ||
| 1259 | SurfaceInterval copy_interval = params.GetCopyableInterval(copy_surface); | ||
| 1260 | CopySurface(copy_surface, surface, copy_interval); | ||
| 1261 | surface->invalid_regions.erase(copy_interval); | ||
| 1262 | continue; | ||
| 1263 | } | ||
| 1264 | 607 | ||
| 1265 | // Load data from Switch memory | 608 | return surfaces[0]; |
| 1266 | FlushRegion(params.addr, params.size); | ||
| 1267 | surface->LoadGLBuffer(params.addr, params.end); | ||
| 1268 | surface->UploadGLTexture(surface->GetSubRect(params), read_framebuffer.handle, | ||
| 1269 | draw_framebuffer.handle); | ||
| 1270 | surface->invalid_regions.erase(params.GetInterval()); | ||
| 1271 | } | ||
| 1272 | } | 609 | } |
| 1273 | 610 | ||
| 1274 | void RasterizerCacheOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size, Surface flush_surface) { | 611 | void RasterizerCacheOpenGL::FlushRegion(Tegra::GPUVAddr /*addr*/, size_t /*size*/) { |
| 1275 | if (size == 0) | 612 | // TODO(bunnei): This is unused in the current implementation of the rasterizer cache. We should |
| 1276 | return; | 613 | // probably implement this in the future, but for now, the `use_accurate_framebufers` setting |
| 1277 | 614 | // can be used to always flush. | |
| 1278 | const SurfaceInterval flush_interval(addr, addr + size); | 615 | } |
| 1279 | SurfaceRegions flushed_intervals; | ||
| 1280 | |||
| 1281 | for (auto& pair : RangeFromInterval(dirty_regions, flush_interval)) { | ||
| 1282 | // small sizes imply that this most likely comes from the cpu, flush the entire region | ||
| 1283 | // the point is to avoid thousands of small writes every frame if the cpu decides to access | ||
| 1284 | // that region, anything higher than 8 you're guaranteed it comes from a service | ||
| 1285 | const auto interval = size <= 8 ? pair.first : pair.first & flush_interval; | ||
| 1286 | auto& surface = pair.second; | ||
| 1287 | |||
| 1288 | if (flush_surface != nullptr && surface != flush_surface) | ||
| 1289 | continue; | ||
| 1290 | 616 | ||
| 1291 | // Sanity check, this surface is the last one that marked this region dirty | 617 | void RasterizerCacheOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, size_t size) { |
| 1292 | ASSERT(surface->IsRegionValid(interval)); | 618 | for (const auto& pair : surface_cache) { |
| 619 | const auto& surface{pair.second}; | ||
| 620 | const auto& params{surface->GetSurfaceParams()}; | ||
| 1293 | 621 | ||
| 1294 | if (surface->type != SurfaceType::Fill) { | 622 | if (params.IsOverlappingRegion(addr, size)) { |
| 1295 | SurfaceParams params = surface->FromInterval(interval); | 623 | UnregisterSurface(surface); |
| 1296 | surface->DownloadGLTexture(surface->GetSubRect(params), read_framebuffer.handle, | ||
| 1297 | draw_framebuffer.handle); | ||
| 1298 | } | 624 | } |
| 1299 | surface->FlushGLBuffer(boost::icl::first(interval), boost::icl::last_next(interval)); | ||
| 1300 | flushed_intervals += interval; | ||
| 1301 | } | 625 | } |
| 1302 | // Reset dirty regions | ||
| 1303 | dirty_regions -= flushed_intervals; | ||
| 1304 | } | 626 | } |
| 1305 | 627 | ||
| 1306 | void RasterizerCacheOpenGL::FlushAll() { | 628 | void RasterizerCacheOpenGL::RegisterSurface(const Surface& surface) { |
| 1307 | FlushRegion(0, Kernel::VMManager::MAX_ADDRESS); | 629 | const auto& params{surface->GetSurfaceParams()}; |
| 1308 | } | 630 | const auto& surface_key{SurfaceKey::Create(params)}; |
| 631 | const auto& search{surface_cache.find(surface_key)}; | ||
| 1309 | 632 | ||
| 1310 | void RasterizerCacheOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size, | 633 | if (search != surface_cache.end()) { |
| 1311 | const Surface& region_owner) { | 634 | // Registered already |
| 1312 | if (size == 0) | ||
| 1313 | return; | 635 | return; |
| 1314 | |||
| 1315 | const SurfaceInterval invalid_interval(addr, addr + size); | ||
| 1316 | |||
| 1317 | if (region_owner != nullptr) { | ||
| 1318 | ASSERT(addr >= region_owner->addr && addr + size <= region_owner->end); | ||
| 1319 | // Surfaces can't have a gap | ||
| 1320 | ASSERT(region_owner->width == region_owner->stride); | ||
| 1321 | region_owner->invalid_regions.erase(invalid_interval); | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | for (auto& pair : RangeFromInterval(surface_cache, invalid_interval)) { | ||
| 1325 | for (auto& cached_surface : pair.second) { | ||
| 1326 | if (cached_surface == region_owner) | ||
| 1327 | continue; | ||
| 1328 | |||
| 1329 | // If cpu is invalidating this region we want to remove it | ||
| 1330 | // to (likely) mark the memory pages as uncached | ||
| 1331 | if (region_owner == nullptr && size <= 8) { | ||
| 1332 | FlushRegion(cached_surface->addr, cached_surface->size, cached_surface); | ||
| 1333 | remove_surfaces.emplace(cached_surface); | ||
| 1334 | continue; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | const auto interval = cached_surface->GetInterval() & invalid_interval; | ||
| 1338 | cached_surface->invalid_regions.insert(interval); | ||
| 1339 | |||
| 1340 | // Remove only "empty" fill surfaces to avoid destroying and recreating OGL textures | ||
| 1341 | if (cached_surface->type == SurfaceType::Fill && | ||
| 1342 | cached_surface->IsSurfaceFullyInvalid()) { | ||
| 1343 | remove_surfaces.emplace(cached_surface); | ||
| 1344 | } | ||
| 1345 | } | ||
| 1346 | } | 636 | } |
| 1347 | 637 | ||
| 1348 | if (region_owner != nullptr) | 638 | surface_cache[surface_key] = surface; |
| 1349 | dirty_regions.set({invalid_interval, region_owner}); | 639 | UpdatePagesCachedCount(params.addr, params.size_in_bytes, 1); |
| 1350 | else | ||
| 1351 | dirty_regions.erase(invalid_interval); | ||
| 1352 | |||
| 1353 | for (auto& remove_surface : remove_surfaces) { | ||
| 1354 | if (remove_surface == region_owner) { | ||
| 1355 | Surface expanded_surface = FindMatch<MatchFlags::SubRect | MatchFlags::Invalid>( | ||
| 1356 | surface_cache, *region_owner, ScaleMatch::Ignore); | ||
| 1357 | ASSERT(expanded_surface); | ||
| 1358 | |||
| 1359 | if ((region_owner->invalid_regions - expanded_surface->invalid_regions).empty()) { | ||
| 1360 | DuplicateSurface(region_owner, expanded_surface); | ||
| 1361 | } else { | ||
| 1362 | continue; | ||
| 1363 | } | ||
| 1364 | } | ||
| 1365 | UnregisterSurface(remove_surface); | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | remove_surfaces.clear(); | ||
| 1369 | } | 640 | } |
| 1370 | 641 | ||
| 1371 | Surface RasterizerCacheOpenGL::CreateSurface(const SurfaceParams& params) { | 642 | void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) { |
| 1372 | Surface surface = std::make_shared<CachedSurface>(); | 643 | const auto& params{surface->GetSurfaceParams()}; |
| 1373 | static_cast<SurfaceParams&>(*surface) = params; | 644 | const auto& surface_key{SurfaceKey::Create(params)}; |
| 1374 | 645 | const auto& search{surface_cache.find(surface_key)}; | |
| 1375 | surface->texture.Create(); | ||
| 1376 | |||
| 1377 | surface->gl_buffer_size = 0; | ||
| 1378 | surface->invalid_regions.insert(surface->GetInterval()); | ||
| 1379 | AllocateSurfaceTexture(surface->texture.handle, | ||
| 1380 | GetFormatTuple(surface->pixel_format, surface->component_type), | ||
| 1381 | surface->GetScaledWidth(), surface->GetScaledHeight()); | ||
| 1382 | |||
| 1383 | return surface; | ||
| 1384 | } | ||
| 1385 | 646 | ||
| 1386 | void RasterizerCacheOpenGL::RegisterSurface(const Surface& surface) { | 647 | if (search == surface_cache.end()) { |
| 1387 | if (surface->registered) { | 648 | // Unregistered already |
| 1388 | return; | 649 | return; |
| 1389 | } | 650 | } |
| 1390 | surface->registered = true; | 651 | |
| 1391 | surface_cache.add({surface->GetInterval(), SurfaceSet{surface}}); | 652 | UpdatePagesCachedCount(params.addr, params.size_in_bytes, -1); |
| 1392 | UpdatePagesCachedCount(surface->addr, surface->size, 1); | 653 | surface_cache.erase(search); |
| 1393 | } | 654 | } |
| 1394 | 655 | ||
| 1395 | void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) { | 656 | template <typename Map, typename Interval> |
| 1396 | if (!surface->registered) { | 657 | constexpr auto RangeFromInterval(Map& map, const Interval& interval) { |
| 1397 | return; | 658 | return boost::make_iterator_range(map.equal_range(interval)); |
| 1398 | } | ||
| 1399 | surface->registered = false; | ||
| 1400 | UpdatePagesCachedCount(surface->addr, surface->size, -1); | ||
| 1401 | surface_cache.subtract({surface->GetInterval(), SurfaceSet{surface}}); | ||
| 1402 | } | 659 | } |
| 1403 | 660 | ||
| 1404 | void RasterizerCacheOpenGL::UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) { | 661 | void RasterizerCacheOpenGL::UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 0f43e863d..1bedae992 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -1,57 +1,26 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | 1 | // Copyright 2018 yuzu Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <map> | ||
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | #include <set> | 10 | #include <vector> |
| 10 | #include <tuple> | ||
| 11 | #ifdef __GNUC__ | ||
| 12 | #pragma GCC diagnostic push | ||
| 13 | #pragma GCC diagnostic ignored "-Wunused-local-typedefs" | ||
| 14 | #endif | ||
| 15 | #include <boost/icl/interval_map.hpp> | 11 | #include <boost/icl/interval_map.hpp> |
| 16 | #include <boost/icl/interval_set.hpp> | ||
| 17 | #ifdef __GNUC__ | ||
| 18 | #pragma GCC diagnostic pop | ||
| 19 | #endif | ||
| 20 | #include <boost/optional.hpp> | ||
| 21 | #include <glad/glad.h> | ||
| 22 | #include "common/assert.h" | ||
| 23 | #include "common/common_funcs.h" | ||
| 24 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "common/hash.h" | ||
| 25 | #include "common/math_util.h" | 14 | #include "common/math_util.h" |
| 26 | #include "video_core/gpu.h" | 15 | #include "video_core/engines/maxwell_3d.h" |
| 27 | #include "video_core/memory_manager.h" | ||
| 28 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 16 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 29 | #include "video_core/textures/texture.h" | 17 | #include "video_core/textures/texture.h" |
| 30 | 18 | ||
| 31 | struct CachedSurface; | 19 | class CachedSurface; |
| 32 | using Surface = std::shared_ptr<CachedSurface>; | 20 | using Surface = std::shared_ptr<CachedSurface>; |
| 33 | using SurfaceSet = std::set<Surface>; | ||
| 34 | |||
| 35 | using SurfaceRegions = boost::icl::interval_set<Tegra::GPUVAddr>; | ||
| 36 | using SurfaceMap = boost::icl::interval_map<Tegra::GPUVAddr, Surface>; | ||
| 37 | using SurfaceCache = boost::icl::interval_map<Tegra::GPUVAddr, SurfaceSet>; | ||
| 38 | |||
| 39 | using SurfaceInterval = SurfaceCache::interval_type; | ||
| 40 | static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval_type>() && | ||
| 41 | std::is_same<SurfaceMap::interval_type, SurfaceCache::interval_type>(), | ||
| 42 | "incorrect interval types"); | ||
| 43 | |||
| 44 | using SurfaceRect_Tuple = std::tuple<Surface, MathUtil::Rectangle<u32>>; | ||
| 45 | using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; | 21 | using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; |
| 46 | |||
| 47 | using PageMap = boost::icl::interval_map<u64, int>; | 22 | using PageMap = boost::icl::interval_map<u64, int>; |
| 48 | 23 | ||
| 49 | enum class ScaleMatch { | ||
| 50 | Exact, // only accept same res scale | ||
| 51 | Upscale, // only allow higher scale than params | ||
| 52 | Ignore // accept every scaled res | ||
| 53 | }; | ||
| 54 | |||
| 55 | struct SurfaceParams { | 24 | struct SurfaceParams { |
| 56 | enum class PixelFormat { | 25 | enum class PixelFormat { |
| 57 | ABGR8 = 0, | 26 | ABGR8 = 0, |
| @@ -61,12 +30,24 @@ struct SurfaceParams { | |||
| 61 | R8 = 4, | 30 | R8 = 4, |
| 62 | RGBA16F = 5, | 31 | RGBA16F = 5, |
| 63 | R11FG11FB10F = 6, | 32 | R11FG11FB10F = 6, |
| 64 | DXT1 = 7, | 33 | RGBA32UI = 7, |
| 65 | DXT23 = 8, | 34 | DXT1 = 8, |
| 66 | DXT45 = 9, | 35 | DXT23 = 9, |
| 67 | DXN1 = 10, // This is also known as BC4 | 36 | DXT45 = 10, |
| 37 | DXN1 = 11, // This is also known as BC4 | ||
| 38 | BC7U = 12, | ||
| 39 | ASTC_2D_4X4 = 13, | ||
| 68 | 40 | ||
| 69 | Max, | 41 | MaxColorFormat, |
| 42 | |||
| 43 | // DepthStencil formats | ||
| 44 | Z24S8 = 14, | ||
| 45 | S8Z24 = 15, | ||
| 46 | Z32F = 16, | ||
| 47 | |||
| 48 | MaxDepthStencilFormat, | ||
| 49 | |||
| 50 | Max = MaxDepthStencilFormat, | ||
| 70 | Invalid = 255, | 51 | Invalid = 255, |
| 71 | }; | 52 | }; |
| 72 | 53 | ||
| @@ -92,10 +73,10 @@ struct SurfaceParams { | |||
| 92 | /** | 73 | /** |
| 93 | * Gets the compression factor for the specified PixelFormat. This applies to just the | 74 | * Gets the compression factor for the specified PixelFormat. This applies to just the |
| 94 | * "compressed width" and "compressed height", not the overall compression factor of a | 75 | * "compressed width" and "compressed height", not the overall compression factor of a |
| 95 | * compressed image. This is used for maintaining proper surface sizes for compressed texture | 76 | * compressed image. This is used for maintaining proper surface sizes for compressed |
| 96 | * formats. | 77 | * texture formats. |
| 97 | */ | 78 | */ |
| 98 | static constexpr u32 GetCompresssionFactor(PixelFormat format) { | 79 | static constexpr u32 GetCompressionFactor(PixelFormat format) { |
| 99 | if (format == PixelFormat::Invalid) | 80 | if (format == PixelFormat::Invalid) |
| 100 | return 0; | 81 | return 0; |
| 101 | 82 | ||
| @@ -107,18 +88,21 @@ struct SurfaceParams { | |||
| 107 | 1, // R8 | 88 | 1, // R8 |
| 108 | 1, // RGBA16F | 89 | 1, // RGBA16F |
| 109 | 1, // R11FG11FB10F | 90 | 1, // R11FG11FB10F |
| 91 | 1, // RGBA32UI | ||
| 110 | 4, // DXT1 | 92 | 4, // DXT1 |
| 111 | 4, // DXT23 | 93 | 4, // DXT23 |
| 112 | 4, // DXT45 | 94 | 4, // DXT45 |
| 113 | 4, // DXN1 | 95 | 4, // DXN1 |
| 96 | 4, // BC7U | ||
| 97 | 4, // ASTC_2D_4X4 | ||
| 98 | 1, // Z24S8 | ||
| 99 | 1, // S8Z24 | ||
| 100 | 1, // Z32F | ||
| 114 | }}; | 101 | }}; |
| 115 | 102 | ||
| 116 | ASSERT(static_cast<size_t>(format) < compression_factor_table.size()); | 103 | ASSERT(static_cast<size_t>(format) < compression_factor_table.size()); |
| 117 | return compression_factor_table[static_cast<size_t>(format)]; | 104 | return compression_factor_table[static_cast<size_t>(format)]; |
| 118 | } | 105 | } |
| 119 | u32 GetCompresssionFactor() const { | ||
| 120 | return GetCompresssionFactor(pixel_format); | ||
| 121 | } | ||
| 122 | 106 | ||
| 123 | static constexpr u32 GetFormatBpp(PixelFormat format) { | 107 | static constexpr u32 GetFormatBpp(PixelFormat format) { |
| 124 | if (format == PixelFormat::Invalid) | 108 | if (format == PixelFormat::Invalid) |
| @@ -132,10 +116,16 @@ struct SurfaceParams { | |||
| 132 | 8, // R8 | 116 | 8, // R8 |
| 133 | 64, // RGBA16F | 117 | 64, // RGBA16F |
| 134 | 32, // R11FG11FB10F | 118 | 32, // R11FG11FB10F |
| 119 | 128, // RGBA32UI | ||
| 135 | 64, // DXT1 | 120 | 64, // DXT1 |
| 136 | 128, // DXT23 | 121 | 128, // DXT23 |
| 137 | 128, // DXT45 | 122 | 128, // DXT45 |
| 138 | 64, // DXN1 | 123 | 64, // DXN1 |
| 124 | 128, // BC7U | ||
| 125 | 32, // ASTC_2D_4X4 | ||
| 126 | 32, // Z24S8 | ||
| 127 | 32, // S8Z24 | ||
| 128 | 32, // Z32F | ||
| 139 | }}; | 129 | }}; |
| 140 | 130 | ||
| 141 | ASSERT(static_cast<size_t>(format) < bpp_table.size()); | 131 | ASSERT(static_cast<size_t>(format) < bpp_table.size()); |
| @@ -145,6 +135,20 @@ struct SurfaceParams { | |||
| 145 | return GetFormatBpp(pixel_format); | 135 | return GetFormatBpp(pixel_format); |
| 146 | } | 136 | } |
| 147 | 137 | ||
| 138 | static PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) { | ||
| 139 | switch (format) { | ||
| 140 | case Tegra::DepthFormat::S8_Z24_UNORM: | ||
| 141 | return PixelFormat::S8Z24; | ||
| 142 | case Tegra::DepthFormat::Z24_S8_UNORM: | ||
| 143 | return PixelFormat::Z24S8; | ||
| 144 | case Tegra::DepthFormat::Z32_FLOAT: | ||
| 145 | return PixelFormat::Z32F; | ||
| 146 | default: | ||
| 147 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); | ||
| 148 | UNREACHABLE(); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 148 | static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) { | 152 | static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) { |
| 149 | switch (format) { | 153 | switch (format) { |
| 150 | case Tegra::RenderTargetFormat::RGBA8_UNORM: | 154 | case Tegra::RenderTargetFormat::RGBA8_UNORM: |
| @@ -156,18 +160,10 @@ struct SurfaceParams { | |||
| 156 | return PixelFormat::RGBA16F; | 160 | return PixelFormat::RGBA16F; |
| 157 | case Tegra::RenderTargetFormat::R11G11B10_FLOAT: | 161 | case Tegra::RenderTargetFormat::R11G11B10_FLOAT: |
| 158 | return PixelFormat::R11FG11FB10F; | 162 | return PixelFormat::R11FG11FB10F; |
| 163 | case Tegra::RenderTargetFormat::RGBA32_UINT: | ||
| 164 | return PixelFormat::RGBA32UI; | ||
| 159 | default: | 165 | default: |
| 160 | NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); | 166 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); |
| 161 | UNREACHABLE(); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { | ||
| 166 | switch (format) { | ||
| 167 | case Tegra::FramebufferConfig::PixelFormat::ABGR8: | ||
| 168 | return PixelFormat::ABGR8; | ||
| 169 | default: | ||
| 170 | NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); | ||
| 171 | UNREACHABLE(); | 167 | UNREACHABLE(); |
| 172 | } | 168 | } |
| 173 | } | 169 | } |
| @@ -189,6 +185,8 @@ struct SurfaceParams { | |||
| 189 | return PixelFormat::RGBA16F; | 185 | return PixelFormat::RGBA16F; |
| 190 | case Tegra::Texture::TextureFormat::BF10GF11RF11: | 186 | case Tegra::Texture::TextureFormat::BF10GF11RF11: |
| 191 | return PixelFormat::R11FG11FB10F; | 187 | return PixelFormat::R11FG11FB10F; |
| 188 | case Tegra::Texture::TextureFormat::R32_G32_B32_A32: | ||
| 189 | return PixelFormat::RGBA32UI; | ||
| 192 | case Tegra::Texture::TextureFormat::DXT1: | 190 | case Tegra::Texture::TextureFormat::DXT1: |
| 193 | return PixelFormat::DXT1; | 191 | return PixelFormat::DXT1; |
| 194 | case Tegra::Texture::TextureFormat::DXT23: | 192 | case Tegra::Texture::TextureFormat::DXT23: |
| @@ -197,8 +195,12 @@ struct SurfaceParams { | |||
| 197 | return PixelFormat::DXT45; | 195 | return PixelFormat::DXT45; |
| 198 | case Tegra::Texture::TextureFormat::DXN1: | 196 | case Tegra::Texture::TextureFormat::DXN1: |
| 199 | return PixelFormat::DXN1; | 197 | return PixelFormat::DXN1; |
| 198 | case Tegra::Texture::TextureFormat::BC7U: | ||
| 199 | return PixelFormat::BC7U; | ||
| 200 | case Tegra::Texture::TextureFormat::ASTC_2D_4X4: | ||
| 201 | return PixelFormat::ASTC_2D_4X4; | ||
| 200 | default: | 202 | default: |
| 201 | NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); | 203 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); |
| 202 | UNREACHABLE(); | 204 | UNREACHABLE(); |
| 203 | } | 205 | } |
| 204 | } | 206 | } |
| @@ -220,6 +222,8 @@ struct SurfaceParams { | |||
| 220 | return Tegra::Texture::TextureFormat::R16_G16_B16_A16; | 222 | return Tegra::Texture::TextureFormat::R16_G16_B16_A16; |
| 221 | case PixelFormat::R11FG11FB10F: | 223 | case PixelFormat::R11FG11FB10F: |
| 222 | return Tegra::Texture::TextureFormat::BF10GF11RF11; | 224 | return Tegra::Texture::TextureFormat::BF10GF11RF11; |
| 225 | case PixelFormat::RGBA32UI: | ||
| 226 | return Tegra::Texture::TextureFormat::R32_G32_B32_A32; | ||
| 223 | case PixelFormat::DXT1: | 227 | case PixelFormat::DXT1: |
| 224 | return Tegra::Texture::TextureFormat::DXT1; | 228 | return Tegra::Texture::TextureFormat::DXT1; |
| 225 | case PixelFormat::DXT23: | 229 | case PixelFormat::DXT23: |
| @@ -228,6 +232,23 @@ struct SurfaceParams { | |||
| 228 | return Tegra::Texture::TextureFormat::DXT45; | 232 | return Tegra::Texture::TextureFormat::DXT45; |
| 229 | case PixelFormat::DXN1: | 233 | case PixelFormat::DXN1: |
| 230 | return Tegra::Texture::TextureFormat::DXN1; | 234 | return Tegra::Texture::TextureFormat::DXN1; |
| 235 | case PixelFormat::BC7U: | ||
| 236 | return Tegra::Texture::TextureFormat::BC7U; | ||
| 237 | case PixelFormat::ASTC_2D_4X4: | ||
| 238 | return Tegra::Texture::TextureFormat::ASTC_2D_4X4; | ||
| 239 | default: | ||
| 240 | UNREACHABLE(); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | static Tegra::DepthFormat DepthFormatFromPixelFormat(PixelFormat format) { | ||
| 245 | switch (format) { | ||
| 246 | case PixelFormat::S8Z24: | ||
| 247 | return Tegra::DepthFormat::S8_Z24_UNORM; | ||
| 248 | case PixelFormat::Z24S8: | ||
| 249 | return Tegra::DepthFormat::Z24_S8_UNORM; | ||
| 250 | case PixelFormat::Z32F: | ||
| 251 | return Tegra::DepthFormat::Z32_FLOAT; | ||
| 231 | default: | 252 | default: |
| 232 | UNREACHABLE(); | 253 | UNREACHABLE(); |
| 233 | } | 254 | } |
| @@ -239,7 +260,7 @@ struct SurfaceParams { | |||
| 239 | case Tegra::Texture::ComponentType::UNORM: | 260 | case Tegra::Texture::ComponentType::UNORM: |
| 240 | return ComponentType::UNorm; | 261 | return ComponentType::UNorm; |
| 241 | default: | 262 | default: |
| 242 | NGLOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type)); | 263 | LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type)); |
| 243 | UNREACHABLE(); | 264 | UNREACHABLE(); |
| 244 | } | 265 | } |
| 245 | } | 266 | } |
| @@ -254,215 +275,153 @@ struct SurfaceParams { | |||
| 254 | case Tegra::RenderTargetFormat::RGBA16_FLOAT: | 275 | case Tegra::RenderTargetFormat::RGBA16_FLOAT: |
| 255 | case Tegra::RenderTargetFormat::R11G11B10_FLOAT: | 276 | case Tegra::RenderTargetFormat::R11G11B10_FLOAT: |
| 256 | return ComponentType::Float; | 277 | return ComponentType::Float; |
| 278 | case Tegra::RenderTargetFormat::RGBA32_UINT: | ||
| 279 | return ComponentType::UInt; | ||
| 257 | default: | 280 | default: |
| 258 | NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); | 281 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); |
| 259 | UNREACHABLE(); | 282 | UNREACHABLE(); |
| 260 | } | 283 | } |
| 261 | } | 284 | } |
| 262 | 285 | ||
| 263 | static ComponentType ComponentTypeFromGPUPixelFormat( | 286 | static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { |
| 264 | Tegra::FramebufferConfig::PixelFormat format) { | ||
| 265 | switch (format) { | 287 | switch (format) { |
| 266 | case Tegra::FramebufferConfig::PixelFormat::ABGR8: | 288 | case Tegra::FramebufferConfig::PixelFormat::ABGR8: |
| 267 | return ComponentType::UNorm; | 289 | return PixelFormat::ABGR8; |
| 268 | default: | 290 | default: |
| 269 | NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); | 291 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); |
| 270 | UNREACHABLE(); | 292 | UNREACHABLE(); |
| 271 | } | 293 | } |
| 272 | } | 294 | } |
| 273 | 295 | ||
| 274 | static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) { | 296 | static ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) { |
| 275 | SurfaceType a_type = GetFormatType(pixel_format_a); | 297 | switch (format) { |
| 276 | SurfaceType b_type = GetFormatType(pixel_format_b); | 298 | case Tegra::DepthFormat::S8_Z24_UNORM: |
| 277 | 299 | case Tegra::DepthFormat::Z24_S8_UNORM: | |
| 278 | if (a_type == SurfaceType::ColorTexture && b_type == SurfaceType::ColorTexture) { | 300 | return ComponentType::UNorm; |
| 279 | return true; | 301 | case Tegra::DepthFormat::Z32_FLOAT: |
| 280 | } | 302 | return ComponentType::Float; |
| 281 | 303 | default: | |
| 282 | if (a_type == SurfaceType::Depth && b_type == SurfaceType::Depth) { | 304 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); |
| 283 | return true; | 305 | UNREACHABLE(); |
| 284 | } | ||
| 285 | |||
| 286 | if (a_type == SurfaceType::DepthStencil && b_type == SurfaceType::DepthStencil) { | ||
| 287 | return true; | ||
| 288 | } | 306 | } |
| 289 | |||
| 290 | return false; | ||
| 291 | } | 307 | } |
| 292 | 308 | ||
| 293 | static SurfaceType GetFormatType(PixelFormat pixel_format) { | 309 | static SurfaceType GetFormatType(PixelFormat pixel_format) { |
| 294 | if (static_cast<size_t>(pixel_format) < MaxPixelFormat) { | 310 | if (static_cast<size_t>(pixel_format) < static_cast<size_t>(PixelFormat::MaxColorFormat)) { |
| 295 | return SurfaceType::ColorTexture; | 311 | return SurfaceType::ColorTexture; |
| 296 | } | 312 | } |
| 297 | 313 | ||
| 314 | if (static_cast<size_t>(pixel_format) < | ||
| 315 | static_cast<size_t>(PixelFormat::MaxDepthStencilFormat)) { | ||
| 316 | return SurfaceType::DepthStencil; | ||
| 317 | } | ||
| 318 | |||
| 298 | // TODO(Subv): Implement the other formats | 319 | // TODO(Subv): Implement the other formats |
| 299 | ASSERT(false); | 320 | ASSERT(false); |
| 300 | 321 | ||
| 301 | return SurfaceType::Invalid; | 322 | return SurfaceType::Invalid; |
| 302 | } | 323 | } |
| 303 | 324 | ||
| 304 | /// Update the params "size", "end" and "type" from the already set "addr", "width", "height" | 325 | /// Returns the rectangle corresponding to this surface |
| 305 | /// and "pixel_format" | 326 | MathUtil::Rectangle<u32> GetRect() const; |
| 306 | void UpdateParams() { | ||
| 307 | if (stride == 0) { | ||
| 308 | stride = width; | ||
| 309 | } | ||
| 310 | type = GetFormatType(pixel_format); | ||
| 311 | size = !is_tiled ? BytesInPixels(stride * (height - 1) + width) | ||
| 312 | : BytesInPixels(stride * 8 * (height / 8 - 1) + width * 8); | ||
| 313 | end = addr + size; | ||
| 314 | } | ||
| 315 | |||
| 316 | SurfaceInterval GetInterval() const { | ||
| 317 | return SurfaceInterval::right_open(addr, end); | ||
| 318 | } | ||
| 319 | |||
| 320 | // Returns the outer rectangle containing "interval" | ||
| 321 | SurfaceParams FromInterval(SurfaceInterval interval) const; | ||
| 322 | |||
| 323 | SurfaceInterval GetSubRectInterval(MathUtil::Rectangle<u32> unscaled_rect) const; | ||
| 324 | |||
| 325 | // Returns the region of the biggest valid rectange within interval | ||
| 326 | SurfaceInterval GetCopyableInterval(const Surface& src_surface) const; | ||
| 327 | |||
| 328 | /** | ||
| 329 | * Gets the actual width (in pixels) of the surface. This is provided because `width` is used | ||
| 330 | * for tracking the surface region in memory, which may be compressed for certain formats. In | ||
| 331 | * this scenario, `width` is actually the compressed width. | ||
| 332 | */ | ||
| 333 | u32 GetActualWidth() const { | ||
| 334 | return width * GetCompresssionFactor(); | ||
| 335 | } | ||
| 336 | |||
| 337 | /** | ||
| 338 | * Gets the actual height (in pixels) of the surface. This is provided because `height` is used | ||
| 339 | * for tracking the surface region in memory, which may be compressed for certain formats. In | ||
| 340 | * this scenario, `height` is actually the compressed height. | ||
| 341 | */ | ||
| 342 | u32 GetActualHeight() const { | ||
| 343 | return height * GetCompresssionFactor(); | ||
| 344 | } | ||
| 345 | 327 | ||
| 346 | u32 GetScaledWidth() const { | 328 | /// Returns the size of this surface in bytes, adjusted for compression |
| 347 | return width * res_scale; | 329 | size_t SizeInBytes() const { |
| 330 | const u32 compression_factor{GetCompressionFactor(pixel_format)}; | ||
| 331 | ASSERT(width % compression_factor == 0); | ||
| 332 | ASSERT(height % compression_factor == 0); | ||
| 333 | return (width / compression_factor) * (height / compression_factor) * | ||
| 334 | GetFormatBpp(pixel_format) / CHAR_BIT; | ||
| 348 | } | 335 | } |
| 349 | 336 | ||
| 350 | u32 GetScaledHeight() const { | 337 | /// Returns the CPU virtual address for this surface |
| 351 | return height * res_scale; | 338 | VAddr GetCpuAddr() const; |
| 352 | } | ||
| 353 | 339 | ||
| 354 | MathUtil::Rectangle<u32> GetRect() const { | 340 | /// Returns true if the specified region overlaps with this surface's region in Switch memory |
| 355 | return {0, height, width, 0}; | 341 | bool IsOverlappingRegion(Tegra::GPUVAddr region_addr, size_t region_size) const { |
| 342 | return addr <= (region_addr + region_size) && region_addr <= (addr + size_in_bytes); | ||
| 356 | } | 343 | } |
| 357 | 344 | ||
| 358 | MathUtil::Rectangle<u32> GetScaledRect() const { | 345 | /// Creates SurfaceParams from a texture configuration |
| 359 | return {0, GetScaledHeight(), GetScaledWidth(), 0}; | 346 | static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config); |
| 360 | } | 347 | |
| 348 | /// Creates SurfaceParams from a framebuffer configuration | ||
| 349 | static SurfaceParams CreateForFramebuffer( | ||
| 350 | const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config); | ||
| 351 | |||
| 352 | /// Creates SurfaceParams for a depth buffer configuration | ||
| 353 | static SurfaceParams CreateForDepthBuffer( | ||
| 354 | const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config, | ||
| 355 | Tegra::GPUVAddr zeta_address, Tegra::DepthFormat format); | ||
| 356 | |||
| 357 | Tegra::GPUVAddr addr; | ||
| 358 | bool is_tiled; | ||
| 359 | u32 block_height; | ||
| 360 | PixelFormat pixel_format; | ||
| 361 | ComponentType component_type; | ||
| 362 | SurfaceType type; | ||
| 363 | u32 width; | ||
| 364 | u32 height; | ||
| 365 | u32 unaligned_height; | ||
| 366 | size_t size_in_bytes; | ||
| 367 | }; | ||
| 361 | 368 | ||
| 362 | u64 PixelsInBytes(u64 size) const { | 369 | /// Hashable variation of SurfaceParams, used for a key in the surface cache |
| 363 | return size * CHAR_BIT / GetFormatBpp(pixel_format); | 370 | struct SurfaceKey : Common::HashableStruct<SurfaceParams> { |
| 371 | static SurfaceKey Create(const SurfaceParams& params) { | ||
| 372 | SurfaceKey res; | ||
| 373 | res.state = params; | ||
| 374 | return res; | ||
| 364 | } | 375 | } |
| 376 | }; | ||
| 365 | 377 | ||
| 366 | u64 BytesInPixels(u64 pixels) const { | 378 | namespace std { |
| 367 | return pixels * GetFormatBpp(pixel_format) / CHAR_BIT; | 379 | template <> |
| 380 | struct hash<SurfaceKey> { | ||
| 381 | size_t operator()(const SurfaceKey& k) const { | ||
| 382 | return k.Hash(); | ||
| 368 | } | 383 | } |
| 369 | |||
| 370 | VAddr GetCpuAddr() const; | ||
| 371 | |||
| 372 | bool ExactMatch(const SurfaceParams& other_surface) const; | ||
| 373 | bool CanSubRect(const SurfaceParams& sub_surface) const; | ||
| 374 | bool CanExpand(const SurfaceParams& expanded_surface) const; | ||
| 375 | bool CanTexCopy(const SurfaceParams& texcopy_params) const; | ||
| 376 | |||
| 377 | MathUtil::Rectangle<u32> GetSubRect(const SurfaceParams& sub_surface) const; | ||
| 378 | MathUtil::Rectangle<u32> GetScaledSubRect(const SurfaceParams& sub_surface) const; | ||
| 379 | |||
| 380 | Tegra::GPUVAddr addr = 0; | ||
| 381 | Tegra::GPUVAddr end = 0; | ||
| 382 | boost::optional<VAddr> cpu_addr; | ||
| 383 | u64 size = 0; | ||
| 384 | |||
| 385 | u32 width = 0; | ||
| 386 | u32 height = 0; | ||
| 387 | u32 stride = 0; | ||
| 388 | u32 block_height = 0; | ||
| 389 | u16 res_scale = 1; | ||
| 390 | |||
| 391 | bool is_tiled = false; | ||
| 392 | PixelFormat pixel_format = PixelFormat::Invalid; | ||
| 393 | SurfaceType type = SurfaceType::Invalid; | ||
| 394 | ComponentType component_type = ComponentType::Invalid; | ||
| 395 | }; | 384 | }; |
| 385 | } // namespace std | ||
| 396 | 386 | ||
| 397 | struct CachedSurface : SurfaceParams { | 387 | class CachedSurface final { |
| 398 | bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const; | 388 | public: |
| 399 | bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const; | 389 | CachedSurface(const SurfaceParams& params); |
| 400 | |||
| 401 | bool IsRegionValid(SurfaceInterval interval) const { | ||
| 402 | return (invalid_regions.find(interval) == invalid_regions.end()); | ||
| 403 | } | ||
| 404 | 390 | ||
| 405 | bool IsSurfaceFullyInvalid() const { | 391 | const OGLTexture& Texture() const { |
| 406 | return (invalid_regions & GetInterval()) == SurfaceRegions(GetInterval()); | 392 | return texture; |
| 407 | } | 393 | } |
| 408 | 394 | ||
| 409 | bool registered = false; | 395 | static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) { |
| 410 | SurfaceRegions invalid_regions; | 396 | if (format == SurfaceParams::PixelFormat::Invalid) |
| 411 | |||
| 412 | u64 fill_size = 0; /// Number of bytes to read from fill_data | ||
| 413 | std::array<u8, 4> fill_data; | ||
| 414 | |||
| 415 | OGLTexture texture; | ||
| 416 | |||
| 417 | static constexpr unsigned int GetGLBytesPerPixel(PixelFormat format) { | ||
| 418 | if (format == PixelFormat::Invalid) | ||
| 419 | return 0; | 397 | return 0; |
| 420 | 398 | ||
| 421 | return SurfaceParams::GetFormatBpp(format) / CHAR_BIT; | 399 | return SurfaceParams::GetFormatBpp(format) / CHAR_BIT; |
| 422 | } | 400 | } |
| 423 | 401 | ||
| 424 | std::unique_ptr<u8[]> gl_buffer; | 402 | const SurfaceParams& GetSurfaceParams() const { |
| 425 | size_t gl_buffer_size = 0; | 403 | return params; |
| 404 | } | ||
| 426 | 405 | ||
| 427 | // Read/Write data in Switch memory to/from gl_buffer | 406 | // Read/Write data in Switch memory to/from gl_buffer |
| 428 | void LoadGLBuffer(Tegra::GPUVAddr load_start, Tegra::GPUVAddr load_end); | 407 | void LoadGLBuffer(); |
| 429 | void FlushGLBuffer(Tegra::GPUVAddr flush_start, Tegra::GPUVAddr flush_end); | 408 | void FlushGLBuffer(); |
| 430 | 409 | ||
| 431 | // Upload/Download data in gl_buffer in/to this surface's texture | 410 | // Upload/Download data in gl_buffer in/to this surface's texture |
| 432 | void UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle, | 411 | void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); |
| 433 | GLuint draw_fb_handle); | 412 | void DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); |
| 434 | void DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle, | 413 | |
| 435 | GLuint draw_fb_handle); | 414 | private: |
| 415 | OGLTexture texture; | ||
| 416 | std::vector<u8> gl_buffer; | ||
| 417 | SurfaceParams params; | ||
| 436 | }; | 418 | }; |
| 437 | 419 | ||
| 438 | class RasterizerCacheOpenGL : NonCopyable { | 420 | class RasterizerCacheOpenGL final : NonCopyable { |
| 439 | public: | 421 | public: |
| 440 | RasterizerCacheOpenGL(); | 422 | RasterizerCacheOpenGL(); |
| 441 | ~RasterizerCacheOpenGL(); | 423 | ~RasterizerCacheOpenGL(); |
| 442 | 424 | ||
| 443 | /// Blit one surface's texture to another | ||
| 444 | bool BlitSurfaces(const Surface& src_surface, const MathUtil::Rectangle<u32>& src_rect, | ||
| 445 | const Surface& dst_surface, const MathUtil::Rectangle<u32>& dst_rect); | ||
| 446 | |||
| 447 | void ConvertD24S8toABGR(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, | ||
| 448 | GLuint dst_tex, const MathUtil::Rectangle<u32>& dst_rect); | ||
| 449 | |||
| 450 | /// Copy one surface's region to another | ||
| 451 | void CopySurface(const Surface& src_surface, const Surface& dst_surface, | ||
| 452 | SurfaceInterval copy_interval); | ||
| 453 | |||
| 454 | /// Load a texture from Switch memory to OpenGL and cache it (if not already cached) | ||
| 455 | Surface GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale, | ||
| 456 | bool load_if_create); | ||
| 457 | |||
| 458 | /// Tries to find a framebuffer GPU address based on the provided CPU address | ||
| 459 | boost::optional<Tegra::GPUVAddr> TryFindFramebufferGpuAddress(VAddr cpu_addr) const; | ||
| 460 | |||
| 461 | /// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from | ||
| 462 | /// Switch memory to OpenGL and caches it (if not already cached) | ||
| 463 | SurfaceRect_Tuple GetSurfaceSubRect(const SurfaceParams& params, ScaleMatch match_res_scale, | ||
| 464 | bool load_if_create); | ||
| 465 | |||
| 466 | /// Get a surface based on the texture configuration | 425 | /// Get a surface based on the texture configuration |
| 467 | Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); | 426 | Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); |
| 468 | 427 | ||
| @@ -470,29 +429,21 @@ public: | |||
| 470 | SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, | 429 | SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, |
| 471 | const MathUtil::Rectangle<s32>& viewport); | 430 | const MathUtil::Rectangle<s32>& viewport); |
| 472 | 431 | ||
| 473 | /// Get a surface that matches the fill config | 432 | /// Marks the specified surface as "dirty", in that it is out of sync with Switch memory |
| 474 | Surface GetFillSurface(const void* config); | 433 | void MarkSurfaceAsDirty(const Surface& surface); |
| 475 | 434 | ||
| 476 | /// Get a surface that matches a "texture copy" display transfer config | 435 | /// Tries to find a framebuffer GPU address based on the provided CPU address |
| 477 | SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params); | 436 | Surface TryFindFramebufferSurface(VAddr cpu_addr) const; |
| 478 | 437 | ||
| 479 | /// Write any cached resources overlapping the region back to memory (if dirty) | 438 | /// Write any cached resources overlapping the region back to memory (if dirty) |
| 480 | void FlushRegion(Tegra::GPUVAddr addr, u64 size, Surface flush_surface = nullptr); | 439 | void FlushRegion(Tegra::GPUVAddr addr, size_t size); |
| 481 | |||
| 482 | /// Mark region as being invalidated by region_owner (nullptr if Switch memory) | ||
| 483 | void InvalidateRegion(Tegra::GPUVAddr addr, u64 size, const Surface& region_owner); | ||
| 484 | 440 | ||
| 485 | /// Flush all cached resources tracked by this cache manager | 441 | /// Mark the specified region as being invalidated |
| 486 | void FlushAll(); | 442 | void InvalidateRegion(Tegra::GPUVAddr addr, size_t size); |
| 487 | 443 | ||
| 488 | private: | 444 | private: |
| 489 | void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface); | 445 | void LoadSurface(const Surface& surface); |
| 490 | 446 | Surface GetSurface(const SurfaceParams& params); | |
| 491 | /// Update surface's texture for given region when necessary | ||
| 492 | void ValidateSurface(const Surface& surface, Tegra::GPUVAddr addr, u64 size); | ||
| 493 | |||
| 494 | /// Create a new surface | ||
| 495 | Surface CreateSurface(const SurfaceParams& params); | ||
| 496 | 447 | ||
| 497 | /// Register surface into the cache | 448 | /// Register surface into the cache |
| 498 | void RegisterSurface(const Surface& surface); | 449 | void RegisterSurface(const Surface& surface); |
| @@ -503,18 +454,9 @@ private: | |||
| 503 | /// Increase/decrease the number of surface in pages touching the specified region | 454 | /// Increase/decrease the number of surface in pages touching the specified region |
| 504 | void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta); | 455 | void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta); |
| 505 | 456 | ||
| 506 | SurfaceCache surface_cache; | 457 | std::unordered_map<SurfaceKey, Surface> surface_cache; |
| 507 | PageMap cached_pages; | 458 | PageMap cached_pages; |
| 508 | SurfaceMap dirty_regions; | ||
| 509 | SurfaceSet remove_surfaces; | ||
| 510 | 459 | ||
| 511 | OGLFramebuffer read_framebuffer; | 460 | OGLFramebuffer read_framebuffer; |
| 512 | OGLFramebuffer draw_framebuffer; | 461 | OGLFramebuffer draw_framebuffer; |
| 513 | |||
| 514 | OGLVertexArray attributeless_vao; | ||
| 515 | OGLBuffer d24s8_abgr_buffer; | ||
| 516 | GLsizeiptr d24s8_abgr_buffer_size; | ||
| 517 | OGLProgram d24s8_abgr_shader; | ||
| 518 | GLint d24s8_abgr_tbo_size_u_id; | ||
| 519 | GLint d24s8_abgr_viewport_u_id; | ||
| 520 | }; | 462 | }; |
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 93f9172e7..0fed93ca5 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h | |||
| @@ -38,7 +38,7 @@ public: | |||
| 38 | if (handle == 0) | 38 | if (handle == 0) |
| 39 | return; | 39 | return; |
| 40 | glDeleteTextures(1, &handle); | 40 | glDeleteTextures(1, &handle); |
| 41 | OpenGLState::GetCurState().ResetTexture(handle).Apply(); | 41 | OpenGLState::GetCurState().UnbindTexture(handle).Apply(); |
| 42 | handle = 0; | 42 | handle = 0; |
| 43 | } | 43 | } |
| 44 | 44 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 67726e7c6..5914077e8 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/assert.h" | 9 | #include "common/assert.h" |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "video_core/engines/shader_bytecode.h" | 11 | #include "video_core/engines/shader_bytecode.h" |
| 12 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 12 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" | 13 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" |
| 13 | 14 | ||
| 14 | namespace GLShader { | 15 | namespace GLShader { |
| @@ -16,6 +17,7 @@ namespace Decompiler { | |||
| 16 | 17 | ||
| 17 | using Tegra::Shader::Attribute; | 18 | using Tegra::Shader::Attribute; |
| 18 | using Tegra::Shader::Instruction; | 19 | using Tegra::Shader::Instruction; |
| 20 | using Tegra::Shader::LogicOperation; | ||
| 19 | using Tegra::Shader::OpCode; | 21 | using Tegra::Shader::OpCode; |
| 20 | using Tegra::Shader::Register; | 22 | using Tegra::Shader::Register; |
| 21 | using Tegra::Shader::Sampler; | 23 | using Tegra::Shader::Sampler; |
| @@ -266,6 +268,27 @@ public: | |||
| 266 | } | 268 | } |
| 267 | 269 | ||
| 268 | /** | 270 | /** |
| 271 | * Returns code that does an integer size conversion for the specified size. | ||
| 272 | * @param value Value to perform integer size conversion on. | ||
| 273 | * @param size Register size to use for conversion instructions. | ||
| 274 | * @returns GLSL string corresponding to the value converted to the specified size. | ||
| 275 | */ | ||
| 276 | static std::string ConvertIntegerSize(const std::string& value, Register::Size size) { | ||
| 277 | switch (size) { | ||
| 278 | case Register::Size::Byte: | ||
| 279 | return "((" + value + " << 24) >> 24)"; | ||
| 280 | case Register::Size::Short: | ||
| 281 | return "((" + value + " << 16) >> 16)"; | ||
| 282 | case Register::Size::Word: | ||
| 283 | // Default - do nothing | ||
| 284 | return value; | ||
| 285 | default: | ||
| 286 | LOG_CRITICAL(HW_GPU, "Unimplemented conversion size {}", static_cast<u32>(size)); | ||
| 287 | UNREACHABLE(); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | /** | ||
| 269 | * Gets a register as an float. | 292 | * Gets a register as an float. |
| 270 | * @param reg The register to get. | 293 | * @param reg The register to get. |
| 271 | * @param elem The element to use for the operation. | 294 | * @param elem The element to use for the operation. |
| @@ -281,15 +304,18 @@ public: | |||
| 281 | * @param reg The register to get. | 304 | * @param reg The register to get. |
| 282 | * @param elem The element to use for the operation. | 305 | * @param elem The element to use for the operation. |
| 283 | * @param is_signed Whether to get the register as a signed (or unsigned) integer. | 306 | * @param is_signed Whether to get the register as a signed (or unsigned) integer. |
| 307 | * @param size Register size to use for conversion instructions. | ||
| 284 | * @returns GLSL string corresponding to the register as an integer. | 308 | * @returns GLSL string corresponding to the register as an integer. |
| 285 | */ | 309 | */ |
| 286 | std::string GetRegisterAsInteger(const Register& reg, unsigned elem = 0, | 310 | std::string GetRegisterAsInteger(const Register& reg, unsigned elem = 0, bool is_signed = true, |
| 287 | bool is_signed = true) { | 311 | Register::Size size = Register::Size::Word) { |
| 288 | const std::string func = GetGLSLConversionFunc( | 312 | const std::string func = GetGLSLConversionFunc( |
| 289 | GLSLRegister::Type::Float, | 313 | GLSLRegister::Type::Float, |
| 290 | is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger); | 314 | is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger); |
| 291 | 315 | ||
| 292 | return func + '(' + GetRegister(reg, elem) + ')'; | 316 | std::string value = func + '(' + GetRegister(reg, elem) + ')'; |
| 317 | |||
| 318 | return ConvertIntegerSize(value, size); | ||
| 293 | } | 319 | } |
| 294 | 320 | ||
| 295 | /** | 321 | /** |
| @@ -299,13 +325,15 @@ public: | |||
| 299 | * @param value The code representing the value to assign. | 325 | * @param value The code representing the value to assign. |
| 300 | * @param dest_num_components Number of components in the destination. | 326 | * @param dest_num_components Number of components in the destination. |
| 301 | * @param value_num_components Number of components in the value. | 327 | * @param value_num_components Number of components in the value. |
| 302 | * @param is_abs Optional, when True, applies absolute value to output. | 328 | * @param is_saturated Optional, when True, saturates the provided value. |
| 303 | * @param dest_elem Optional, the destination element to use for the operation. | 329 | * @param dest_elem Optional, the destination element to use for the operation. |
| 304 | */ | 330 | */ |
| 305 | void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value, | 331 | void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value, |
| 306 | u64 dest_num_components, u64 value_num_components, bool is_abs = false, | 332 | u64 dest_num_components, u64 value_num_components, |
| 307 | u64 dest_elem = 0) { | 333 | bool is_saturated = false, u64 dest_elem = 0) { |
| 308 | SetRegister(reg, elem, value, dest_num_components, value_num_components, is_abs, dest_elem); | 334 | |
| 335 | SetRegister(reg, elem, is_saturated ? "clamp(" + value + ", 0.0, 1.0)" : value, | ||
| 336 | dest_num_components, value_num_components, dest_elem); | ||
| 309 | } | 337 | } |
| 310 | 338 | ||
| 311 | /** | 339 | /** |
| @@ -315,18 +343,22 @@ public: | |||
| 315 | * @param value The code representing the value to assign. | 343 | * @param value The code representing the value to assign. |
| 316 | * @param dest_num_components Number of components in the destination. | 344 | * @param dest_num_components Number of components in the destination. |
| 317 | * @param value_num_components Number of components in the value. | 345 | * @param value_num_components Number of components in the value. |
| 318 | * @param is_abs Optional, when True, applies absolute value to output. | 346 | * @param is_saturated Optional, when True, saturates the provided value. |
| 319 | * @param dest_elem Optional, the destination element to use for the operation. | 347 | * @param dest_elem Optional, the destination element to use for the operation. |
| 348 | * @param size Register size to use for conversion instructions. | ||
| 320 | */ | 349 | */ |
| 321 | void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, | 350 | void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, |
| 322 | const std::string& value, u64 dest_num_components, | 351 | const std::string& value, u64 dest_num_components, |
| 323 | u64 value_num_components, bool is_abs = false, u64 dest_elem = 0) { | 352 | u64 value_num_components, bool is_saturated = false, |
| 353 | u64 dest_elem = 0, Register::Size size = Register::Size::Word) { | ||
| 354 | ASSERT_MSG(!is_saturated, "Unimplemented"); | ||
| 355 | |||
| 324 | const std::string func = GetGLSLConversionFunc( | 356 | const std::string func = GetGLSLConversionFunc( |
| 325 | is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger, | 357 | is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger, |
| 326 | GLSLRegister::Type::Float); | 358 | GLSLRegister::Type::Float); |
| 327 | 359 | ||
| 328 | SetRegister(reg, elem, func + '(' + value + ')', dest_num_components, value_num_components, | 360 | SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')', |
| 329 | is_abs, dest_elem); | 361 | dest_num_components, value_num_components, dest_elem); |
| 330 | } | 362 | } |
| 331 | 363 | ||
| 332 | /** | 364 | /** |
| @@ -366,7 +398,8 @@ public: | |||
| 366 | /// Generates code representing a uniform (C buffer) register, interpreted as the input type. | 398 | /// Generates code representing a uniform (C buffer) register, interpreted as the input type. |
| 367 | std::string GetUniform(u64 index, u64 offset, GLSLRegister::Type type) { | 399 | std::string GetUniform(u64 index, u64 offset, GLSLRegister::Type type) { |
| 368 | declr_const_buffers[index].MarkAsUsed(index, offset, stage); | 400 | declr_const_buffers[index].MarkAsUsed(index, offset, stage); |
| 369 | std::string value = 'c' + std::to_string(index) + '[' + std::to_string(offset) + ']'; | 401 | std::string value = 'c' + std::to_string(index) + '[' + std::to_string(offset / 4) + "][" + |
| 402 | std::to_string(offset % 4) + ']'; | ||
| 370 | 403 | ||
| 371 | if (type == GLSLRegister::Type::Float) { | 404 | if (type == GLSLRegister::Type::Float) { |
| 372 | return value; | 405 | return value; |
| @@ -380,8 +413,12 @@ public: | |||
| 380 | std::string GetUniformIndirect(u64 index, s64 offset, const Register& index_reg, | 413 | std::string GetUniformIndirect(u64 index, s64 offset, const Register& index_reg, |
| 381 | GLSLRegister::Type type) { | 414 | GLSLRegister::Type type) { |
| 382 | declr_const_buffers[index].MarkAsUsedIndirect(index, stage); | 415 | declr_const_buffers[index].MarkAsUsedIndirect(index, stage); |
| 383 | std::string value = 'c' + std::to_string(index) + "[(floatBitsToInt(" + | 416 | |
| 384 | GetRegister(index_reg, 0) + ") + " + std::to_string(offset) + ") / 4]"; | 417 | std::string final_offset = "((floatBitsToInt(" + GetRegister(index_reg, 0) + ") + " + |
| 418 | std::to_string(offset) + ") / 4)"; | ||
| 419 | |||
| 420 | std::string value = | ||
| 421 | 'c' + std::to_string(index) + '[' + final_offset + " / 4][" + final_offset + " % 4]"; | ||
| 385 | 422 | ||
| 386 | if (type == GLSLRegister::Type::Float) { | 423 | if (type == GLSLRegister::Type::Float) { |
| 387 | return value; | 424 | return value; |
| @@ -423,9 +460,10 @@ public: | |||
| 423 | 460 | ||
| 424 | unsigned const_buffer_layout = 0; | 461 | unsigned const_buffer_layout = 0; |
| 425 | for (const auto& entry : GetConstBuffersDeclarations()) { | 462 | for (const auto& entry : GetConstBuffersDeclarations()) { |
| 426 | declarations.AddLine("layout(std430) buffer " + entry.GetName()); | 463 | declarations.AddLine("layout(std140) uniform " + entry.GetName()); |
| 427 | declarations.AddLine('{'); | 464 | declarations.AddLine('{'); |
| 428 | declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];"); | 465 | declarations.AddLine(" vec4 c" + std::to_string(entry.GetIndex()) + |
| 466 | "[MAX_CONSTBUFFER_ELEMENTS];"); | ||
| 429 | declarations.AddLine("};"); | 467 | declarations.AddLine("};"); |
| 430 | declarations.AddNewLine(); | 468 | declarations.AddNewLine(); |
| 431 | ++const_buffer_layout; | 469 | ++const_buffer_layout; |
| @@ -500,13 +538,11 @@ private: | |||
| 500 | * @param value The code representing the value to assign. | 538 | * @param value The code representing the value to assign. |
| 501 | * @param dest_num_components Number of components in the destination. | 539 | * @param dest_num_components Number of components in the destination. |
| 502 | * @param value_num_components Number of components in the value. | 540 | * @param value_num_components Number of components in the value. |
| 503 | * @param is_abs Optional, when True, applies absolute value to output. | ||
| 504 | * @param dest_elem Optional, the destination element to use for the operation. | 541 | * @param dest_elem Optional, the destination element to use for the operation. |
| 505 | */ | 542 | */ |
| 506 | void SetRegister(const Register& reg, u64 elem, const std::string& value, | 543 | void SetRegister(const Register& reg, u64 elem, const std::string& value, |
| 507 | u64 dest_num_components, u64 value_num_components, bool is_abs, | 544 | u64 dest_num_components, u64 value_num_components, u64 dest_elem) { |
| 508 | u64 dest_elem) { | 545 | std::string dest = GetRegister(reg, static_cast<u32>(dest_elem)); |
| 509 | std::string dest = GetRegister(reg, dest_elem); | ||
| 510 | if (dest_num_components > 1) { | 546 | if (dest_num_components > 1) { |
| 511 | dest += GetSwizzle(elem); | 547 | dest += GetSwizzle(elem); |
| 512 | } | 548 | } |
| @@ -516,8 +552,6 @@ private: | |||
| 516 | src += GetSwizzle(elem); | 552 | src += GetSwizzle(elem); |
| 517 | } | 553 | } |
| 518 | 554 | ||
| 519 | src = is_abs ? "abs(" + src + ')' : src; | ||
| 520 | |||
| 521 | shader.AddLine(dest + " = " + src + ';'); | 555 | shader.AddLine(dest + " = " + src + ';'); |
| 522 | } | 556 | } |
| 523 | 557 | ||
| @@ -547,7 +581,7 @@ private: | |||
| 547 | return "input_attribute_" + std::to_string(index); | 581 | return "input_attribute_" + std::to_string(index); |
| 548 | } | 582 | } |
| 549 | 583 | ||
| 550 | NGLOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index); | 584 | LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index); |
| 551 | UNREACHABLE(); | 585 | UNREACHABLE(); |
| 552 | } | 586 | } |
| 553 | } | 587 | } |
| @@ -565,7 +599,7 @@ private: | |||
| 565 | return "output_attribute_" + std::to_string(index); | 599 | return "output_attribute_" + std::to_string(index); |
| 566 | } | 600 | } |
| 567 | 601 | ||
| 568 | NGLOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index); | 602 | LOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index); |
| 569 | UNREACHABLE(); | 603 | UNREACHABLE(); |
| 570 | } | 604 | } |
| 571 | } | 605 | } |
| @@ -685,21 +719,31 @@ private: | |||
| 685 | /** | 719 | /** |
| 686 | * Returns the comparison string to use to compare two values in the 'set' family of | 720 | * Returns the comparison string to use to compare two values in the 'set' family of |
| 687 | * instructions. | 721 | * instructions. |
| 688 | * @params condition The condition used in the 'set'-family instruction. | 722 | * @param condition The condition used in the 'set'-family instruction. |
| 723 | * @param op_a First operand to use for the comparison. | ||
| 724 | * @param op_b Second operand to use for the comparison. | ||
| 689 | * @returns String corresponding to the GLSL operator that matches the desired comparison. | 725 | * @returns String corresponding to the GLSL operator that matches the desired comparison. |
| 690 | */ | 726 | */ |
| 691 | std::string GetPredicateComparison(Tegra::Shader::PredCondition condition) const { | 727 | std::string GetPredicateComparison(Tegra::Shader::PredCondition condition, |
| 728 | const std::string& op_a, const std::string& op_b) const { | ||
| 692 | using Tegra::Shader::PredCondition; | 729 | using Tegra::Shader::PredCondition; |
| 693 | static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = { | 730 | static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = { |
| 694 | {PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="}, | 731 | {PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="}, |
| 695 | {PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"}, | 732 | {PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"}, |
| 696 | {PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="}, | 733 | {PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="}, |
| 734 | {PredCondition::NotEqualWithNan, "!="}, | ||
| 697 | }; | 735 | }; |
| 698 | 736 | ||
| 699 | auto comparison = PredicateComparisonStrings.find(condition); | 737 | const auto& comparison{PredicateComparisonStrings.find(condition)}; |
| 700 | ASSERT_MSG(comparison != PredicateComparisonStrings.end(), | 738 | ASSERT_MSG(comparison != PredicateComparisonStrings.end(), |
| 701 | "Unknown predicate comparison operation"); | 739 | "Unknown predicate comparison operation"); |
| 702 | return comparison->second; | 740 | |
| 741 | std::string predicate{'(' + op_a + ") " + comparison->second + " (" + op_b + ')'}; | ||
| 742 | if (condition == PredCondition::NotEqualWithNan) { | ||
| 743 | predicate += " || isnan(" + op_a + ") || isnan(" + op_b + ')'; | ||
| 744 | } | ||
| 745 | |||
| 746 | return predicate; | ||
| 703 | } | 747 | } |
| 704 | 748 | ||
| 705 | /** | 749 | /** |
| @@ -733,6 +777,31 @@ private: | |||
| 733 | return (absolute_offset % SchedPeriod) == 0; | 777 | return (absolute_offset % SchedPeriod) == 0; |
| 734 | } | 778 | } |
| 735 | 779 | ||
| 780 | void WriteLogicOperation(Register dest, LogicOperation logic_op, const std::string& op_a, | ||
| 781 | const std::string& op_b) { | ||
| 782 | switch (logic_op) { | ||
| 783 | case LogicOperation::And: { | ||
| 784 | regs.SetRegisterToInteger(dest, true, 0, '(' + op_a + " & " + op_b + ')', 1, 1); | ||
| 785 | break; | ||
| 786 | } | ||
| 787 | case LogicOperation::Or: { | ||
| 788 | regs.SetRegisterToInteger(dest, true, 0, '(' + op_a + " | " + op_b + ')', 1, 1); | ||
| 789 | break; | ||
| 790 | } | ||
| 791 | case LogicOperation::Xor: { | ||
| 792 | regs.SetRegisterToInteger(dest, true, 0, '(' + op_a + " ^ " + op_b + ')', 1, 1); | ||
| 793 | break; | ||
| 794 | } | ||
| 795 | case LogicOperation::PassB: { | ||
| 796 | regs.SetRegisterToInteger(dest, true, 0, op_b, 1, 1); | ||
| 797 | break; | ||
| 798 | } | ||
| 799 | default: | ||
| 800 | LOG_CRITICAL(HW_GPU, "Unimplemented logic operation: {}", static_cast<u32>(logic_op)); | ||
| 801 | UNREACHABLE(); | ||
| 802 | } | ||
| 803 | } | ||
| 804 | |||
| 736 | /** | 805 | /** |
| 737 | * Compiles a single instruction from Tegra to GLSL. | 806 | * Compiles a single instruction from Tegra to GLSL. |
| 738 | * @param offset the offset of the Tegra shader instruction. | 807 | * @param offset the offset of the Tegra shader instruction. |
| @@ -750,8 +819,9 @@ private: | |||
| 750 | 819 | ||
| 751 | // Decoding failure | 820 | // Decoding failure |
| 752 | if (!opcode) { | 821 | if (!opcode) { |
| 753 | NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {0:x}", instr.value); | 822 | LOG_CRITICAL(HW_GPU, "Unhandled instruction: {0:x}", instr.value); |
| 754 | UNREACHABLE(); | 823 | UNREACHABLE(); |
| 824 | return offset + 1; | ||
| 755 | } | 825 | } |
| 756 | 826 | ||
| 757 | shader.AddLine("// " + std::to_string(offset) + ": " + opcode->GetName()); | 827 | shader.AddLine("// " + std::to_string(offset) + ": " + opcode->GetName()); |
| @@ -770,22 +840,25 @@ private: | |||
| 770 | 840 | ||
| 771 | switch (opcode->GetType()) { | 841 | switch (opcode->GetType()) { |
| 772 | case OpCode::Type::Arithmetic: { | 842 | case OpCode::Type::Arithmetic: { |
| 773 | std::string op_a = instr.alu.negate_a ? "-" : ""; | 843 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 774 | op_a += regs.GetRegisterAsFloat(instr.gpr8); | ||
| 775 | if (instr.alu.abs_a) { | 844 | if (instr.alu.abs_a) { |
| 776 | op_a = "abs(" + op_a + ')'; | 845 | op_a = "abs(" + op_a + ')'; |
| 777 | } | 846 | } |
| 778 | 847 | ||
| 779 | std::string op_b = instr.alu.negate_b ? "-" : ""; | 848 | if (instr.alu.negate_a) { |
| 849 | op_a = "-(" + op_a + ')'; | ||
| 850 | } | ||
| 851 | |||
| 852 | std::string op_b; | ||
| 780 | 853 | ||
| 781 | if (instr.is_b_imm) { | 854 | if (instr.is_b_imm) { |
| 782 | op_b += GetImmediate19(instr); | 855 | op_b = GetImmediate19(instr); |
| 783 | } else { | 856 | } else { |
| 784 | if (instr.is_b_gpr) { | 857 | if (instr.is_b_gpr) { |
| 785 | op_b += regs.GetRegisterAsFloat(instr.gpr20); | 858 | op_b = regs.GetRegisterAsFloat(instr.gpr20); |
| 786 | } else { | 859 | } else { |
| 787 | op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, | 860 | op_b = regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, |
| 788 | GLSLRegister::Type::Float); | 861 | GLSLRegister::Type::Float); |
| 789 | } | 862 | } |
| 790 | } | 863 | } |
| 791 | 864 | ||
| @@ -793,6 +866,10 @@ private: | |||
| 793 | op_b = "abs(" + op_b + ')'; | 866 | op_b = "abs(" + op_b + ')'; |
| 794 | } | 867 | } |
| 795 | 868 | ||
| 869 | if (instr.alu.negate_b) { | ||
| 870 | op_b = "-(" + op_b + ')'; | ||
| 871 | } | ||
| 872 | |||
| 796 | switch (opcode->GetId()) { | 873 | switch (opcode->GetId()) { |
| 797 | case OpCode::Id::MOV_C: | 874 | case OpCode::Id::MOV_C: |
| 798 | case OpCode::Id::MOV_R: { | 875 | case OpCode::Id::MOV_R: { |
| @@ -800,68 +877,53 @@ private: | |||
| 800 | break; | 877 | break; |
| 801 | } | 878 | } |
| 802 | 879 | ||
| 803 | case OpCode::Id::MOV32_IMM: { | ||
| 804 | // mov32i doesn't have abs or neg bits. | ||
| 805 | regs.SetRegisterToFloat(instr.gpr0, 0, GetImmediate32(instr), 1, 1); | ||
| 806 | break; | ||
| 807 | } | ||
| 808 | case OpCode::Id::FMUL_C: | 880 | case OpCode::Id::FMUL_C: |
| 809 | case OpCode::Id::FMUL_R: | 881 | case OpCode::Id::FMUL_R: |
| 810 | case OpCode::Id::FMUL_IMM: { | 882 | case OpCode::Id::FMUL_IMM: { |
| 811 | ASSERT_MSG(!instr.saturate_a, "Unimplemented"); | 883 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, |
| 812 | 884 | instr.alu.saturate_d); | |
| 813 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, instr.alu.abs_d); | ||
| 814 | break; | ||
| 815 | } | ||
| 816 | case OpCode::Id::FMUL32_IMM: { | ||
| 817 | // fmul32i doesn't have abs or neg bits. | ||
| 818 | regs.SetRegisterToFloat( | ||
| 819 | instr.gpr0, 0, | ||
| 820 | regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1); | ||
| 821 | break; | 885 | break; |
| 822 | } | 886 | } |
| 823 | case OpCode::Id::FADD_C: | 887 | case OpCode::Id::FADD_C: |
| 824 | case OpCode::Id::FADD_R: | 888 | case OpCode::Id::FADD_R: |
| 825 | case OpCode::Id::FADD_IMM: { | 889 | case OpCode::Id::FADD_IMM: { |
| 826 | ASSERT_MSG(!instr.saturate_a, "Unimplemented"); | 890 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, |
| 827 | 891 | instr.alu.saturate_d); | |
| 828 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, instr.alu.abs_d); | ||
| 829 | break; | 892 | break; |
| 830 | } | 893 | } |
| 831 | case OpCode::Id::MUFU: { | 894 | case OpCode::Id::MUFU: { |
| 832 | ASSERT_MSG(!instr.saturate_a, "Unimplemented"); | ||
| 833 | |||
| 834 | switch (instr.sub_op) { | 895 | switch (instr.sub_op) { |
| 835 | case SubOp::Cos: | 896 | case SubOp::Cos: |
| 836 | regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1, | 897 | regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1, |
| 837 | instr.alu.abs_d); | 898 | instr.alu.saturate_d); |
| 838 | break; | 899 | break; |
| 839 | case SubOp::Sin: | 900 | case SubOp::Sin: |
| 840 | regs.SetRegisterToFloat(instr.gpr0, 0, "sin(" + op_a + ')', 1, 1, | 901 | regs.SetRegisterToFloat(instr.gpr0, 0, "sin(" + op_a + ')', 1, 1, |
| 841 | instr.alu.abs_d); | 902 | instr.alu.saturate_d); |
| 842 | break; | 903 | break; |
| 843 | case SubOp::Ex2: | 904 | case SubOp::Ex2: |
| 844 | regs.SetRegisterToFloat(instr.gpr0, 0, "exp2(" + op_a + ')', 1, 1, | 905 | regs.SetRegisterToFloat(instr.gpr0, 0, "exp2(" + op_a + ')', 1, 1, |
| 845 | instr.alu.abs_d); | 906 | instr.alu.saturate_d); |
| 846 | break; | 907 | break; |
| 847 | case SubOp::Lg2: | 908 | case SubOp::Lg2: |
| 848 | regs.SetRegisterToFloat(instr.gpr0, 0, "log2(" + op_a + ')', 1, 1, | 909 | regs.SetRegisterToFloat(instr.gpr0, 0, "log2(" + op_a + ')', 1, 1, |
| 849 | instr.alu.abs_d); | 910 | instr.alu.saturate_d); |
| 850 | break; | 911 | break; |
| 851 | case SubOp::Rcp: | 912 | case SubOp::Rcp: |
| 852 | regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1, instr.alu.abs_d); | 913 | regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1, |
| 914 | instr.alu.saturate_d); | ||
| 853 | break; | 915 | break; |
| 854 | case SubOp::Rsq: | 916 | case SubOp::Rsq: |
| 855 | regs.SetRegisterToFloat(instr.gpr0, 0, "inversesqrt(" + op_a + ')', 1, 1, | 917 | regs.SetRegisterToFloat(instr.gpr0, 0, "inversesqrt(" + op_a + ')', 1, 1, |
| 856 | instr.alu.abs_d); | 918 | instr.alu.saturate_d); |
| 857 | break; | 919 | break; |
| 858 | case SubOp::Min: | 920 | case SubOp::Sqrt: |
| 859 | regs.SetRegisterToFloat(instr.gpr0, 0, "min(" + op_a + "," + op_b + ')', 1, 1, | 921 | regs.SetRegisterToFloat(instr.gpr0, 0, "sqrt(" + op_a + ')', 1, 1, |
| 860 | instr.alu.abs_d); | 922 | instr.alu.saturate_d); |
| 861 | break; | 923 | break; |
| 862 | default: | 924 | default: |
| 863 | NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}", | 925 | LOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}", |
| 864 | static_cast<unsigned>(instr.sub_op.Value())); | 926 | static_cast<unsigned>(instr.sub_op.Value())); |
| 865 | UNREACHABLE(); | 927 | UNREACHABLE(); |
| 866 | } | 928 | } |
| 867 | break; | 929 | break; |
| @@ -884,16 +946,31 @@ private: | |||
| 884 | // Currently RRO is only implemented as a register move. | 946 | // Currently RRO is only implemented as a register move. |
| 885 | // Usage of `abs_b` and `negate_b` here should also be correct. | 947 | // Usage of `abs_b` and `negate_b` here should also be correct. |
| 886 | regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1); | 948 | regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1); |
| 887 | NGLOG_WARNING(HW_GPU, "RRO instruction is incomplete"); | 949 | LOG_WARNING(HW_GPU, "RRO instruction is incomplete"); |
| 888 | break; | 950 | break; |
| 889 | } | 951 | } |
| 890 | default: { | 952 | default: { |
| 891 | NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {}", opcode->GetName()); | 953 | LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {}", opcode->GetName()); |
| 892 | UNREACHABLE(); | 954 | UNREACHABLE(); |
| 893 | } | 955 | } |
| 894 | } | 956 | } |
| 895 | break; | 957 | break; |
| 896 | } | 958 | } |
| 959 | case OpCode::Type::ArithmeticImmediate: { | ||
| 960 | switch (opcode->GetId()) { | ||
| 961 | case OpCode::Id::MOV32_IMM: { | ||
| 962 | regs.SetRegisterToFloat(instr.gpr0, 0, GetImmediate32(instr), 1, 1); | ||
| 963 | break; | ||
| 964 | } | ||
| 965 | case OpCode::Id::FMUL32_IMM: { | ||
| 966 | regs.SetRegisterToFloat( | ||
| 967 | instr.gpr0, 0, | ||
| 968 | regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1); | ||
| 969 | break; | ||
| 970 | } | ||
| 971 | } | ||
| 972 | break; | ||
| 973 | } | ||
| 897 | case OpCode::Type::Bfe: { | 974 | case OpCode::Type::Bfe: { |
| 898 | ASSERT_MSG(!instr.bfe.negate_b, "Unimplemented"); | 975 | ASSERT_MSG(!instr.bfe.negate_b, "Unimplemented"); |
| 899 | 976 | ||
| @@ -912,56 +989,13 @@ private: | |||
| 912 | break; | 989 | break; |
| 913 | } | 990 | } |
| 914 | default: { | 991 | default: { |
| 915 | NGLOG_CRITICAL(HW_GPU, "Unhandled BFE instruction: {}", opcode->GetName()); | 992 | LOG_CRITICAL(HW_GPU, "Unhandled BFE instruction: {}", opcode->GetName()); |
| 916 | UNREACHABLE(); | 993 | UNREACHABLE(); |
| 917 | } | 994 | } |
| 918 | } | 995 | } |
| 919 | 996 | ||
| 920 | break; | 997 | break; |
| 921 | } | 998 | } |
| 922 | case OpCode::Type::Logic: { | ||
| 923 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true); | ||
| 924 | |||
| 925 | if (instr.alu.lop.invert_a) | ||
| 926 | op_a = "~(" + op_a + ')'; | ||
| 927 | |||
| 928 | switch (opcode->GetId()) { | ||
| 929 | case OpCode::Id::LOP32I: { | ||
| 930 | u32 imm = static_cast<u32>(instr.alu.imm20_32.Value()); | ||
| 931 | |||
| 932 | if (instr.alu.lop.invert_b) | ||
| 933 | imm = ~imm; | ||
| 934 | |||
| 935 | switch (instr.alu.lop.operation) { | ||
| 936 | case Tegra::Shader::LogicOperation::And: { | ||
| 937 | regs.SetRegisterToInteger(instr.gpr0, true, 0, | ||
| 938 | '(' + op_a + " & " + std::to_string(imm) + ')', 1, 1); | ||
| 939 | break; | ||
| 940 | } | ||
| 941 | case Tegra::Shader::LogicOperation::Or: { | ||
| 942 | regs.SetRegisterToInteger(instr.gpr0, true, 0, | ||
| 943 | '(' + op_a + " | " + std::to_string(imm) + ')', 1, 1); | ||
| 944 | break; | ||
| 945 | } | ||
| 946 | case Tegra::Shader::LogicOperation::Xor: { | ||
| 947 | regs.SetRegisterToInteger(instr.gpr0, true, 0, | ||
| 948 | '(' + op_a + " ^ " + std::to_string(imm) + ')', 1, 1); | ||
| 949 | break; | ||
| 950 | } | ||
| 951 | default: | ||
| 952 | NGLOG_CRITICAL(HW_GPU, "Unimplemented lop32i operation: {}", | ||
| 953 | static_cast<u32>(instr.alu.lop.operation.Value())); | ||
| 954 | UNREACHABLE(); | ||
| 955 | } | ||
| 956 | break; | ||
| 957 | } | ||
| 958 | default: { | ||
| 959 | NGLOG_CRITICAL(HW_GPU, "Unhandled logic instruction: {}", opcode->GetName()); | ||
| 960 | UNREACHABLE(); | ||
| 961 | } | ||
| 962 | } | ||
| 963 | break; | ||
| 964 | } | ||
| 965 | 999 | ||
| 966 | case OpCode::Type::Shift: { | 1000 | case OpCode::Type::Shift: { |
| 967 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true); | 1001 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true); |
| @@ -998,21 +1032,46 @@ private: | |||
| 998 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); | 1032 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); |
| 999 | break; | 1033 | break; |
| 1000 | default: { | 1034 | default: { |
| 1001 | NGLOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->GetName()); | 1035 | LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->GetName()); |
| 1002 | UNREACHABLE(); | 1036 | UNREACHABLE(); |
| 1003 | } | 1037 | } |
| 1004 | } | 1038 | } |
| 1005 | break; | 1039 | break; |
| 1006 | } | 1040 | } |
| 1007 | 1041 | ||
| 1008 | case OpCode::Type::ArithmeticInteger: { | 1042 | case OpCode::Type::ArithmeticIntegerImmediate: { |
| 1009 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); | 1043 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); |
| 1044 | std::string op_b = std::to_string(instr.alu.imm20_32.Value()); | ||
| 1010 | 1045 | ||
| 1011 | if (instr.alu_integer.negate_a) | 1046 | switch (opcode->GetId()) { |
| 1012 | op_a = '-' + op_a; | 1047 | case OpCode::Id::IADD32I: |
| 1048 | if (instr.iadd32i.negate_a) | ||
| 1049 | op_a = "-(" + op_a + ')'; | ||
| 1013 | 1050 | ||
| 1014 | std::string op_b = instr.alu_integer.negate_b ? "-" : ""; | 1051 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, |
| 1052 | instr.iadd32i.saturate != 0); | ||
| 1053 | break; | ||
| 1054 | case OpCode::Id::LOP32I: { | ||
| 1055 | if (instr.alu.lop32i.invert_a) | ||
| 1056 | op_a = "~(" + op_a + ')'; | ||
| 1015 | 1057 | ||
| 1058 | if (instr.alu.lop32i.invert_b) | ||
| 1059 | op_b = "~(" + op_b + ')'; | ||
| 1060 | |||
| 1061 | WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b); | ||
| 1062 | break; | ||
| 1063 | } | ||
| 1064 | default: { | ||
| 1065 | LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticIntegerImmediate instruction: {}", | ||
| 1066 | opcode->GetName()); | ||
| 1067 | UNREACHABLE(); | ||
| 1068 | } | ||
| 1069 | } | ||
| 1070 | break; | ||
| 1071 | } | ||
| 1072 | case OpCode::Type::ArithmeticInteger: { | ||
| 1073 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 1074 | std::string op_b; | ||
| 1016 | if (instr.is_b_imm) { | 1075 | if (instr.is_b_imm) { |
| 1017 | op_b += '(' + std::to_string(instr.alu.GetSignedImm20_20()) + ')'; | 1076 | op_b += '(' + std::to_string(instr.alu.GetSignedImm20_20()) + ')'; |
| 1018 | } else { | 1077 | } else { |
| @@ -1028,22 +1087,63 @@ private: | |||
| 1028 | case OpCode::Id::IADD_C: | 1087 | case OpCode::Id::IADD_C: |
| 1029 | case OpCode::Id::IADD_R: | 1088 | case OpCode::Id::IADD_R: |
| 1030 | case OpCode::Id::IADD_IMM: { | 1089 | case OpCode::Id::IADD_IMM: { |
| 1031 | ASSERT_MSG(!instr.saturate_a, "Unimplemented"); | 1090 | if (instr.alu_integer.negate_a) |
| 1032 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1); | 1091 | op_a = "-(" + op_a + ')'; |
| 1092 | |||
| 1093 | if (instr.alu_integer.negate_b) | ||
| 1094 | op_b = "-(" + op_b + ')'; | ||
| 1095 | |||
| 1096 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, | ||
| 1097 | instr.alu.saturate_d); | ||
| 1033 | break; | 1098 | break; |
| 1034 | } | 1099 | } |
| 1035 | case OpCode::Id::ISCADD_C: | 1100 | case OpCode::Id::ISCADD_C: |
| 1036 | case OpCode::Id::ISCADD_R: | 1101 | case OpCode::Id::ISCADD_R: |
| 1037 | case OpCode::Id::ISCADD_IMM: { | 1102 | case OpCode::Id::ISCADD_IMM: { |
| 1103 | if (instr.alu_integer.negate_a) | ||
| 1104 | op_a = "-(" + op_a + ')'; | ||
| 1105 | |||
| 1106 | if (instr.alu_integer.negate_b) | ||
| 1107 | op_b = "-(" + op_b + ')'; | ||
| 1108 | |||
| 1038 | std::string shift = std::to_string(instr.alu_integer.shift_amount.Value()); | 1109 | std::string shift = std::to_string(instr.alu_integer.shift_amount.Value()); |
| 1039 | 1110 | ||
| 1040 | regs.SetRegisterToInteger(instr.gpr0, true, 0, | 1111 | regs.SetRegisterToInteger(instr.gpr0, true, 0, |
| 1041 | "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); | 1112 | "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); |
| 1042 | break; | 1113 | break; |
| 1043 | } | 1114 | } |
| 1115 | case OpCode::Id::LOP_C: | ||
| 1116 | case OpCode::Id::LOP_R: | ||
| 1117 | case OpCode::Id::LOP_IMM: { | ||
| 1118 | ASSERT_MSG(!instr.alu.lop.unk44, "Unimplemented"); | ||
| 1119 | ASSERT_MSG(instr.alu.lop.pred48 == Pred::UnusedIndex, "Unimplemented"); | ||
| 1120 | |||
| 1121 | if (instr.alu.lop.invert_a) | ||
| 1122 | op_a = "~(" + op_a + ')'; | ||
| 1123 | |||
| 1124 | if (instr.alu.lop.invert_b) | ||
| 1125 | op_b = "~(" + op_b + ')'; | ||
| 1126 | |||
| 1127 | WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b); | ||
| 1128 | break; | ||
| 1129 | } | ||
| 1130 | case OpCode::Id::IMNMX_C: | ||
| 1131 | case OpCode::Id::IMNMX_R: | ||
| 1132 | case OpCode::Id::IMNMX_IMM: { | ||
| 1133 | ASSERT_MSG(instr.imnmx.exchange == Tegra::Shader::IMinMaxExchange::None, | ||
| 1134 | "Unimplemented"); | ||
| 1135 | std::string condition = | ||
| 1136 | GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0); | ||
| 1137 | std::string parameters = op_a + ',' + op_b; | ||
| 1138 | regs.SetRegisterToInteger(instr.gpr0, instr.imnmx.is_signed, 0, | ||
| 1139 | '(' + condition + ") ? min(" + parameters + ") : max(" + | ||
| 1140 | parameters + ')', | ||
| 1141 | 1, 1); | ||
| 1142 | break; | ||
| 1143 | } | ||
| 1044 | default: { | 1144 | default: { |
| 1045 | NGLOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", | 1145 | LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", |
| 1046 | opcode->GetName()); | 1146 | opcode->GetName()); |
| 1047 | UNREACHABLE(); | 1147 | UNREACHABLE(); |
| 1048 | } | 1148 | } |
| 1049 | } | 1149 | } |
| @@ -1051,8 +1151,6 @@ private: | |||
| 1051 | break; | 1151 | break; |
| 1052 | } | 1152 | } |
| 1053 | case OpCode::Type::Ffma: { | 1153 | case OpCode::Type::Ffma: { |
| 1054 | ASSERT_MSG(!instr.saturate_a, "Unimplemented"); | ||
| 1055 | |||
| 1056 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 1154 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 1057 | std::string op_b = instr.ffma.negate_b ? "-" : ""; | 1155 | std::string op_b = instr.ffma.negate_b ? "-" : ""; |
| 1058 | std::string op_c = instr.ffma.negate_c ? "-" : ""; | 1156 | std::string op_c = instr.ffma.negate_c ? "-" : ""; |
| @@ -1081,38 +1179,38 @@ private: | |||
| 1081 | break; | 1179 | break; |
| 1082 | } | 1180 | } |
| 1083 | default: { | 1181 | default: { |
| 1084 | NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {}", opcode->GetName()); | 1182 | LOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {}", opcode->GetName()); |
| 1085 | UNREACHABLE(); | 1183 | UNREACHABLE(); |
| 1086 | } | 1184 | } |
| 1087 | } | 1185 | } |
| 1088 | 1186 | ||
| 1089 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1); | 1187 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1, |
| 1188 | instr.alu.saturate_d); | ||
| 1090 | break; | 1189 | break; |
| 1091 | } | 1190 | } |
| 1092 | case OpCode::Type::Conversion: { | 1191 | case OpCode::Type::Conversion: { |
| 1093 | ASSERT_MSG(instr.conversion.size == Register::Size::Word, "Unimplemented"); | ||
| 1094 | ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented"); | 1192 | ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented"); |
| 1095 | ASSERT_MSG(!instr.saturate_a, "Unimplemented"); | ||
| 1096 | 1193 | ||
| 1097 | switch (opcode->GetId()) { | 1194 | switch (opcode->GetId()) { |
| 1098 | case OpCode::Id::I2I_R: { | 1195 | case OpCode::Id::I2I_R: { |
| 1099 | ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); | 1196 | ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); |
| 1100 | 1197 | ||
| 1101 | std::string op_a = | 1198 | std::string op_a = regs.GetRegisterAsInteger( |
| 1102 | regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_input_signed); | 1199 | instr.gpr20, 0, instr.conversion.is_input_signed, instr.conversion.src_size); |
| 1103 | 1200 | ||
| 1104 | if (instr.conversion.abs_a) { | 1201 | if (instr.conversion.abs_a) { |
| 1105 | op_a = "abs(" + op_a + ')'; | 1202 | op_a = "abs(" + op_a + ')'; |
| 1106 | } | 1203 | } |
| 1107 | 1204 | ||
| 1108 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, | 1205 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, |
| 1109 | 1); | 1206 | 1, instr.alu.saturate_d, 0, instr.conversion.dest_size); |
| 1110 | break; | 1207 | break; |
| 1111 | } | 1208 | } |
| 1112 | case OpCode::Id::I2F_R: { | 1209 | case OpCode::Id::I2F_R: { |
| 1210 | ASSERT_MSG(instr.conversion.dest_size == Register::Size::Word, "Unimplemented"); | ||
| 1113 | ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); | 1211 | ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); |
| 1114 | std::string op_a = | 1212 | std::string op_a = regs.GetRegisterAsInteger( |
| 1115 | regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_input_signed); | 1213 | instr.gpr20, 0, instr.conversion.is_input_signed, instr.conversion.src_size); |
| 1116 | 1214 | ||
| 1117 | if (instr.conversion.abs_a) { | 1215 | if (instr.conversion.abs_a) { |
| 1118 | op_a = "abs(" + op_a + ')'; | 1216 | op_a = "abs(" + op_a + ')'; |
| @@ -1122,13 +1220,16 @@ private: | |||
| 1122 | break; | 1220 | break; |
| 1123 | } | 1221 | } |
| 1124 | case OpCode::Id::F2F_R: { | 1222 | case OpCode::Id::F2F_R: { |
| 1125 | ASSERT_MSG(!instr.saturate_a, "Unimplemented"); | 1223 | ASSERT_MSG(instr.conversion.dest_size == Register::Size::Word, "Unimplemented"); |
| 1126 | 1224 | ASSERT_MSG(instr.conversion.src_size == Register::Size::Word, "Unimplemented"); | |
| 1127 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); | 1225 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); |
| 1128 | 1226 | ||
| 1129 | switch (instr.conversion.f2f.rounding) { | 1227 | switch (instr.conversion.f2f.rounding) { |
| 1130 | case Tegra::Shader::F2fRoundingOp::None: | 1228 | case Tegra::Shader::F2fRoundingOp::None: |
| 1131 | break; | 1229 | break; |
| 1230 | case Tegra::Shader::F2fRoundingOp::Round: | ||
| 1231 | op_a = "roundEven(" + op_a + ')'; | ||
| 1232 | break; | ||
| 1132 | case Tegra::Shader::F2fRoundingOp::Floor: | 1233 | case Tegra::Shader::F2fRoundingOp::Floor: |
| 1133 | op_a = "floor(" + op_a + ')'; | 1234 | op_a = "floor(" + op_a + ')'; |
| 1134 | break; | 1235 | break; |
| @@ -1139,8 +1240,8 @@ private: | |||
| 1139 | op_a = "trunc(" + op_a + ')'; | 1240 | op_a = "trunc(" + op_a + ')'; |
| 1140 | break; | 1241 | break; |
| 1141 | default: | 1242 | default: |
| 1142 | NGLOG_CRITICAL(HW_GPU, "Unimplemented f2f rounding mode {}", | 1243 | LOG_CRITICAL(HW_GPU, "Unimplemented f2f rounding mode {}", |
| 1143 | static_cast<u32>(instr.conversion.f2f.rounding.Value())); | 1244 | static_cast<u32>(instr.conversion.f2f.rounding.Value())); |
| 1144 | UNREACHABLE(); | 1245 | UNREACHABLE(); |
| 1145 | break; | 1246 | break; |
| 1146 | } | 1247 | } |
| @@ -1149,10 +1250,11 @@ private: | |||
| 1149 | op_a = "abs(" + op_a + ')'; | 1250 | op_a = "abs(" + op_a + ')'; |
| 1150 | } | 1251 | } |
| 1151 | 1252 | ||
| 1152 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); | 1253 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d); |
| 1153 | break; | 1254 | break; |
| 1154 | } | 1255 | } |
| 1155 | case OpCode::Id::F2I_R: { | 1256 | case OpCode::Id::F2I_R: { |
| 1257 | ASSERT_MSG(instr.conversion.src_size == Register::Size::Word, "Unimplemented"); | ||
| 1156 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); | 1258 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); |
| 1157 | 1259 | ||
| 1158 | if (instr.conversion.abs_a) { | 1260 | if (instr.conversion.abs_a) { |
| @@ -1172,8 +1274,8 @@ private: | |||
| 1172 | op_a = "trunc(" + op_a + ')'; | 1274 | op_a = "trunc(" + op_a + ')'; |
| 1173 | break; | 1275 | break; |
| 1174 | default: | 1276 | default: |
| 1175 | NGLOG_CRITICAL(HW_GPU, "Unimplemented f2i rounding mode {}", | 1277 | LOG_CRITICAL(HW_GPU, "Unimplemented f2i rounding mode {}", |
| 1176 | static_cast<u32>(instr.conversion.f2i.rounding.Value())); | 1278 | static_cast<u32>(instr.conversion.f2i.rounding.Value())); |
| 1177 | UNREACHABLE(); | 1279 | UNREACHABLE(); |
| 1178 | break; | 1280 | break; |
| 1179 | } | 1281 | } |
| @@ -1185,11 +1287,11 @@ private: | |||
| 1185 | } | 1287 | } |
| 1186 | 1288 | ||
| 1187 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, | 1289 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, |
| 1188 | 1); | 1290 | 1, false, 0, instr.conversion.dest_size); |
| 1189 | break; | 1291 | break; |
| 1190 | } | 1292 | } |
| 1191 | default: { | 1293 | default: { |
| 1192 | NGLOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", opcode->GetName()); | 1294 | LOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", opcode->GetName()); |
| 1193 | UNREACHABLE(); | 1295 | UNREACHABLE(); |
| 1194 | } | 1296 | } |
| 1195 | } | 1297 | } |
| @@ -1224,8 +1326,8 @@ private: | |||
| 1224 | break; | 1326 | break; |
| 1225 | 1327 | ||
| 1226 | default: | 1328 | default: |
| 1227 | NGLOG_CRITICAL(HW_GPU, "Unhandled type: {}", | 1329 | LOG_CRITICAL(HW_GPU, "Unhandled type: {}", |
| 1228 | static_cast<unsigned>(instr.ld_c.type.Value())); | 1330 | static_cast<unsigned>(instr.ld_c.type.Value())); |
| 1229 | UNREACHABLE(); | 1331 | UNREACHABLE(); |
| 1230 | } | 1332 | } |
| 1231 | break; | 1333 | break; |
| @@ -1298,7 +1400,7 @@ private: | |||
| 1298 | break; | 1400 | break; |
| 1299 | } | 1401 | } |
| 1300 | default: { | 1402 | default: { |
| 1301 | NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName()); | 1403 | LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName()); |
| 1302 | UNREACHABLE(); | 1404 | UNREACHABLE(); |
| 1303 | } | 1405 | } |
| 1304 | } | 1406 | } |
| @@ -1340,10 +1442,9 @@ private: | |||
| 1340 | std::string second_pred = | 1442 | std::string second_pred = |
| 1341 | GetPredicateCondition(instr.fsetp.pred39, instr.fsetp.neg_pred != 0); | 1443 | GetPredicateCondition(instr.fsetp.pred39, instr.fsetp.neg_pred != 0); |
| 1342 | 1444 | ||
| 1343 | std::string comparator = GetPredicateComparison(instr.fsetp.cond); | ||
| 1344 | std::string combiner = GetPredicateCombiner(instr.fsetp.op); | 1445 | std::string combiner = GetPredicateCombiner(instr.fsetp.op); |
| 1345 | 1446 | ||
| 1346 | std::string predicate = '(' + op_a + ") " + comparator + " (" + op_b + ')'; | 1447 | std::string predicate = GetPredicateComparison(instr.fsetp.cond, op_a, op_b); |
| 1347 | // Set the primary predicate to the result of Predicate OP SecondPredicate | 1448 | // Set the primary predicate to the result of Predicate OP SecondPredicate |
| 1348 | SetPredicate(instr.fsetp.pred3, | 1449 | SetPredicate(instr.fsetp.pred3, |
| 1349 | '(' + predicate + ") " + combiner + " (" + second_pred + ')'); | 1450 | '(' + predicate + ") " + combiner + " (" + second_pred + ')'); |
| @@ -1378,10 +1479,9 @@ private: | |||
| 1378 | std::string second_pred = | 1479 | std::string second_pred = |
| 1379 | GetPredicateCondition(instr.isetp.pred39, instr.isetp.neg_pred != 0); | 1480 | GetPredicateCondition(instr.isetp.pred39, instr.isetp.neg_pred != 0); |
| 1380 | 1481 | ||
| 1381 | std::string comparator = GetPredicateComparison(instr.isetp.cond); | ||
| 1382 | std::string combiner = GetPredicateCombiner(instr.isetp.op); | 1482 | std::string combiner = GetPredicateCombiner(instr.isetp.op); |
| 1383 | 1483 | ||
| 1384 | std::string predicate = '(' + op_a + ") " + comparator + " (" + op_b + ')'; | 1484 | std::string predicate = GetPredicateComparison(instr.isetp.cond, op_a, op_b); |
| 1385 | // Set the primary predicate to the result of Predicate OP SecondPredicate | 1485 | // Set the primary predicate to the result of Predicate OP SecondPredicate |
| 1386 | SetPredicate(instr.isetp.pred3, | 1486 | SetPredicate(instr.isetp.pred3, |
| 1387 | '(' + predicate + ") " + combiner + " (" + second_pred + ')'); | 1487 | '(' + predicate + ") " + combiner + " (" + second_pred + ')'); |
| @@ -1394,6 +1494,36 @@ private: | |||
| 1394 | } | 1494 | } |
| 1395 | break; | 1495 | break; |
| 1396 | } | 1496 | } |
| 1497 | case OpCode::Type::PredicateSetPredicate: { | ||
| 1498 | std::string op_a = | ||
| 1499 | GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); | ||
| 1500 | std::string op_b = | ||
| 1501 | GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); | ||
| 1502 | |||
| 1503 | using Tegra::Shader::Pred; | ||
| 1504 | // We can't use the constant predicate as destination. | ||
| 1505 | ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); | ||
| 1506 | |||
| 1507 | std::string second_pred = | ||
| 1508 | GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); | ||
| 1509 | |||
| 1510 | std::string combiner = GetPredicateCombiner(instr.psetp.op); | ||
| 1511 | |||
| 1512 | std::string predicate = | ||
| 1513 | '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; | ||
| 1514 | |||
| 1515 | // Set the primary predicate to the result of Predicate OP SecondPredicate | ||
| 1516 | SetPredicate(instr.psetp.pred3, | ||
| 1517 | '(' + predicate + ") " + combiner + " (" + second_pred + ')'); | ||
| 1518 | |||
| 1519 | if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { | ||
| 1520 | // Set the secondary predicate to the result of !Predicate OP SecondPredicate, | ||
| 1521 | // if enabled | ||
| 1522 | SetPredicate(instr.psetp.pred0, | ||
| 1523 | "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); | ||
| 1524 | } | ||
| 1525 | break; | ||
| 1526 | } | ||
| 1397 | case OpCode::Type::FloatSet: { | 1527 | case OpCode::Type::FloatSet: { |
| 1398 | std::string op_a = instr.fset.neg_a ? "-" : ""; | 1528 | std::string op_a = instr.fset.neg_a ? "-" : ""; |
| 1399 | op_a += regs.GetRegisterAsFloat(instr.gpr8); | 1529 | op_a += regs.GetRegisterAsFloat(instr.gpr8); |
| @@ -1428,11 +1558,10 @@ private: | |||
| 1428 | std::string second_pred = | 1558 | std::string second_pred = |
| 1429 | GetPredicateCondition(instr.fset.pred39, instr.fset.neg_pred != 0); | 1559 | GetPredicateCondition(instr.fset.pred39, instr.fset.neg_pred != 0); |
| 1430 | 1560 | ||
| 1431 | std::string comparator = GetPredicateComparison(instr.fset.cond); | ||
| 1432 | std::string combiner = GetPredicateCombiner(instr.fset.op); | 1561 | std::string combiner = GetPredicateCombiner(instr.fset.op); |
| 1433 | 1562 | ||
| 1434 | std::string predicate = "(((" + op_a + ") " + comparator + " (" + op_b + ")) " + | 1563 | std::string predicate = "((" + GetPredicateComparison(instr.fset.cond, op_a, op_b) + |
| 1435 | combiner + " (" + second_pred + "))"; | 1564 | ") " + combiner + " (" + second_pred + "))"; |
| 1436 | 1565 | ||
| 1437 | if (instr.fset.bf) { | 1566 | if (instr.fset.bf) { |
| 1438 | regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); | 1567 | regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); |
| @@ -1463,11 +1592,10 @@ private: | |||
| 1463 | std::string second_pred = | 1592 | std::string second_pred = |
| 1464 | GetPredicateCondition(instr.iset.pred39, instr.iset.neg_pred != 0); | 1593 | GetPredicateCondition(instr.iset.pred39, instr.iset.neg_pred != 0); |
| 1465 | 1594 | ||
| 1466 | std::string comparator = GetPredicateComparison(instr.iset.cond); | ||
| 1467 | std::string combiner = GetPredicateCombiner(instr.iset.op); | 1595 | std::string combiner = GetPredicateCombiner(instr.iset.op); |
| 1468 | 1596 | ||
| 1469 | std::string predicate = "(((" + op_a + ") " + comparator + " (" + op_b + ")) " + | 1597 | std::string predicate = "((" + GetPredicateComparison(instr.iset.cond, op_a, op_b) + |
| 1470 | combiner + " (" + second_pred + "))"; | 1598 | ") " + combiner + " (" + second_pred + "))"; |
| 1471 | 1599 | ||
| 1472 | if (instr.iset.bf) { | 1600 | if (instr.iset.bf) { |
| 1473 | regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); | 1601 | regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); |
| @@ -1518,8 +1646,15 @@ private: | |||
| 1518 | // can ignore this when generating GLSL code. | 1646 | // can ignore this when generating GLSL code. |
| 1519 | break; | 1647 | break; |
| 1520 | } | 1648 | } |
| 1649 | case OpCode::Id::DEPBAR: | ||
| 1650 | case OpCode::Id::SYNC: { | ||
| 1651 | // TODO(Subv): Find out if we actually have to care about these instructions or if | ||
| 1652 | // the GLSL compiler takes care of that for us. | ||
| 1653 | LOG_WARNING(HW_GPU, "DEPBAR/SYNC instruction is stubbed"); | ||
| 1654 | break; | ||
| 1655 | } | ||
| 1521 | default: { | 1656 | default: { |
| 1522 | NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->GetName()); | 1657 | LOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->GetName()); |
| 1523 | UNREACHABLE(); | 1658 | UNREACHABLE(); |
| 1524 | } | 1659 | } |
| 1525 | } | 1660 | } |
| @@ -1646,7 +1781,10 @@ private: | |||
| 1646 | }; // namespace Decompiler | 1781 | }; // namespace Decompiler |
| 1647 | 1782 | ||
| 1648 | std::string GetCommonDeclarations() { | 1783 | std::string GetCommonDeclarations() { |
| 1649 | return "bool exec_shader();"; | 1784 | std::string declarations = "bool exec_shader();\n"; |
| 1785 | declarations += "#define MAX_CONSTBUFFER_ELEMENTS " + | ||
| 1786 | std::to_string(RasterizerOpenGL::MaxConstbufferSize / (sizeof(GLvec4))); | ||
| 1787 | return declarations; | ||
| 1650 | } | 1788 | } |
| 1651 | 1789 | ||
| 1652 | boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, | 1790 | boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, |
| @@ -1656,7 +1794,7 @@ boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, | |||
| 1656 | GLSLGenerator generator(subroutines, program_code, main_offset, stage); | 1794 | GLSLGenerator generator(subroutines, program_code, main_offset, stage); |
| 1657 | return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; | 1795 | return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; |
| 1658 | } catch (const DecompileFail& exception) { | 1796 | } catch (const DecompileFail& exception) { |
| 1659 | NGLOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); | 1797 | LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); |
| 1660 | } | 1798 | } |
| 1661 | return boost::none; | 1799 | return boost::none; |
| 1662 | } | 1800 | } |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index b88d592b7..c1e6fac9f 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -39,6 +39,10 @@ void main() { | |||
| 39 | // Viewport can be flipped, which is unsupported by glViewport | 39 | // Viewport can be flipped, which is unsupported by glViewport |
| 40 | position.xy *= viewport_flip.xy; | 40 | position.xy *= viewport_flip.xy; |
| 41 | gl_Position = position; | 41 | gl_Position = position; |
| 42 | |||
| 43 | // TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0 | ||
| 44 | // For now, this is here to bring order in lieu of proper emulation | ||
| 45 | position.w = 1.0; | ||
| 42 | } | 46 | } |
| 43 | )"; | 47 | )"; |
| 44 | out += program.first; | 48 | out += program.first; |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 7c00beb33..d7167b298 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp | |||
| @@ -38,8 +38,8 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh | |||
| 38 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | 38 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 39 | 39 | ||
| 40 | // TODO(bunnei): Support more than one viewport | 40 | // TODO(bunnei): Support more than one viewport |
| 41 | viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0 : 1.0; | 41 | viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f; |
| 42 | viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0 : 1.0; | 42 | viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | } // namespace GLShader | 45 | } // namespace GLShader |
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index 8568fface..3c087d638 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp | |||
| @@ -27,7 +27,7 @@ GLuint LoadShader(const char* source, GLenum type) { | |||
| 27 | } | 27 | } |
| 28 | GLuint shader_id = glCreateShader(type); | 28 | GLuint shader_id = glCreateShader(type); |
| 29 | glShaderSource(shader_id, 1, &source, nullptr); | 29 | glShaderSource(shader_id, 1, &source, nullptr); |
| 30 | NGLOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type); | 30 | LOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type); |
| 31 | glCompileShader(shader_id); | 31 | glCompileShader(shader_id); |
| 32 | 32 | ||
| 33 | GLint result = GL_FALSE; | 33 | GLint result = GL_FALSE; |
| @@ -39,9 +39,9 @@ GLuint LoadShader(const char* source, GLenum type) { | |||
| 39 | std::string shader_error(info_log_length, ' '); | 39 | std::string shader_error(info_log_length, ' '); |
| 40 | glGetShaderInfoLog(shader_id, info_log_length, nullptr, &shader_error[0]); | 40 | glGetShaderInfoLog(shader_id, info_log_length, nullptr, &shader_error[0]); |
| 41 | if (result == GL_TRUE) { | 41 | if (result == GL_TRUE) { |
| 42 | NGLOG_DEBUG(Render_OpenGL, "{}", shader_error); | 42 | LOG_DEBUG(Render_OpenGL, "{}", shader_error); |
| 43 | } else { | 43 | } else { |
| 44 | NGLOG_ERROR(Render_OpenGL, "Error compiling {} shader:\n{}", debug_type, shader_error); | 44 | LOG_ERROR(Render_OpenGL, "Error compiling {} shader:\n{}", debug_type, shader_error); |
| 45 | } | 45 | } |
| 46 | } | 46 | } |
| 47 | return shader_id; | 47 | return shader_id; |
diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h index 2036a06a9..0e4d782e2 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.h +++ b/src/video_core/renderer_opengl/gl_shader_util.h | |||
| @@ -29,7 +29,7 @@ void LogShaderSource(T... shaders) { | |||
| 29 | 29 | ||
| 30 | std::string source(source_length, ' '); | 30 | std::string source(source_length, ' '); |
| 31 | glGetShaderSource(shader, source_length, nullptr, &source[0]); | 31 | glGetShaderSource(shader, source_length, nullptr, &source[0]); |
| 32 | NGLOG_INFO(Render_OpenGL, "Shader source {}", source); | 32 | LOG_INFO(Render_OpenGL, "Shader source {}", source); |
| 33 | } | 33 | } |
| 34 | } | 34 | } |
| 35 | 35 | ||
| @@ -49,7 +49,7 @@ GLuint LoadShader(const char* source, GLenum type); | |||
| 49 | template <typename... T> | 49 | template <typename... T> |
| 50 | GLuint LoadProgram(bool separable_program, T... shaders) { | 50 | GLuint LoadProgram(bool separable_program, T... shaders) { |
| 51 | // Link the program | 51 | // Link the program |
| 52 | NGLOG_DEBUG(Render_OpenGL, "Linking program..."); | 52 | LOG_DEBUG(Render_OpenGL, "Linking program..."); |
| 53 | 53 | ||
| 54 | GLuint program_id = glCreateProgram(); | 54 | GLuint program_id = glCreateProgram(); |
| 55 | 55 | ||
| @@ -71,9 +71,9 @@ GLuint LoadProgram(bool separable_program, T... shaders) { | |||
| 71 | std::string program_error(info_log_length, ' '); | 71 | std::string program_error(info_log_length, ' '); |
| 72 | glGetProgramInfoLog(program_id, info_log_length, nullptr, &program_error[0]); | 72 | glGetProgramInfoLog(program_id, info_log_length, nullptr, &program_error[0]); |
| 73 | if (result == GL_TRUE) { | 73 | if (result == GL_TRUE) { |
| 74 | NGLOG_DEBUG(Render_OpenGL, "{}", program_error); | 74 | LOG_DEBUG(Render_OpenGL, "{}", program_error); |
| 75 | } else { | 75 | } else { |
| 76 | NGLOG_ERROR(Render_OpenGL, "Error linking shader:\n{}", program_error); | 76 | LOG_ERROR(Render_OpenGL, "Error linking shader:\n{}", program_error); |
| 77 | } | 77 | } |
| 78 | } | 78 | } |
| 79 | 79 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 44f0c8a01..2e8a422a8 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -48,24 +48,9 @@ OpenGLState::OpenGLState() { | |||
| 48 | logic_op = GL_COPY; | 48 | logic_op = GL_COPY; |
| 49 | 49 | ||
| 50 | for (auto& texture_unit : texture_units) { | 50 | for (auto& texture_unit : texture_units) { |
| 51 | texture_unit.texture_2d = 0; | 51 | texture_unit.Reset(); |
| 52 | texture_unit.sampler = 0; | ||
| 53 | texture_unit.swizzle.r = GL_RED; | ||
| 54 | texture_unit.swizzle.g = GL_GREEN; | ||
| 55 | texture_unit.swizzle.b = GL_BLUE; | ||
| 56 | texture_unit.swizzle.a = GL_ALPHA; | ||
| 57 | } | 52 | } |
| 58 | 53 | ||
| 59 | lighting_lut.texture_buffer = 0; | ||
| 60 | |||
| 61 | fog_lut.texture_buffer = 0; | ||
| 62 | |||
| 63 | proctex_lut.texture_buffer = 0; | ||
| 64 | proctex_diff_lut.texture_buffer = 0; | ||
| 65 | proctex_color_map.texture_buffer = 0; | ||
| 66 | proctex_alpha_map.texture_buffer = 0; | ||
| 67 | proctex_noise_lut.texture_buffer = 0; | ||
| 68 | |||
| 69 | draw.read_framebuffer = 0; | 54 | draw.read_framebuffer = 0; |
| 70 | draw.draw_framebuffer = 0; | 55 | draw.draw_framebuffer = 0; |
| 71 | draw.vertex_array = 0; | 56 | draw.vertex_array = 0; |
| @@ -196,13 +181,13 @@ void OpenGLState::Apply() const { | |||
| 196 | } | 181 | } |
| 197 | 182 | ||
| 198 | // Textures | 183 | // Textures |
| 199 | for (size_t i = 0; i < std::size(texture_units); ++i) { | 184 | for (int i = 0; i < std::size(texture_units); ++i) { |
| 200 | if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) { | 185 | if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) { |
| 201 | glActiveTexture(TextureUnits::MaxwellTexture(i).Enum()); | 186 | glActiveTexture(TextureUnits::MaxwellTexture(i).Enum()); |
| 202 | glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d); | 187 | glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d); |
| 203 | } | 188 | } |
| 204 | if (texture_units[i].sampler != cur_state.texture_units[i].sampler) { | 189 | if (texture_units[i].sampler != cur_state.texture_units[i].sampler) { |
| 205 | glBindSampler(i, texture_units[i].sampler); | 190 | glBindSampler(static_cast<GLuint>(i), texture_units[i].sampler); |
| 206 | } | 191 | } |
| 207 | // Update the texture swizzle | 192 | // Update the texture swizzle |
| 208 | if (texture_units[i].swizzle.r != cur_state.texture_units[i].swizzle.r || | 193 | if (texture_units[i].swizzle.r != cur_state.texture_units[i].swizzle.r || |
| @@ -223,54 +208,12 @@ void OpenGLState::Apply() const { | |||
| 223 | if (current.enabled != new_state.enabled || current.bindpoint != new_state.bindpoint || | 208 | if (current.enabled != new_state.enabled || current.bindpoint != new_state.bindpoint || |
| 224 | current.ssbo != new_state.ssbo) { | 209 | current.ssbo != new_state.ssbo) { |
| 225 | if (new_state.enabled) { | 210 | if (new_state.enabled) { |
| 226 | glBindBufferBase(GL_SHADER_STORAGE_BUFFER, new_state.bindpoint, new_state.ssbo); | 211 | glBindBufferBase(GL_UNIFORM_BUFFER, new_state.bindpoint, new_state.ssbo); |
| 227 | } | 212 | } |
| 228 | } | 213 | } |
| 229 | } | 214 | } |
| 230 | } | 215 | } |
| 231 | 216 | ||
| 232 | // Lighting LUTs | ||
| 233 | if (lighting_lut.texture_buffer != cur_state.lighting_lut.texture_buffer) { | ||
| 234 | glActiveTexture(TextureUnits::LightingLUT.Enum()); | ||
| 235 | glBindTexture(GL_TEXTURE_BUFFER, lighting_lut.texture_buffer); | ||
| 236 | } | ||
| 237 | |||
| 238 | // Fog LUT | ||
| 239 | if (fog_lut.texture_buffer != cur_state.fog_lut.texture_buffer) { | ||
| 240 | glActiveTexture(TextureUnits::FogLUT.Enum()); | ||
| 241 | glBindTexture(GL_TEXTURE_BUFFER, fog_lut.texture_buffer); | ||
| 242 | } | ||
| 243 | |||
| 244 | // ProcTex Noise LUT | ||
| 245 | if (proctex_noise_lut.texture_buffer != cur_state.proctex_noise_lut.texture_buffer) { | ||
| 246 | glActiveTexture(TextureUnits::ProcTexNoiseLUT.Enum()); | ||
| 247 | glBindTexture(GL_TEXTURE_BUFFER, proctex_noise_lut.texture_buffer); | ||
| 248 | } | ||
| 249 | |||
| 250 | // ProcTex Color Map | ||
| 251 | if (proctex_color_map.texture_buffer != cur_state.proctex_color_map.texture_buffer) { | ||
| 252 | glActiveTexture(TextureUnits::ProcTexColorMap.Enum()); | ||
| 253 | glBindTexture(GL_TEXTURE_BUFFER, proctex_color_map.texture_buffer); | ||
| 254 | } | ||
| 255 | |||
| 256 | // ProcTex Alpha Map | ||
| 257 | if (proctex_alpha_map.texture_buffer != cur_state.proctex_alpha_map.texture_buffer) { | ||
| 258 | glActiveTexture(TextureUnits::ProcTexAlphaMap.Enum()); | ||
| 259 | glBindTexture(GL_TEXTURE_BUFFER, proctex_alpha_map.texture_buffer); | ||
| 260 | } | ||
| 261 | |||
| 262 | // ProcTex LUT | ||
| 263 | if (proctex_lut.texture_buffer != cur_state.proctex_lut.texture_buffer) { | ||
| 264 | glActiveTexture(TextureUnits::ProcTexLUT.Enum()); | ||
| 265 | glBindTexture(GL_TEXTURE_BUFFER, proctex_lut.texture_buffer); | ||
| 266 | } | ||
| 267 | |||
| 268 | // ProcTex Diff LUT | ||
| 269 | if (proctex_diff_lut.texture_buffer != cur_state.proctex_diff_lut.texture_buffer) { | ||
| 270 | glActiveTexture(TextureUnits::ProcTexDiffLUT.Enum()); | ||
| 271 | glBindTexture(GL_TEXTURE_BUFFER, proctex_diff_lut.texture_buffer); | ||
| 272 | } | ||
| 273 | |||
| 274 | // Framebuffer | 217 | // Framebuffer |
| 275 | if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { | 218 | if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { |
| 276 | glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); | 219 | glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); |
| @@ -338,26 +281,12 @@ void OpenGLState::Apply() const { | |||
| 338 | cur_state = *this; | 281 | cur_state = *this; |
| 339 | } | 282 | } |
| 340 | 283 | ||
| 341 | OpenGLState& OpenGLState::ResetTexture(GLuint handle) { | 284 | OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { |
| 342 | for (auto& unit : texture_units) { | 285 | for (auto& unit : texture_units) { |
| 343 | if (unit.texture_2d == handle) { | 286 | if (unit.texture_2d == handle) { |
| 344 | unit.texture_2d = 0; | 287 | unit.Unbind(); |
| 345 | } | 288 | } |
| 346 | } | 289 | } |
| 347 | if (lighting_lut.texture_buffer == handle) | ||
| 348 | lighting_lut.texture_buffer = 0; | ||
| 349 | if (fog_lut.texture_buffer == handle) | ||
| 350 | fog_lut.texture_buffer = 0; | ||
| 351 | if (proctex_noise_lut.texture_buffer == handle) | ||
| 352 | proctex_noise_lut.texture_buffer = 0; | ||
| 353 | if (proctex_color_map.texture_buffer == handle) | ||
| 354 | proctex_color_map.texture_buffer = 0; | ||
| 355 | if (proctex_alpha_map.texture_buffer == handle) | ||
| 356 | proctex_alpha_map.texture_buffer = 0; | ||
| 357 | if (proctex_lut.texture_buffer == handle) | ||
| 358 | proctex_lut.texture_buffer = 0; | ||
| 359 | if (proctex_diff_lut.texture_buffer == handle) | ||
| 360 | proctex_diff_lut.texture_buffer = 0; | ||
| 361 | return *this; | 290 | return *this; |
| 362 | } | 291 | } |
| 363 | 292 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 839e50e93..3398d7c04 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -91,35 +91,20 @@ public: | |||
| 91 | GLint b; // GL_TEXTURE_SWIZZLE_B | 91 | GLint b; // GL_TEXTURE_SWIZZLE_B |
| 92 | GLint a; // GL_TEXTURE_SWIZZLE_A | 92 | GLint a; // GL_TEXTURE_SWIZZLE_A |
| 93 | } swizzle; | 93 | } swizzle; |
| 94 | } texture_units[32]; | ||
| 95 | |||
| 96 | struct { | ||
| 97 | GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER | ||
| 98 | } lighting_lut; | ||
| 99 | |||
| 100 | struct { | ||
| 101 | GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER | ||
| 102 | } fog_lut; | ||
| 103 | |||
| 104 | struct { | ||
| 105 | GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER | ||
| 106 | } proctex_noise_lut; | ||
| 107 | 94 | ||
| 108 | struct { | 95 | void Unbind() { |
| 109 | GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER | 96 | texture_2d = 0; |
| 110 | } proctex_color_map; | 97 | swizzle.r = GL_RED; |
| 111 | 98 | swizzle.g = GL_GREEN; | |
| 112 | struct { | 99 | swizzle.b = GL_BLUE; |
| 113 | GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER | 100 | swizzle.a = GL_ALPHA; |
| 114 | } proctex_alpha_map; | 101 | } |
| 115 | 102 | ||
| 116 | struct { | 103 | void Reset() { |
| 117 | GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER | 104 | Unbind(); |
| 118 | } proctex_lut; | 105 | sampler = 0; |
| 119 | 106 | } | |
| 120 | struct { | 107 | } texture_units[32]; |
| 121 | GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER | ||
| 122 | } proctex_diff_lut; | ||
| 123 | 108 | ||
| 124 | struct { | 109 | struct { |
| 125 | GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING | 110 | GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING |
| @@ -165,7 +150,7 @@ public: | |||
| 165 | void Apply() const; | 150 | void Apply() const; |
| 166 | 151 | ||
| 167 | /// Resets any references to the given resource | 152 | /// Resets any references to the given resource |
| 168 | OpenGLState& ResetTexture(GLuint handle); | 153 | OpenGLState& UnbindTexture(GLuint handle); |
| 169 | OpenGLState& ResetSampler(GLuint handle); | 154 | OpenGLState& ResetSampler(GLuint handle); |
| 170 | OpenGLState& ResetProgram(GLuint handle); | 155 | OpenGLState& ResetProgram(GLuint handle); |
| 171 | OpenGLState& ResetPipeline(GLuint handle); | 156 | OpenGLState& ResetPipeline(GLuint handle); |
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 2155fb019..e19c3b280 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -29,9 +29,13 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | |||
| 29 | switch (attrib.size) { | 29 | switch (attrib.size) { |
| 30 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | 30 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: |
| 31 | return GL_UNSIGNED_BYTE; | 31 | return GL_UNSIGNED_BYTE; |
| 32 | case Maxwell::VertexAttribute::Size::Size_16_16: | ||
| 33 | return GL_UNSIGNED_SHORT; | ||
| 34 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: | ||
| 35 | return GL_UNSIGNED_INT_2_10_10_10_REV; | ||
| 32 | } | 36 | } |
| 33 | 37 | ||
| 34 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); | 38 | LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); |
| 35 | UNREACHABLE(); | 39 | UNREACHABLE(); |
| 36 | return {}; | 40 | return {}; |
| 37 | } | 41 | } |
| @@ -41,9 +45,13 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | |||
| 41 | switch (attrib.size) { | 45 | switch (attrib.size) { |
| 42 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | 46 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: |
| 43 | return GL_BYTE; | 47 | return GL_BYTE; |
| 48 | case Maxwell::VertexAttribute::Size::Size_16_16: | ||
| 49 | return GL_SHORT; | ||
| 50 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: | ||
| 51 | return GL_INT_2_10_10_10_REV; | ||
| 44 | } | 52 | } |
| 45 | 53 | ||
| 46 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); | 54 | LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); |
| 47 | UNREACHABLE(); | 55 | UNREACHABLE(); |
| 48 | return {}; | 56 | return {}; |
| 49 | } | 57 | } |
| @@ -52,7 +60,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | |||
| 52 | return GL_FLOAT; | 60 | return GL_FLOAT; |
| 53 | } | 61 | } |
| 54 | 62 | ||
| 55 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString()); | 63 | LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString()); |
| 56 | UNREACHABLE(); | 64 | UNREACHABLE(); |
| 57 | return {}; | 65 | return {}; |
| 58 | } | 66 | } |
| @@ -66,7 +74,7 @@ inline GLenum IndexFormat(Maxwell::IndexFormat index_format) { | |||
| 66 | case Maxwell::IndexFormat::UnsignedInt: | 74 | case Maxwell::IndexFormat::UnsignedInt: |
| 67 | return GL_UNSIGNED_INT; | 75 | return GL_UNSIGNED_INT; |
| 68 | } | 76 | } |
| 69 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented index_format={}", static_cast<u32>(index_format)); | 77 | LOG_CRITICAL(Render_OpenGL, "Unimplemented index_format={}", static_cast<u32>(index_format)); |
| 70 | UNREACHABLE(); | 78 | UNREACHABLE(); |
| 71 | return {}; | 79 | return {}; |
| 72 | } | 80 | } |
| @@ -78,7 +86,7 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { | |||
| 78 | case Maxwell::PrimitiveTopology::TriangleStrip: | 86 | case Maxwell::PrimitiveTopology::TriangleStrip: |
| 79 | return GL_TRIANGLE_STRIP; | 87 | return GL_TRIANGLE_STRIP; |
| 80 | } | 88 | } |
| 81 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology)); | 89 | LOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology)); |
| 82 | UNREACHABLE(); | 90 | UNREACHABLE(); |
| 83 | return {}; | 91 | return {}; |
| 84 | } | 92 | } |
| @@ -90,8 +98,8 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) { | |||
| 90 | case Tegra::Texture::TextureFilter::Nearest: | 98 | case Tegra::Texture::TextureFilter::Nearest: |
| 91 | return GL_NEAREST; | 99 | return GL_NEAREST; |
| 92 | } | 100 | } |
| 93 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", | 101 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", |
| 94 | static_cast<u32>(filter_mode)); | 102 | static_cast<u32>(filter_mode)); |
| 95 | UNREACHABLE(); | 103 | UNREACHABLE(); |
| 96 | return {}; | 104 | return {}; |
| 97 | } | 105 | } |
| @@ -110,8 +118,7 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { | |||
| 110 | // manually mix them. However the shader part of this is not yet implemented. | 118 | // manually mix them. However the shader part of this is not yet implemented. |
| 111 | return GL_CLAMP_TO_BORDER; | 119 | return GL_CLAMP_TO_BORDER; |
| 112 | } | 120 | } |
| 113 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}", | 121 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); |
| 114 | static_cast<u32>(wrap_mode)); | ||
| 115 | UNREACHABLE(); | 122 | UNREACHABLE(); |
| 116 | return {}; | 123 | return {}; |
| 117 | } | 124 | } |
| @@ -129,7 +136,7 @@ inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { | |||
| 129 | case Maxwell::Blend::Equation::Max: | 136 | case Maxwell::Blend::Equation::Max: |
| 130 | return GL_MAX; | 137 | return GL_MAX; |
| 131 | } | 138 | } |
| 132 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation)); | 139 | LOG_CRITICAL(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation)); |
| 133 | UNREACHABLE(); | 140 | UNREACHABLE(); |
| 134 | return {}; | 141 | return {}; |
| 135 | } | 142 | } |
| @@ -175,7 +182,7 @@ inline GLenum BlendFunc(Maxwell::Blend::Factor factor) { | |||
| 175 | case Maxwell::Blend::Factor::OneMinusConstantAlpha: | 182 | case Maxwell::Blend::Factor::OneMinusConstantAlpha: |
| 176 | return GL_ONE_MINUS_CONSTANT_ALPHA; | 183 | return GL_ONE_MINUS_CONSTANT_ALPHA; |
| 177 | } | 184 | } |
| 178 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor)); | 185 | LOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor)); |
| 179 | UNREACHABLE(); | 186 | UNREACHABLE(); |
| 180 | return {}; | 187 | return {}; |
| 181 | } | 188 | } |
| @@ -196,7 +203,65 @@ inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) { | |||
| 196 | case Tegra::Texture::SwizzleSource::OneFloat: | 203 | case Tegra::Texture::SwizzleSource::OneFloat: |
| 197 | return GL_ONE; | 204 | return GL_ONE; |
| 198 | } | 205 | } |
| 199 | NGLOG_CRITICAL(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source)); | 206 | LOG_CRITICAL(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source)); |
| 207 | UNREACHABLE(); | ||
| 208 | return {}; | ||
| 209 | } | ||
| 210 | |||
| 211 | inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) { | ||
| 212 | switch (comparison) { | ||
| 213 | case Maxwell::ComparisonOp::Never: | ||
| 214 | case Maxwell::ComparisonOp::NeverOld: | ||
| 215 | return GL_NEVER; | ||
| 216 | case Maxwell::ComparisonOp::Less: | ||
| 217 | case Maxwell::ComparisonOp::LessOld: | ||
| 218 | return GL_LESS; | ||
| 219 | case Maxwell::ComparisonOp::Equal: | ||
| 220 | case Maxwell::ComparisonOp::EqualOld: | ||
| 221 | return GL_EQUAL; | ||
| 222 | case Maxwell::ComparisonOp::LessEqual: | ||
| 223 | case Maxwell::ComparisonOp::LessEqualOld: | ||
| 224 | return GL_LEQUAL; | ||
| 225 | case Maxwell::ComparisonOp::Greater: | ||
| 226 | case Maxwell::ComparisonOp::GreaterOld: | ||
| 227 | return GL_GREATER; | ||
| 228 | case Maxwell::ComparisonOp::NotEqual: | ||
| 229 | case Maxwell::ComparisonOp::NotEqualOld: | ||
| 230 | return GL_NOTEQUAL; | ||
| 231 | case Maxwell::ComparisonOp::GreaterEqual: | ||
| 232 | case Maxwell::ComparisonOp::GreaterEqualOld: | ||
| 233 | return GL_GEQUAL; | ||
| 234 | case Maxwell::ComparisonOp::Always: | ||
| 235 | case Maxwell::ComparisonOp::AlwaysOld: | ||
| 236 | return GL_ALWAYS; | ||
| 237 | } | ||
| 238 | LOG_CRITICAL(Render_OpenGL, "Unimplemented comparison op={}", static_cast<u32>(comparison)); | ||
| 239 | UNREACHABLE(); | ||
| 240 | return {}; | ||
| 241 | } | ||
| 242 | |||
| 243 | inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) { | ||
| 244 | switch (front_face) { | ||
| 245 | case Maxwell::Cull::FrontFace::ClockWise: | ||
| 246 | return GL_CW; | ||
| 247 | case Maxwell::Cull::FrontFace::CounterClockWise: | ||
| 248 | return GL_CCW; | ||
| 249 | } | ||
| 250 | LOG_CRITICAL(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face)); | ||
| 251 | UNREACHABLE(); | ||
| 252 | return {}; | ||
| 253 | } | ||
| 254 | |||
| 255 | inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) { | ||
| 256 | switch (cull_face) { | ||
| 257 | case Maxwell::Cull::CullFace::Front: | ||
| 258 | return GL_FRONT; | ||
| 259 | case Maxwell::Cull::CullFace::Back: | ||
| 260 | return GL_BACK; | ||
| 261 | case Maxwell::Cull::CullFace::FrontAndBack: | ||
| 262 | return GL_FRONT_AND_BACK; | ||
| 263 | } | ||
| 264 | LOG_CRITICAL(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face)); | ||
| 200 | UNREACHABLE(); | 265 | UNREACHABLE(); |
| 201 | return {}; | 266 | return {}; |
| 202 | } | 267 | } |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index f33766bfd..00841e937 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -150,7 +150,6 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf | |||
| 150 | screen_info)) { | 150 | screen_info)) { |
| 151 | // Reset the screen info's display texture to its own permanent texture | 151 | // Reset the screen info's display texture to its own permanent texture |
| 152 | screen_info.display_texture = screen_info.texture.resource.handle; | 152 | screen_info.display_texture = screen_info.texture.resource.handle; |
| 153 | screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f); | ||
| 154 | 153 | ||
| 155 | Memory::RasterizerFlushVirtualRegion(framebuffer_addr, size_in_bytes, | 154 | Memory::RasterizerFlushVirtualRegion(framebuffer_addr, size_in_bytes, |
| 156 | Memory::FlushMode::Flush); | 155 | Memory::FlushMode::Flush); |
| @@ -302,8 +301,8 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, | |||
| 302 | right = texcoords.left; | 301 | right = texcoords.left; |
| 303 | } else { | 302 | } else { |
| 304 | // Other transformations are unsupported | 303 | // Other transformations are unsupported |
| 305 | NGLOG_CRITICAL(Render_OpenGL, "Unsupported framebuffer_transform_flags={}", | 304 | LOG_CRITICAL(Render_OpenGL, "Unsupported framebuffer_transform_flags={}", |
| 306 | static_cast<u32>(framebuffer_transform_flags)); | 305 | static_cast<u32>(framebuffer_transform_flags)); |
| 307 | UNIMPLEMENTED(); | 306 | UNIMPLEMENTED(); |
| 308 | } | 307 | } |
| 309 | } | 308 | } |
| @@ -405,14 +404,14 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum | |||
| 405 | 404 | ||
| 406 | switch (severity) { | 405 | switch (severity) { |
| 407 | case GL_DEBUG_SEVERITY_HIGH: | 406 | case GL_DEBUG_SEVERITY_HIGH: |
| 408 | NGLOG_ERROR(Render_OpenGL, format, str_source, str_type, id, message); | 407 | LOG_ERROR(Render_OpenGL, format, str_source, str_type, id, message); |
| 409 | break; | 408 | break; |
| 410 | case GL_DEBUG_SEVERITY_MEDIUM: | 409 | case GL_DEBUG_SEVERITY_MEDIUM: |
| 411 | NGLOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message); | 410 | LOG_WARNING(Render_OpenGL, format, str_source, str_type, id, message); |
| 412 | break; | 411 | break; |
| 413 | case GL_DEBUG_SEVERITY_NOTIFICATION: | 412 | case GL_DEBUG_SEVERITY_NOTIFICATION: |
| 414 | case GL_DEBUG_SEVERITY_LOW: | 413 | case GL_DEBUG_SEVERITY_LOW: |
| 415 | NGLOG_DEBUG(Render_OpenGL, format, str_source, str_type, id, message); | 414 | LOG_DEBUG(Render_OpenGL, format, str_source, str_type, id, message); |
| 416 | break; | 415 | break; |
| 417 | } | 416 | } |
| 418 | } | 417 | } |
| @@ -430,9 +429,9 @@ bool RendererOpenGL::Init() { | |||
| 430 | const char* gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))}; | 429 | const char* gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))}; |
| 431 | const char* gpu_model{reinterpret_cast<char const*>(glGetString(GL_RENDERER))}; | 430 | const char* gpu_model{reinterpret_cast<char const*>(glGetString(GL_RENDERER))}; |
| 432 | 431 | ||
| 433 | NGLOG_INFO(Render_OpenGL, "GL_VERSION: {}", gl_version); | 432 | LOG_INFO(Render_OpenGL, "GL_VERSION: {}", gl_version); |
| 434 | NGLOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor); | 433 | LOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor); |
| 435 | NGLOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model); | 434 | LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model); |
| 436 | 435 | ||
| 437 | Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Vendor", gpu_vendor); | 436 | Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Vendor", gpu_vendor); |
| 438 | Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model); | 437 | Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 2cc6d9a00..21f0d298c 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -27,7 +27,7 @@ struct TextureInfo { | |||
| 27 | /// Structure used for storing information about the display target for the Switch screen | 27 | /// Structure used for storing information about the display target for the Switch screen |
| 28 | struct ScreenInfo { | 28 | struct ScreenInfo { |
| 29 | GLuint display_texture; | 29 | GLuint display_texture; |
| 30 | MathUtil::Rectangle<float> display_texcoords; | 30 | const MathUtil::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f}; |
| 31 | TextureInfo texture; | 31 | TextureInfo texture; |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp new file mode 100644 index 000000000..3c4ad1c9d --- /dev/null +++ b/src/video_core/textures/astc.cpp | |||
| @@ -0,0 +1,1646 @@ | |||
| 1 | // Copyright 2016 The University of North Carolina at Chapel Hill | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | // | ||
| 15 | // Please send all BUG REPORTS to <pavel@cs.unc.edu>. | ||
| 16 | // <http://gamma.cs.unc.edu/FasTC/> | ||
| 17 | |||
| 18 | #include <algorithm> | ||
| 19 | #include <cassert> | ||
| 20 | #include <cstdint> | ||
| 21 | #include <cstring> | ||
| 22 | #include <vector> | ||
| 23 | |||
| 24 | #include "video_core/textures/astc.h" | ||
| 25 | |||
| 26 | class BitStream { | ||
| 27 | public: | ||
| 28 | BitStream(unsigned char* ptr, int nBits = 0, int start_offset = 0) | ||
| 29 | : m_BitsWritten(0), m_BitsRead(0), m_NumBits(nBits), m_CurByte(ptr), | ||
| 30 | m_NextBit(start_offset % 8), done(false) {} | ||
| 31 | |||
| 32 | int GetBitsWritten() const { | ||
| 33 | return m_BitsWritten; | ||
| 34 | } | ||
| 35 | |||
| 36 | ~BitStream() {} | ||
| 37 | |||
| 38 | void WriteBitsR(unsigned int val, unsigned int nBits) { | ||
| 39 | for (unsigned int i = 0; i < nBits; i++) { | ||
| 40 | WriteBit((val >> (nBits - i - 1)) & 1); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | void WriteBits(unsigned int val, unsigned int nBits) { | ||
| 45 | for (unsigned int i = 0; i < nBits; i++) { | ||
| 46 | WriteBit((val >> i) & 1); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | int GetBitsRead() const { | ||
| 51 | return m_BitsRead; | ||
| 52 | } | ||
| 53 | |||
| 54 | int ReadBit() { | ||
| 55 | |||
| 56 | int bit = *m_CurByte >> m_NextBit++; | ||
| 57 | while (m_NextBit >= 8) { | ||
| 58 | m_NextBit -= 8; | ||
| 59 | m_CurByte++; | ||
| 60 | } | ||
| 61 | |||
| 62 | m_BitsRead++; | ||
| 63 | return bit & 1; | ||
| 64 | } | ||
| 65 | |||
| 66 | unsigned int ReadBits(unsigned int nBits) { | ||
| 67 | unsigned int ret = 0; | ||
| 68 | for (unsigned int i = 0; i < nBits; i++) { | ||
| 69 | ret |= (ReadBit() & 1) << i; | ||
| 70 | } | ||
| 71 | return ret; | ||
| 72 | } | ||
| 73 | |||
| 74 | private: | ||
| 75 | void WriteBit(int b) { | ||
| 76 | |||
| 77 | if (done) | ||
| 78 | return; | ||
| 79 | |||
| 80 | const unsigned int mask = 1 << m_NextBit++; | ||
| 81 | |||
| 82 | // clear the bit | ||
| 83 | *m_CurByte &= ~mask; | ||
| 84 | |||
| 85 | // Write the bit, if necessary | ||
| 86 | if (b) | ||
| 87 | *m_CurByte |= mask; | ||
| 88 | |||
| 89 | // Next byte? | ||
| 90 | if (m_NextBit >= 8) { | ||
| 91 | m_CurByte += 1; | ||
| 92 | m_NextBit = 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | done = done || ++m_BitsWritten >= m_NumBits; | ||
| 96 | } | ||
| 97 | |||
| 98 | int m_BitsWritten; | ||
| 99 | const int m_NumBits; | ||
| 100 | unsigned char* m_CurByte; | ||
| 101 | int m_NextBit; | ||
| 102 | int m_BitsRead; | ||
| 103 | |||
| 104 | bool done; | ||
| 105 | }; | ||
| 106 | |||
| 107 | template <typename IntType> | ||
| 108 | class Bits { | ||
| 109 | private: | ||
| 110 | const IntType& m_Bits; | ||
| 111 | |||
| 112 | // Don't copy | ||
| 113 | Bits() {} | ||
| 114 | Bits(const Bits&) {} | ||
| 115 | Bits& operator=(const Bits&) {} | ||
| 116 | |||
| 117 | public: | ||
| 118 | explicit Bits(IntType& v) : m_Bits(v) {} | ||
| 119 | |||
| 120 | uint8_t operator[](uint32_t bitPos) { | ||
| 121 | return static_cast<uint8_t>((m_Bits >> bitPos) & 1); | ||
| 122 | } | ||
| 123 | |||
| 124 | IntType operator()(uint32_t start, uint32_t end) { | ||
| 125 | if (start == end) { | ||
| 126 | return (*this)[start]; | ||
| 127 | } else if (start > end) { | ||
| 128 | uint32_t t = start; | ||
| 129 | start = end; | ||
| 130 | end = t; | ||
| 131 | } | ||
| 132 | |||
| 133 | uint64_t mask = (1 << (end - start + 1)) - 1; | ||
| 134 | return (m_Bits >> start) & mask; | ||
| 135 | } | ||
| 136 | }; | ||
| 137 | |||
| 138 | enum EIntegerEncoding { eIntegerEncoding_JustBits, eIntegerEncoding_Quint, eIntegerEncoding_Trit }; | ||
| 139 | |||
| 140 | class IntegerEncodedValue { | ||
| 141 | private: | ||
| 142 | const EIntegerEncoding m_Encoding; | ||
| 143 | const uint32_t m_NumBits; | ||
| 144 | uint32_t m_BitValue; | ||
| 145 | union { | ||
| 146 | uint32_t m_QuintValue; | ||
| 147 | uint32_t m_TritValue; | ||
| 148 | }; | ||
| 149 | |||
| 150 | public: | ||
| 151 | // Jank, but we're not doing any heavy lifting in this class, so it's | ||
| 152 | // probably OK. It allows us to use these in std::vectors... | ||
| 153 | IntegerEncodedValue& operator=(const IntegerEncodedValue& other) { | ||
| 154 | new (this) IntegerEncodedValue(other); | ||
| 155 | return *this; | ||
| 156 | } | ||
| 157 | |||
| 158 | IntegerEncodedValue(EIntegerEncoding encoding, uint32_t numBits) | ||
| 159 | : m_Encoding(encoding), m_NumBits(numBits) {} | ||
| 160 | |||
| 161 | EIntegerEncoding GetEncoding() const { | ||
| 162 | return m_Encoding; | ||
| 163 | } | ||
| 164 | uint32_t BaseBitLength() const { | ||
| 165 | return m_NumBits; | ||
| 166 | } | ||
| 167 | |||
| 168 | uint32_t GetBitValue() const { | ||
| 169 | return m_BitValue; | ||
| 170 | } | ||
| 171 | void SetBitValue(uint32_t val) { | ||
| 172 | m_BitValue = val; | ||
| 173 | } | ||
| 174 | |||
| 175 | uint32_t GetTritValue() const { | ||
| 176 | return m_TritValue; | ||
| 177 | } | ||
| 178 | void SetTritValue(uint32_t val) { | ||
| 179 | m_TritValue = val; | ||
| 180 | } | ||
| 181 | |||
| 182 | uint32_t GetQuintValue() const { | ||
| 183 | return m_QuintValue; | ||
| 184 | } | ||
| 185 | void SetQuintValue(uint32_t val) { | ||
| 186 | m_QuintValue = val; | ||
| 187 | } | ||
| 188 | |||
| 189 | bool MatchesEncoding(const IntegerEncodedValue& other) { | ||
| 190 | return m_Encoding == other.m_Encoding && m_NumBits == other.m_NumBits; | ||
| 191 | } | ||
| 192 | |||
| 193 | // Returns the number of bits required to encode nVals values. | ||
| 194 | uint32_t GetBitLength(uint32_t nVals) { | ||
| 195 | uint32_t totalBits = m_NumBits * nVals; | ||
| 196 | if (m_Encoding == eIntegerEncoding_Trit) { | ||
| 197 | totalBits += (nVals * 8 + 4) / 5; | ||
| 198 | } else if (m_Encoding == eIntegerEncoding_Quint) { | ||
| 199 | totalBits += (nVals * 7 + 2) / 3; | ||
| 200 | } | ||
| 201 | return totalBits; | ||
| 202 | } | ||
| 203 | |||
| 204 | // Count the number of bits set in a number. | ||
| 205 | static inline uint32_t Popcnt(uint32_t n) { | ||
| 206 | uint32_t c; | ||
| 207 | for (c = 0; n; c++) { | ||
| 208 | n &= n - 1; | ||
| 209 | } | ||
| 210 | return c; | ||
| 211 | } | ||
| 212 | |||
| 213 | // Returns a new instance of this struct that corresponds to the | ||
| 214 | // can take no more than maxval values | ||
| 215 | static IntegerEncodedValue CreateEncoding(uint32_t maxVal) { | ||
| 216 | while (maxVal > 0) { | ||
| 217 | uint32_t check = maxVal + 1; | ||
| 218 | |||
| 219 | // Is maxVal a power of two? | ||
| 220 | if (!(check & (check - 1))) { | ||
| 221 | return IntegerEncodedValue(eIntegerEncoding_JustBits, Popcnt(maxVal)); | ||
| 222 | } | ||
| 223 | |||
| 224 | // Is maxVal of the type 3*2^n - 1? | ||
| 225 | if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) { | ||
| 226 | return IntegerEncodedValue(eIntegerEncoding_Trit, Popcnt(check / 3 - 1)); | ||
| 227 | } | ||
| 228 | |||
| 229 | // Is maxVal of the type 5*2^n - 1? | ||
| 230 | if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) { | ||
| 231 | return IntegerEncodedValue(eIntegerEncoding_Quint, Popcnt(check / 5 - 1)); | ||
| 232 | } | ||
| 233 | |||
| 234 | // Apparently it can't be represented with a bounded integer sequence... | ||
| 235 | // just iterate. | ||
| 236 | maxVal--; | ||
| 237 | } | ||
| 238 | return IntegerEncodedValue(eIntegerEncoding_JustBits, 0); | ||
| 239 | } | ||
| 240 | |||
| 241 | // Fills result with the values that are encoded in the given | ||
| 242 | // bitstream. We must know beforehand what the maximum possible | ||
| 243 | // value is, and how many values we're decoding. | ||
| 244 | static void DecodeIntegerSequence(std::vector<IntegerEncodedValue>& result, BitStream& bits, | ||
| 245 | uint32_t maxRange, uint32_t nValues) { | ||
| 246 | // Determine encoding parameters | ||
| 247 | IntegerEncodedValue val = IntegerEncodedValue::CreateEncoding(maxRange); | ||
| 248 | |||
| 249 | // Start decoding | ||
| 250 | uint32_t nValsDecoded = 0; | ||
| 251 | while (nValsDecoded < nValues) { | ||
| 252 | switch (val.GetEncoding()) { | ||
| 253 | case eIntegerEncoding_Quint: | ||
| 254 | DecodeQuintBlock(bits, result, val.BaseBitLength()); | ||
| 255 | nValsDecoded += 3; | ||
| 256 | break; | ||
| 257 | |||
| 258 | case eIntegerEncoding_Trit: | ||
| 259 | DecodeTritBlock(bits, result, val.BaseBitLength()); | ||
| 260 | nValsDecoded += 5; | ||
| 261 | break; | ||
| 262 | |||
| 263 | case eIntegerEncoding_JustBits: | ||
| 264 | val.SetBitValue(bits.ReadBits(val.BaseBitLength())); | ||
| 265 | result.push_back(val); | ||
| 266 | nValsDecoded++; | ||
| 267 | break; | ||
| 268 | } | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | private: | ||
| 273 | static void DecodeTritBlock(BitStream& bits, std::vector<IntegerEncodedValue>& result, | ||
| 274 | uint32_t nBitsPerValue) { | ||
| 275 | // Implement the algorithm in section C.2.12 | ||
| 276 | uint32_t m[5]; | ||
| 277 | uint32_t t[5]; | ||
| 278 | uint32_t T; | ||
| 279 | |||
| 280 | // Read the trit encoded block according to | ||
| 281 | // table C.2.14 | ||
| 282 | m[0] = bits.ReadBits(nBitsPerValue); | ||
| 283 | T = bits.ReadBits(2); | ||
| 284 | m[1] = bits.ReadBits(nBitsPerValue); | ||
| 285 | T |= bits.ReadBits(2) << 2; | ||
| 286 | m[2] = bits.ReadBits(nBitsPerValue); | ||
| 287 | T |= bits.ReadBit() << 4; | ||
| 288 | m[3] = bits.ReadBits(nBitsPerValue); | ||
| 289 | T |= bits.ReadBits(2) << 5; | ||
| 290 | m[4] = bits.ReadBits(nBitsPerValue); | ||
| 291 | T |= bits.ReadBit() << 7; | ||
| 292 | |||
| 293 | uint32_t C = 0; | ||
| 294 | |||
| 295 | Bits<uint32_t> Tb(T); | ||
| 296 | if (Tb(2, 4) == 7) { | ||
| 297 | C = (Tb(5, 7) << 2) | Tb(0, 1); | ||
| 298 | t[4] = t[3] = 2; | ||
| 299 | } else { | ||
| 300 | C = Tb(0, 4); | ||
| 301 | if (Tb(5, 6) == 3) { | ||
| 302 | t[4] = 2; | ||
| 303 | t[3] = Tb[7]; | ||
| 304 | } else { | ||
| 305 | t[4] = Tb[7]; | ||
| 306 | t[3] = Tb(5, 6); | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | Bits<uint32_t> Cb(C); | ||
| 311 | if (Cb(0, 1) == 3) { | ||
| 312 | t[2] = 2; | ||
| 313 | t[1] = Cb[4]; | ||
| 314 | t[0] = (Cb[3] << 1) | (Cb[2] & ~Cb[3]); | ||
| 315 | } else if (Cb(2, 3) == 3) { | ||
| 316 | t[2] = 2; | ||
| 317 | t[1] = 2; | ||
| 318 | t[0] = Cb(0, 1); | ||
| 319 | } else { | ||
| 320 | t[2] = Cb[4]; | ||
| 321 | t[1] = Cb(2, 3); | ||
| 322 | t[0] = (Cb[1] << 1) | (Cb[0] & ~Cb[1]); | ||
| 323 | } | ||
| 324 | |||
| 325 | for (uint32_t i = 0; i < 5; i++) { | ||
| 326 | IntegerEncodedValue val(eIntegerEncoding_Trit, nBitsPerValue); | ||
| 327 | val.SetBitValue(m[i]); | ||
| 328 | val.SetTritValue(t[i]); | ||
| 329 | result.push_back(val); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | static void DecodeQuintBlock(BitStream& bits, std::vector<IntegerEncodedValue>& result, | ||
| 334 | uint32_t nBitsPerValue) { | ||
| 335 | // Implement the algorithm in section C.2.12 | ||
| 336 | uint32_t m[3]; | ||
| 337 | uint32_t q[3]; | ||
| 338 | uint32_t Q; | ||
| 339 | |||
| 340 | // Read the trit encoded block according to | ||
| 341 | // table C.2.15 | ||
| 342 | m[0] = bits.ReadBits(nBitsPerValue); | ||
| 343 | Q = bits.ReadBits(3); | ||
| 344 | m[1] = bits.ReadBits(nBitsPerValue); | ||
| 345 | Q |= bits.ReadBits(2) << 3; | ||
| 346 | m[2] = bits.ReadBits(nBitsPerValue); | ||
| 347 | Q |= bits.ReadBits(2) << 5; | ||
| 348 | |||
| 349 | Bits<uint32_t> Qb(Q); | ||
| 350 | if (Qb(1, 2) == 3 && Qb(5, 6) == 0) { | ||
| 351 | q[0] = q[1] = 4; | ||
| 352 | q[2] = (Qb[0] << 2) | ((Qb[4] & ~Qb[0]) << 1) | (Qb[3] & ~Qb[0]); | ||
| 353 | } else { | ||
| 354 | uint32_t C = 0; | ||
| 355 | if (Qb(1, 2) == 3) { | ||
| 356 | q[2] = 4; | ||
| 357 | C = (Qb(3, 4) << 3) | ((~Qb(5, 6) & 3) << 1) | Qb[0]; | ||
| 358 | } else { | ||
| 359 | q[2] = Qb(5, 6); | ||
| 360 | C = Qb(0, 4); | ||
| 361 | } | ||
| 362 | |||
| 363 | Bits<uint32_t> Cb(C); | ||
| 364 | if (Cb(0, 2) == 5) { | ||
| 365 | q[1] = 4; | ||
| 366 | q[0] = Cb(3, 4); | ||
| 367 | } else { | ||
| 368 | q[1] = Cb(3, 4); | ||
| 369 | q[0] = Cb(0, 2); | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 373 | for (uint32_t i = 0; i < 3; i++) { | ||
| 374 | IntegerEncodedValue val(eIntegerEncoding_Quint, nBitsPerValue); | ||
| 375 | val.m_BitValue = m[i]; | ||
| 376 | val.m_QuintValue = q[i]; | ||
| 377 | result.push_back(val); | ||
| 378 | } | ||
| 379 | } | ||
| 380 | }; | ||
| 381 | |||
| 382 | namespace ASTCC { | ||
| 383 | |||
| 384 | struct TexelWeightParams { | ||
| 385 | uint32_t m_Width; | ||
| 386 | uint32_t m_Height; | ||
| 387 | bool m_bDualPlane; | ||
| 388 | uint32_t m_MaxWeight; | ||
| 389 | bool m_bError; | ||
| 390 | bool m_bVoidExtentLDR; | ||
| 391 | bool m_bVoidExtentHDR; | ||
| 392 | |||
| 393 | TexelWeightParams() { | ||
| 394 | memset(this, 0, sizeof(*this)); | ||
| 395 | } | ||
| 396 | |||
| 397 | uint32_t GetPackedBitSize() { | ||
| 398 | // How many indices do we have? | ||
| 399 | uint32_t nIdxs = m_Height * m_Width; | ||
| 400 | if (m_bDualPlane) { | ||
| 401 | nIdxs *= 2; | ||
| 402 | } | ||
| 403 | |||
| 404 | return IntegerEncodedValue::CreateEncoding(m_MaxWeight).GetBitLength(nIdxs); | ||
| 405 | } | ||
| 406 | |||
| 407 | uint32_t GetNumWeightValues() const { | ||
| 408 | uint32_t ret = m_Width * m_Height; | ||
| 409 | if (m_bDualPlane) { | ||
| 410 | ret *= 2; | ||
| 411 | } | ||
| 412 | return ret; | ||
| 413 | } | ||
| 414 | }; | ||
| 415 | |||
| 416 | TexelWeightParams DecodeBlockInfo(BitStream& strm) { | ||
| 417 | TexelWeightParams params; | ||
| 418 | |||
| 419 | // Read the entire block mode all at once | ||
| 420 | uint16_t modeBits = strm.ReadBits(11); | ||
| 421 | |||
| 422 | // Does this match the void extent block mode? | ||
| 423 | if ((modeBits & 0x01FF) == 0x1FC) { | ||
| 424 | if (modeBits & 0x200) { | ||
| 425 | params.m_bVoidExtentHDR = true; | ||
| 426 | } else { | ||
| 427 | params.m_bVoidExtentLDR = true; | ||
| 428 | } | ||
| 429 | |||
| 430 | // Next two bits must be one. | ||
| 431 | if (!(modeBits & 0x400) || !strm.ReadBit()) { | ||
| 432 | params.m_bError = true; | ||
| 433 | } | ||
| 434 | |||
| 435 | return params; | ||
| 436 | } | ||
| 437 | |||
| 438 | // First check if the last four bits are zero | ||
| 439 | if ((modeBits & 0xF) == 0) { | ||
| 440 | params.m_bError = true; | ||
| 441 | return params; | ||
| 442 | } | ||
| 443 | |||
| 444 | // If the last two bits are zero, then if bits | ||
| 445 | // [6-8] are all ones, this is also reserved. | ||
| 446 | if ((modeBits & 0x3) == 0 && (modeBits & 0x1C0) == 0x1C0) { | ||
| 447 | params.m_bError = true; | ||
| 448 | return params; | ||
| 449 | } | ||
| 450 | |||
| 451 | // Otherwise, there is no error... Figure out the layout | ||
| 452 | // of the block mode. Layout is determined by a number | ||
| 453 | // between 0 and 9 corresponding to table C.2.8 of the | ||
| 454 | // ASTC spec. | ||
| 455 | uint32_t layout = 0; | ||
| 456 | |||
| 457 | if ((modeBits & 0x1) || (modeBits & 0x2)) { | ||
| 458 | // layout is in [0-4] | ||
| 459 | if (modeBits & 0x8) { | ||
| 460 | // layout is in [2-4] | ||
| 461 | if (modeBits & 0x4) { | ||
| 462 | // layout is in [3-4] | ||
| 463 | if (modeBits & 0x100) { | ||
| 464 | layout = 4; | ||
| 465 | } else { | ||
| 466 | layout = 3; | ||
| 467 | } | ||
| 468 | } else { | ||
| 469 | layout = 2; | ||
| 470 | } | ||
| 471 | } else { | ||
| 472 | // layout is in [0-1] | ||
| 473 | if (modeBits & 0x4) { | ||
| 474 | layout = 1; | ||
| 475 | } else { | ||
| 476 | layout = 0; | ||
| 477 | } | ||
| 478 | } | ||
| 479 | } else { | ||
| 480 | // layout is in [5-9] | ||
| 481 | if (modeBits & 0x100) { | ||
| 482 | // layout is in [7-9] | ||
| 483 | if (modeBits & 0x80) { | ||
| 484 | // layout is in [7-8] | ||
| 485 | assert((modeBits & 0x40) == 0U); | ||
| 486 | if (modeBits & 0x20) { | ||
| 487 | layout = 8; | ||
| 488 | } else { | ||
| 489 | layout = 7; | ||
| 490 | } | ||
| 491 | } else { | ||
| 492 | layout = 9; | ||
| 493 | } | ||
| 494 | } else { | ||
| 495 | // layout is in [5-6] | ||
| 496 | if (modeBits & 0x80) { | ||
| 497 | layout = 6; | ||
| 498 | } else { | ||
| 499 | layout = 5; | ||
| 500 | } | ||
| 501 | } | ||
| 502 | } | ||
| 503 | |||
| 504 | assert(layout < 10); | ||
| 505 | |||
| 506 | // Determine R | ||
| 507 | uint32_t R = !!(modeBits & 0x10); | ||
| 508 | if (layout < 5) { | ||
| 509 | R |= (modeBits & 0x3) << 1; | ||
| 510 | } else { | ||
| 511 | R |= (modeBits & 0xC) >> 1; | ||
| 512 | } | ||
| 513 | assert(2 <= R && R <= 7); | ||
| 514 | |||
| 515 | // Determine width & height | ||
| 516 | switch (layout) { | ||
| 517 | case 0: { | ||
| 518 | uint32_t A = (modeBits >> 5) & 0x3; | ||
| 519 | uint32_t B = (modeBits >> 7) & 0x3; | ||
| 520 | params.m_Width = B + 4; | ||
| 521 | params.m_Height = A + 2; | ||
| 522 | break; | ||
| 523 | } | ||
| 524 | |||
| 525 | case 1: { | ||
| 526 | uint32_t A = (modeBits >> 5) & 0x3; | ||
| 527 | uint32_t B = (modeBits >> 7) & 0x3; | ||
| 528 | params.m_Width = B + 8; | ||
| 529 | params.m_Height = A + 2; | ||
| 530 | break; | ||
| 531 | } | ||
| 532 | |||
| 533 | case 2: { | ||
| 534 | uint32_t A = (modeBits >> 5) & 0x3; | ||
| 535 | uint32_t B = (modeBits >> 7) & 0x3; | ||
| 536 | params.m_Width = A + 2; | ||
| 537 | params.m_Height = B + 8; | ||
| 538 | break; | ||
| 539 | } | ||
| 540 | |||
| 541 | case 3: { | ||
| 542 | uint32_t A = (modeBits >> 5) & 0x3; | ||
| 543 | uint32_t B = (modeBits >> 7) & 0x1; | ||
| 544 | params.m_Width = A + 2; | ||
| 545 | params.m_Height = B + 6; | ||
| 546 | break; | ||
| 547 | } | ||
| 548 | |||
| 549 | case 4: { | ||
| 550 | uint32_t A = (modeBits >> 5) & 0x3; | ||
| 551 | uint32_t B = (modeBits >> 7) & 0x1; | ||
| 552 | params.m_Width = B + 2; | ||
| 553 | params.m_Height = A + 2; | ||
| 554 | break; | ||
| 555 | } | ||
| 556 | |||
| 557 | case 5: { | ||
| 558 | uint32_t A = (modeBits >> 5) & 0x3; | ||
| 559 | params.m_Width = 12; | ||
| 560 | params.m_Height = A + 2; | ||
| 561 | break; | ||
| 562 | } | ||
| 563 | |||
| 564 | case 6: { | ||
| 565 | uint32_t A = (modeBits >> 5) & 0x3; | ||
| 566 | params.m_Width = A + 2; | ||
| 567 | params.m_Height = 12; | ||
| 568 | break; | ||
| 569 | } | ||
| 570 | |||
| 571 | case 7: { | ||
| 572 | params.m_Width = 6; | ||
| 573 | params.m_Height = 10; | ||
| 574 | break; | ||
| 575 | } | ||
| 576 | |||
| 577 | case 8: { | ||
| 578 | params.m_Width = 10; | ||
| 579 | params.m_Height = 6; | ||
| 580 | break; | ||
| 581 | } | ||
| 582 | |||
| 583 | case 9: { | ||
| 584 | uint32_t A = (modeBits >> 5) & 0x3; | ||
| 585 | uint32_t B = (modeBits >> 9) & 0x3; | ||
| 586 | params.m_Width = A + 6; | ||
| 587 | params.m_Height = B + 6; | ||
| 588 | break; | ||
| 589 | } | ||
| 590 | |||
| 591 | default: | ||
| 592 | assert(!"Don't know this layout..."); | ||
| 593 | params.m_bError = true; | ||
| 594 | break; | ||
| 595 | } | ||
| 596 | |||
| 597 | // Determine whether or not we're using dual planes | ||
| 598 | // and/or high precision layouts. | ||
| 599 | bool D = (layout != 9) && (modeBits & 0x400); | ||
| 600 | bool H = (layout != 9) && (modeBits & 0x200); | ||
| 601 | |||
| 602 | if (H) { | ||
| 603 | const uint32_t maxWeights[6] = {9, 11, 15, 19, 23, 31}; | ||
| 604 | params.m_MaxWeight = maxWeights[R - 2]; | ||
| 605 | } else { | ||
| 606 | const uint32_t maxWeights[6] = {1, 2, 3, 4, 5, 7}; | ||
| 607 | params.m_MaxWeight = maxWeights[R - 2]; | ||
| 608 | } | ||
| 609 | |||
| 610 | params.m_bDualPlane = D; | ||
| 611 | |||
| 612 | return params; | ||
| 613 | } | ||
| 614 | |||
| 615 | void FillVoidExtentLDR(BitStream& strm, uint32_t* const outBuf, uint32_t blockWidth, | ||
| 616 | uint32_t blockHeight) { | ||
| 617 | // Don't actually care about the void extent, just read the bits... | ||
| 618 | for (int i = 0; i < 4; ++i) { | ||
| 619 | strm.ReadBits(13); | ||
| 620 | } | ||
| 621 | |||
| 622 | // Decode the RGBA components and renormalize them to the range [0, 255] | ||
| 623 | uint16_t r = strm.ReadBits(16); | ||
| 624 | uint16_t g = strm.ReadBits(16); | ||
| 625 | uint16_t b = strm.ReadBits(16); | ||
| 626 | uint16_t a = strm.ReadBits(16); | ||
| 627 | |||
| 628 | uint32_t rgba = (r >> 8) | (g & 0xFF00) | (static_cast<uint32_t>(b) & 0xFF00) << 8 | | ||
| 629 | (static_cast<uint32_t>(a) & 0xFF00) << 16; | ||
| 630 | |||
| 631 | for (uint32_t j = 0; j < blockHeight; j++) | ||
| 632 | for (uint32_t i = 0; i < blockWidth; i++) { | ||
| 633 | outBuf[j * blockWidth + i] = rgba; | ||
| 634 | } | ||
| 635 | } | ||
| 636 | |||
| 637 | void FillError(uint32_t* outBuf, uint32_t blockWidth, uint32_t blockHeight) { | ||
| 638 | for (uint32_t j = 0; j < blockHeight; j++) | ||
| 639 | for (uint32_t i = 0; i < blockWidth; i++) { | ||
| 640 | outBuf[j * blockWidth + i] = 0xFFFF00FF; | ||
| 641 | } | ||
| 642 | } | ||
| 643 | |||
| 644 | // Replicates low numBits such that [(toBit - 1):(toBit - 1 - fromBit)] | ||
| 645 | // is the same as [(numBits - 1):0] and repeats all the way down. | ||
| 646 | template <typename IntType> | ||
| 647 | IntType Replicate(const IntType& val, uint32_t numBits, uint32_t toBit) { | ||
| 648 | if (numBits == 0) | ||
| 649 | return 0; | ||
| 650 | if (toBit == 0) | ||
| 651 | return 0; | ||
| 652 | IntType v = val & ((1 << numBits) - 1); | ||
| 653 | IntType res = v; | ||
| 654 | uint32_t reslen = numBits; | ||
| 655 | while (reslen < toBit) { | ||
| 656 | uint32_t comp = 0; | ||
| 657 | if (numBits > toBit - reslen) { | ||
| 658 | uint32_t newshift = toBit - reslen; | ||
| 659 | comp = numBits - newshift; | ||
| 660 | numBits = newshift; | ||
| 661 | } | ||
| 662 | res <<= numBits; | ||
| 663 | res |= v >> comp; | ||
| 664 | reslen += numBits; | ||
| 665 | } | ||
| 666 | return res; | ||
| 667 | } | ||
| 668 | |||
| 669 | class Pixel { | ||
| 670 | protected: | ||
| 671 | typedef int16_t ChannelType; | ||
| 672 | uint8_t m_BitDepth[4]; | ||
| 673 | int16_t color[4]; | ||
| 674 | |||
| 675 | public: | ||
| 676 | Pixel() { | ||
| 677 | for (int i = 0; i < 4; i++) { | ||
| 678 | m_BitDepth[i] = 8; | ||
| 679 | color[i] = 0; | ||
| 680 | } | ||
| 681 | } | ||
| 682 | |||
| 683 | Pixel(ChannelType a, ChannelType r, ChannelType g, ChannelType b, unsigned bitDepth = 8) { | ||
| 684 | for (int i = 0; i < 4; i++) | ||
| 685 | m_BitDepth[i] = bitDepth; | ||
| 686 | |||
| 687 | color[0] = a; | ||
| 688 | color[1] = r; | ||
| 689 | color[2] = g; | ||
| 690 | color[3] = b; | ||
| 691 | } | ||
| 692 | |||
| 693 | // Changes the depth of each pixel. This scales the values to | ||
| 694 | // the appropriate bit depth by either truncating the least | ||
| 695 | // significant bits when going from larger to smaller bit depth | ||
| 696 | // or by repeating the most significant bits when going from | ||
| 697 | // smaller to larger bit depths. | ||
| 698 | void ChangeBitDepth(const uint8_t (&depth)[4]) { | ||
| 699 | for (uint32_t i = 0; i < 4; i++) { | ||
| 700 | Component(i) = ChangeBitDepth(Component(i), m_BitDepth[i], depth[i]); | ||
| 701 | m_BitDepth[i] = depth[i]; | ||
| 702 | } | ||
| 703 | } | ||
| 704 | |||
| 705 | template <typename IntType> | ||
| 706 | static float ConvertChannelToFloat(IntType channel, uint8_t bitDepth) { | ||
| 707 | float denominator = static_cast<float>((1 << bitDepth) - 1); | ||
| 708 | return static_cast<float>(channel) / denominator; | ||
| 709 | } | ||
| 710 | |||
| 711 | // Changes the bit depth of a single component. See the comment | ||
| 712 | // above for how we do this. | ||
| 713 | static ChannelType ChangeBitDepth(Pixel::ChannelType val, uint8_t oldDepth, uint8_t newDepth) { | ||
| 714 | assert(newDepth <= 8); | ||
| 715 | assert(oldDepth <= 8); | ||
| 716 | |||
| 717 | if (oldDepth == newDepth) { | ||
| 718 | // Do nothing | ||
| 719 | return val; | ||
| 720 | } else if (oldDepth == 0 && newDepth != 0) { | ||
| 721 | return (1 << newDepth) - 1; | ||
| 722 | } else if (newDepth > oldDepth) { | ||
| 723 | return Replicate(val, oldDepth, newDepth); | ||
| 724 | } else { | ||
| 725 | // oldDepth > newDepth | ||
| 726 | if (newDepth == 0) { | ||
| 727 | return 0xFF; | ||
| 728 | } else { | ||
| 729 | uint8_t bitsWasted = oldDepth - newDepth; | ||
| 730 | uint16_t v = static_cast<uint16_t>(val); | ||
| 731 | v = (v + (1 << (bitsWasted - 1))) >> bitsWasted; | ||
| 732 | v = ::std::min<uint16_t>(::std::max<uint16_t>(0, v), (1 << newDepth) - 1); | ||
| 733 | return static_cast<uint8_t>(v); | ||
| 734 | } | ||
| 735 | } | ||
| 736 | |||
| 737 | assert(!"We shouldn't get here."); | ||
| 738 | return 0; | ||
| 739 | } | ||
| 740 | |||
| 741 | const ChannelType& A() const { | ||
| 742 | return color[0]; | ||
| 743 | } | ||
| 744 | ChannelType& A() { | ||
| 745 | return color[0]; | ||
| 746 | } | ||
| 747 | const ChannelType& R() const { | ||
| 748 | return color[1]; | ||
| 749 | } | ||
| 750 | ChannelType& R() { | ||
| 751 | return color[1]; | ||
| 752 | } | ||
| 753 | const ChannelType& G() const { | ||
| 754 | return color[2]; | ||
| 755 | } | ||
| 756 | ChannelType& G() { | ||
| 757 | return color[2]; | ||
| 758 | } | ||
| 759 | const ChannelType& B() const { | ||
| 760 | return color[3]; | ||
| 761 | } | ||
| 762 | ChannelType& B() { | ||
| 763 | return color[3]; | ||
| 764 | } | ||
| 765 | const ChannelType& Component(uint32_t idx) const { | ||
| 766 | return color[idx]; | ||
| 767 | } | ||
| 768 | ChannelType& Component(uint32_t idx) { | ||
| 769 | return color[idx]; | ||
| 770 | } | ||
| 771 | |||
| 772 | void GetBitDepth(uint8_t (&outDepth)[4]) const { | ||
| 773 | for (int i = 0; i < 4; i++) { | ||
| 774 | outDepth[i] = m_BitDepth[i]; | ||
| 775 | } | ||
| 776 | } | ||
| 777 | |||
| 778 | // Take all of the components, transform them to their 8-bit variants, | ||
| 779 | // and then pack each channel into an R8G8B8A8 32-bit integer. We assume | ||
| 780 | // that the architecture is little-endian, so the alpha channel will end | ||
| 781 | // up in the most-significant byte. | ||
| 782 | uint32_t Pack() const { | ||
| 783 | Pixel eightBit(*this); | ||
| 784 | const uint8_t eightBitDepth[4] = {8, 8, 8, 8}; | ||
| 785 | eightBit.ChangeBitDepth(eightBitDepth); | ||
| 786 | |||
| 787 | uint32_t r = 0; | ||
| 788 | r |= eightBit.A(); | ||
| 789 | r <<= 8; | ||
| 790 | r |= eightBit.B(); | ||
| 791 | r <<= 8; | ||
| 792 | r |= eightBit.G(); | ||
| 793 | r <<= 8; | ||
| 794 | r |= eightBit.R(); | ||
| 795 | return r; | ||
| 796 | } | ||
| 797 | |||
| 798 | // Clamps the pixel to the range [0,255] | ||
| 799 | void ClampByte() { | ||
| 800 | for (uint32_t i = 0; i < 4; i++) { | ||
| 801 | color[i] = (color[i] < 0) ? 0 : ((color[i] > 255) ? 255 : color[i]); | ||
| 802 | } | ||
| 803 | } | ||
| 804 | |||
| 805 | void MakeOpaque() { | ||
| 806 | A() = 255; | ||
| 807 | } | ||
| 808 | }; | ||
| 809 | |||
| 810 | void DecodeColorValues(uint32_t* out, uint8_t* data, uint32_t* modes, const uint32_t nPartitions, | ||
| 811 | const uint32_t nBitsForColorData) { | ||
| 812 | // First figure out how many color values we have | ||
| 813 | uint32_t nValues = 0; | ||
| 814 | for (uint32_t i = 0; i < nPartitions; i++) { | ||
| 815 | nValues += ((modes[i] >> 2) + 1) << 1; | ||
| 816 | } | ||
| 817 | |||
| 818 | // Then based on the number of values and the remaining number of bits, | ||
| 819 | // figure out the max value for each of them... | ||
| 820 | uint32_t range = 256; | ||
| 821 | while (--range > 0) { | ||
| 822 | IntegerEncodedValue val = IntegerEncodedValue::CreateEncoding(range); | ||
| 823 | uint32_t bitLength = val.GetBitLength(nValues); | ||
| 824 | if (bitLength <= nBitsForColorData) { | ||
| 825 | // Find the smallest possible range that matches the given encoding | ||
| 826 | while (--range > 0) { | ||
| 827 | IntegerEncodedValue newval = IntegerEncodedValue::CreateEncoding(range); | ||
| 828 | if (!newval.MatchesEncoding(val)) { | ||
| 829 | break; | ||
| 830 | } | ||
| 831 | } | ||
| 832 | |||
| 833 | // Return to last matching range. | ||
| 834 | range++; | ||
| 835 | break; | ||
| 836 | } | ||
| 837 | } | ||
| 838 | |||
| 839 | // We now have enough to decode our integer sequence. | ||
| 840 | std::vector<IntegerEncodedValue> decodedColorValues; | ||
| 841 | BitStream colorStream(data); | ||
| 842 | IntegerEncodedValue::DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues); | ||
| 843 | |||
| 844 | // Once we have the decoded values, we need to dequantize them to the 0-255 range | ||
| 845 | // This procedure is outlined in ASTC spec C.2.13 | ||
| 846 | uint32_t outIdx = 0; | ||
| 847 | std::vector<IntegerEncodedValue>::const_iterator itr; | ||
| 848 | for (itr = decodedColorValues.begin(); itr != decodedColorValues.end(); itr++) { | ||
| 849 | // Have we already decoded all that we need? | ||
| 850 | if (outIdx >= nValues) { | ||
| 851 | break; | ||
| 852 | } | ||
| 853 | |||
| 854 | const IntegerEncodedValue& val = *itr; | ||
| 855 | uint32_t bitlen = val.BaseBitLength(); | ||
| 856 | uint32_t bitval = val.GetBitValue(); | ||
| 857 | |||
| 858 | assert(bitlen >= 1); | ||
| 859 | |||
| 860 | uint32_t A = 0, B = 0, C = 0, D = 0; | ||
| 861 | // A is just the lsb replicated 9 times. | ||
| 862 | A = Replicate(bitval & 1, 1, 9); | ||
| 863 | |||
| 864 | switch (val.GetEncoding()) { | ||
| 865 | // Replicate bits | ||
| 866 | case eIntegerEncoding_JustBits: | ||
| 867 | out[outIdx++] = Replicate(bitval, bitlen, 8); | ||
| 868 | break; | ||
| 869 | |||
| 870 | // Use algorithm in C.2.13 | ||
| 871 | case eIntegerEncoding_Trit: { | ||
| 872 | |||
| 873 | D = val.GetTritValue(); | ||
| 874 | |||
| 875 | switch (bitlen) { | ||
| 876 | case 1: { | ||
| 877 | C = 204; | ||
| 878 | } break; | ||
| 879 | |||
| 880 | case 2: { | ||
| 881 | C = 93; | ||
| 882 | // B = b000b0bb0 | ||
| 883 | uint32_t b = (bitval >> 1) & 1; | ||
| 884 | B = (b << 8) | (b << 4) | (b << 2) | (b << 1); | ||
| 885 | } break; | ||
| 886 | |||
| 887 | case 3: { | ||
| 888 | C = 44; | ||
| 889 | // B = cb000cbcb | ||
| 890 | uint32_t cb = (bitval >> 1) & 3; | ||
| 891 | B = (cb << 7) | (cb << 2) | cb; | ||
| 892 | } break; | ||
| 893 | |||
| 894 | case 4: { | ||
| 895 | C = 22; | ||
| 896 | // B = dcb000dcb | ||
| 897 | uint32_t dcb = (bitval >> 1) & 7; | ||
| 898 | B = (dcb << 6) | dcb; | ||
| 899 | } break; | ||
| 900 | |||
| 901 | case 5: { | ||
| 902 | C = 11; | ||
| 903 | // B = edcb000ed | ||
| 904 | uint32_t edcb = (bitval >> 1) & 0xF; | ||
| 905 | B = (edcb << 5) | (edcb >> 2); | ||
| 906 | } break; | ||
| 907 | |||
| 908 | case 6: { | ||
| 909 | C = 5; | ||
| 910 | // B = fedcb000f | ||
| 911 | uint32_t fedcb = (bitval >> 1) & 0x1F; | ||
| 912 | B = (fedcb << 4) | (fedcb >> 4); | ||
| 913 | } break; | ||
| 914 | |||
| 915 | default: | ||
| 916 | assert(!"Unsupported trit encoding for color values!"); | ||
| 917 | break; | ||
| 918 | } // switch(bitlen) | ||
| 919 | } // case eIntegerEncoding_Trit | ||
| 920 | break; | ||
| 921 | |||
| 922 | case eIntegerEncoding_Quint: { | ||
| 923 | |||
| 924 | D = val.GetQuintValue(); | ||
| 925 | |||
| 926 | switch (bitlen) { | ||
| 927 | case 1: { | ||
| 928 | C = 113; | ||
| 929 | } break; | ||
| 930 | |||
| 931 | case 2: { | ||
| 932 | C = 54; | ||
| 933 | // B = b0000bb00 | ||
| 934 | uint32_t b = (bitval >> 1) & 1; | ||
| 935 | B = (b << 8) | (b << 3) | (b << 2); | ||
| 936 | } break; | ||
| 937 | |||
| 938 | case 3: { | ||
| 939 | C = 26; | ||
| 940 | // B = cb0000cbc | ||
| 941 | uint32_t cb = (bitval >> 1) & 3; | ||
| 942 | B = (cb << 7) | (cb << 1) | (cb >> 1); | ||
| 943 | } break; | ||
| 944 | |||
| 945 | case 4: { | ||
| 946 | C = 13; | ||
| 947 | // B = dcb0000dc | ||
| 948 | uint32_t dcb = (bitval >> 1) & 7; | ||
| 949 | B = (dcb << 6) | (dcb >> 1); | ||
| 950 | } break; | ||
| 951 | |||
| 952 | case 5: { | ||
| 953 | C = 6; | ||
| 954 | // B = edcb0000e | ||
| 955 | uint32_t edcb = (bitval >> 1) & 0xF; | ||
| 956 | B = (edcb << 5) | (edcb >> 3); | ||
| 957 | } break; | ||
| 958 | |||
| 959 | default: | ||
| 960 | assert(!"Unsupported quint encoding for color values!"); | ||
| 961 | break; | ||
| 962 | } // switch(bitlen) | ||
| 963 | } // case eIntegerEncoding_Quint | ||
| 964 | break; | ||
| 965 | } // switch(val.GetEncoding()) | ||
| 966 | |||
| 967 | if (val.GetEncoding() != eIntegerEncoding_JustBits) { | ||
| 968 | uint32_t T = D * C + B; | ||
| 969 | T ^= A; | ||
| 970 | T = (A & 0x80) | (T >> 2); | ||
| 971 | out[outIdx++] = T; | ||
| 972 | } | ||
| 973 | } | ||
| 974 | |||
| 975 | // Make sure that each of our values is in the proper range... | ||
| 976 | for (uint32_t i = 0; i < nValues; i++) { | ||
| 977 | assert(out[i] <= 255); | ||
| 978 | } | ||
| 979 | } | ||
| 980 | |||
| 981 | uint32_t UnquantizeTexelWeight(const IntegerEncodedValue& val) { | ||
| 982 | uint32_t bitval = val.GetBitValue(); | ||
| 983 | uint32_t bitlen = val.BaseBitLength(); | ||
| 984 | |||
| 985 | uint32_t A = Replicate(bitval & 1, 1, 7); | ||
| 986 | uint32_t B = 0, C = 0, D = 0; | ||
| 987 | |||
| 988 | uint32_t result = 0; | ||
| 989 | switch (val.GetEncoding()) { | ||
| 990 | case eIntegerEncoding_JustBits: | ||
| 991 | result = Replicate(bitval, bitlen, 6); | ||
| 992 | break; | ||
| 993 | |||
| 994 | case eIntegerEncoding_Trit: { | ||
| 995 | D = val.GetTritValue(); | ||
| 996 | assert(D < 3); | ||
| 997 | |||
| 998 | switch (bitlen) { | ||
| 999 | case 0: { | ||
| 1000 | uint32_t results[3] = {0, 32, 63}; | ||
| 1001 | result = results[D]; | ||
| 1002 | } break; | ||
| 1003 | |||
| 1004 | case 1: { | ||
| 1005 | C = 50; | ||
| 1006 | } break; | ||
| 1007 | |||
| 1008 | case 2: { | ||
| 1009 | C = 23; | ||
| 1010 | uint32_t b = (bitval >> 1) & 1; | ||
| 1011 | B = (b << 6) | (b << 2) | b; | ||
| 1012 | } break; | ||
| 1013 | |||
| 1014 | case 3: { | ||
| 1015 | C = 11; | ||
| 1016 | uint32_t cb = (bitval >> 1) & 3; | ||
| 1017 | B = (cb << 5) | cb; | ||
| 1018 | } break; | ||
| 1019 | |||
| 1020 | default: | ||
| 1021 | assert(!"Invalid trit encoding for texel weight"); | ||
| 1022 | break; | ||
| 1023 | } | ||
| 1024 | } break; | ||
| 1025 | |||
| 1026 | case eIntegerEncoding_Quint: { | ||
| 1027 | D = val.GetQuintValue(); | ||
| 1028 | assert(D < 5); | ||
| 1029 | |||
| 1030 | switch (bitlen) { | ||
| 1031 | case 0: { | ||
| 1032 | uint32_t results[5] = {0, 16, 32, 47, 63}; | ||
| 1033 | result = results[D]; | ||
| 1034 | } break; | ||
| 1035 | |||
| 1036 | case 1: { | ||
| 1037 | C = 28; | ||
| 1038 | } break; | ||
| 1039 | |||
| 1040 | case 2: { | ||
| 1041 | C = 13; | ||
| 1042 | uint32_t b = (bitval >> 1) & 1; | ||
| 1043 | B = (b << 6) | (b << 1); | ||
| 1044 | } break; | ||
| 1045 | |||
| 1046 | default: | ||
| 1047 | assert(!"Invalid quint encoding for texel weight"); | ||
| 1048 | break; | ||
| 1049 | } | ||
| 1050 | } break; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | if (val.GetEncoding() != eIntegerEncoding_JustBits && bitlen > 0) { | ||
| 1054 | // Decode the value... | ||
| 1055 | result = D * C + B; | ||
| 1056 | result ^= A; | ||
| 1057 | result = (A & 0x20) | (result >> 2); | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | assert(result < 64); | ||
| 1061 | |||
| 1062 | // Change from [0,63] to [0,64] | ||
| 1063 | if (result > 32) { | ||
| 1064 | result += 1; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | return result; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | void UnquantizeTexelWeights(uint32_t out[2][144], std::vector<IntegerEncodedValue>& weights, | ||
| 1071 | const TexelWeightParams& params, const uint32_t blockWidth, | ||
| 1072 | const uint32_t blockHeight) { | ||
| 1073 | uint32_t weightIdx = 0; | ||
| 1074 | uint32_t unquantized[2][144]; | ||
| 1075 | std::vector<IntegerEncodedValue>::const_iterator itr; | ||
| 1076 | for (itr = weights.begin(); itr != weights.end(); itr++) { | ||
| 1077 | unquantized[0][weightIdx] = UnquantizeTexelWeight(*itr); | ||
| 1078 | |||
| 1079 | if (params.m_bDualPlane) { | ||
| 1080 | itr++; | ||
| 1081 | unquantized[1][weightIdx] = UnquantizeTexelWeight(*itr); | ||
| 1082 | if (itr == weights.end()) { | ||
| 1083 | break; | ||
| 1084 | } | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | if (++weightIdx >= (params.m_Width * params.m_Height)) | ||
| 1088 | break; | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | // Do infill if necessary (Section C.2.18) ... | ||
| 1092 | uint32_t Ds = (1024 + (blockWidth / 2)) / (blockWidth - 1); | ||
| 1093 | uint32_t Dt = (1024 + (blockHeight / 2)) / (blockHeight - 1); | ||
| 1094 | |||
| 1095 | const uint32_t kPlaneScale = params.m_bDualPlane ? 2U : 1U; | ||
| 1096 | for (uint32_t plane = 0; plane < kPlaneScale; plane++) | ||
| 1097 | for (uint32_t t = 0; t < blockHeight; t++) | ||
| 1098 | for (uint32_t s = 0; s < blockWidth; s++) { | ||
| 1099 | uint32_t cs = Ds * s; | ||
| 1100 | uint32_t ct = Dt * t; | ||
| 1101 | |||
| 1102 | uint32_t gs = (cs * (params.m_Width - 1) + 32) >> 6; | ||
| 1103 | uint32_t gt = (ct * (params.m_Height - 1) + 32) >> 6; | ||
| 1104 | |||
| 1105 | uint32_t js = gs >> 4; | ||
| 1106 | uint32_t fs = gs & 0xF; | ||
| 1107 | |||
| 1108 | uint32_t jt = gt >> 4; | ||
| 1109 | uint32_t ft = gt & 0x0F; | ||
| 1110 | |||
| 1111 | uint32_t w11 = (fs * ft + 8) >> 4; | ||
| 1112 | uint32_t w10 = ft - w11; | ||
| 1113 | uint32_t w01 = fs - w11; | ||
| 1114 | uint32_t w00 = 16 - fs - ft + w11; | ||
| 1115 | |||
| 1116 | uint32_t v0 = js + jt * params.m_Width; | ||
| 1117 | |||
| 1118 | #define FIND_TEXEL(tidx, bidx) \ | ||
| 1119 | uint32_t p##bidx = 0; \ | ||
| 1120 | do { \ | ||
| 1121 | if ((tidx) < (params.m_Width * params.m_Height)) { \ | ||
| 1122 | p##bidx = unquantized[plane][(tidx)]; \ | ||
| 1123 | } \ | ||
| 1124 | } while (0) | ||
| 1125 | |||
| 1126 | FIND_TEXEL(v0, 00); | ||
| 1127 | FIND_TEXEL(v0 + 1, 01); | ||
| 1128 | FIND_TEXEL(v0 + params.m_Width, 10); | ||
| 1129 | FIND_TEXEL(v0 + params.m_Width + 1, 11); | ||
| 1130 | |||
| 1131 | #undef FIND_TEXEL | ||
| 1132 | |||
| 1133 | out[plane][t * blockWidth + s] = | ||
| 1134 | (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4; | ||
| 1135 | } | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | // Transfers a bit as described in C.2.14 | ||
| 1139 | static inline void BitTransferSigned(int32_t& a, int32_t& b) { | ||
| 1140 | b >>= 1; | ||
| 1141 | b |= a & 0x80; | ||
| 1142 | a >>= 1; | ||
| 1143 | a &= 0x3F; | ||
| 1144 | if (a & 0x20) | ||
| 1145 | a -= 0x40; | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | // Adds more precision to the blue channel as described | ||
| 1149 | // in C.2.14 | ||
| 1150 | static inline Pixel BlueContract(int32_t a, int32_t r, int32_t g, int32_t b) { | ||
| 1151 | return Pixel(static_cast<int16_t>(a), static_cast<int16_t>((r + b) >> 1), | ||
| 1152 | static_cast<int16_t>((g + b) >> 1), static_cast<int16_t>(b)); | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | // Partition selection functions as specified in | ||
| 1156 | // C.2.21 | ||
| 1157 | static inline uint32_t hash52(uint32_t p) { | ||
| 1158 | p ^= p >> 15; | ||
| 1159 | p -= p << 17; | ||
| 1160 | p += p << 7; | ||
| 1161 | p += p << 4; | ||
| 1162 | p ^= p >> 5; | ||
| 1163 | p += p << 16; | ||
| 1164 | p ^= p >> 7; | ||
| 1165 | p ^= p >> 3; | ||
| 1166 | p ^= p << 6; | ||
| 1167 | p ^= p >> 17; | ||
| 1168 | return p; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | static uint32_t SelectPartition(int32_t seed, int32_t x, int32_t y, int32_t z, | ||
| 1172 | int32_t partitionCount, int32_t smallBlock) { | ||
| 1173 | if (1 == partitionCount) | ||
| 1174 | return 0; | ||
| 1175 | |||
| 1176 | if (smallBlock) { | ||
| 1177 | x <<= 1; | ||
| 1178 | y <<= 1; | ||
| 1179 | z <<= 1; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | seed += (partitionCount - 1) * 1024; | ||
| 1183 | |||
| 1184 | uint32_t rnum = hash52(static_cast<uint32_t>(seed)); | ||
| 1185 | uint8_t seed1 = static_cast<uint8_t>(rnum & 0xF); | ||
| 1186 | uint8_t seed2 = static_cast<uint8_t>((rnum >> 4) & 0xF); | ||
| 1187 | uint8_t seed3 = static_cast<uint8_t>((rnum >> 8) & 0xF); | ||
| 1188 | uint8_t seed4 = static_cast<uint8_t>((rnum >> 12) & 0xF); | ||
| 1189 | uint8_t seed5 = static_cast<uint8_t>((rnum >> 16) & 0xF); | ||
| 1190 | uint8_t seed6 = static_cast<uint8_t>((rnum >> 20) & 0xF); | ||
| 1191 | uint8_t seed7 = static_cast<uint8_t>((rnum >> 24) & 0xF); | ||
| 1192 | uint8_t seed8 = static_cast<uint8_t>((rnum >> 28) & 0xF); | ||
| 1193 | uint8_t seed9 = static_cast<uint8_t>((rnum >> 18) & 0xF); | ||
| 1194 | uint8_t seed10 = static_cast<uint8_t>((rnum >> 22) & 0xF); | ||
| 1195 | uint8_t seed11 = static_cast<uint8_t>((rnum >> 26) & 0xF); | ||
| 1196 | uint8_t seed12 = static_cast<uint8_t>(((rnum >> 30) | (rnum << 2)) & 0xF); | ||
| 1197 | |||
| 1198 | seed1 *= seed1; | ||
| 1199 | seed2 *= seed2; | ||
| 1200 | seed3 *= seed3; | ||
| 1201 | seed4 *= seed4; | ||
| 1202 | seed5 *= seed5; | ||
| 1203 | seed6 *= seed6; | ||
| 1204 | seed7 *= seed7; | ||
| 1205 | seed8 *= seed8; | ||
| 1206 | seed9 *= seed9; | ||
| 1207 | seed10 *= seed10; | ||
| 1208 | seed11 *= seed11; | ||
| 1209 | seed12 *= seed12; | ||
| 1210 | |||
| 1211 | int32_t sh1, sh2, sh3; | ||
| 1212 | if (seed & 1) { | ||
| 1213 | sh1 = (seed & 2) ? 4 : 5; | ||
| 1214 | sh2 = (partitionCount == 3) ? 6 : 5; | ||
| 1215 | } else { | ||
| 1216 | sh1 = (partitionCount == 3) ? 6 : 5; | ||
| 1217 | sh2 = (seed & 2) ? 4 : 5; | ||
| 1218 | } | ||
| 1219 | sh3 = (seed & 0x10) ? sh1 : sh2; | ||
| 1220 | |||
| 1221 | seed1 >>= sh1; | ||
| 1222 | seed2 >>= sh2; | ||
| 1223 | seed3 >>= sh1; | ||
| 1224 | seed4 >>= sh2; | ||
| 1225 | seed5 >>= sh1; | ||
| 1226 | seed6 >>= sh2; | ||
| 1227 | seed7 >>= sh1; | ||
| 1228 | seed8 >>= sh2; | ||
| 1229 | seed9 >>= sh3; | ||
| 1230 | seed10 >>= sh3; | ||
| 1231 | seed11 >>= sh3; | ||
| 1232 | seed12 >>= sh3; | ||
| 1233 | |||
| 1234 | int32_t a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14); | ||
| 1235 | int32_t b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10); | ||
| 1236 | int32_t c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6); | ||
| 1237 | int32_t d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2); | ||
| 1238 | |||
| 1239 | a &= 0x3F; | ||
| 1240 | b &= 0x3F; | ||
| 1241 | c &= 0x3F; | ||
| 1242 | d &= 0x3F; | ||
| 1243 | |||
| 1244 | if (partitionCount < 4) | ||
| 1245 | d = 0; | ||
| 1246 | if (partitionCount < 3) | ||
| 1247 | c = 0; | ||
| 1248 | |||
| 1249 | if (a >= b && a >= c && a >= d) | ||
| 1250 | return 0; | ||
| 1251 | else if (b >= c && b >= d) | ||
| 1252 | return 1; | ||
| 1253 | else if (c >= d) | ||
| 1254 | return 2; | ||
| 1255 | return 3; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | static inline uint32_t Select2DPartition(int32_t seed, int32_t x, int32_t y, int32_t partitionCount, | ||
| 1259 | int32_t smallBlock) { | ||
| 1260 | return SelectPartition(seed, x, y, 0, partitionCount, smallBlock); | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | // Section C.2.14 | ||
| 1264 | void ComputeEndpoints(Pixel& ep1, Pixel& ep2, const uint32_t*& colorValues, | ||
| 1265 | uint32_t colorEndpointMode) { | ||
| 1266 | #define READ_UINT_VALUES(N) \ | ||
| 1267 | uint32_t v[N]; \ | ||
| 1268 | for (uint32_t i = 0; i < N; i++) { \ | ||
| 1269 | v[i] = *(colorValues++); \ | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | #define READ_INT_VALUES(N) \ | ||
| 1273 | int32_t v[N]; \ | ||
| 1274 | for (uint32_t i = 0; i < N; i++) { \ | ||
| 1275 | v[i] = static_cast<int32_t>(*(colorValues++)); \ | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | switch (colorEndpointMode) { | ||
| 1279 | case 0: { | ||
| 1280 | READ_UINT_VALUES(2) | ||
| 1281 | ep1 = Pixel(0xFF, v[0], v[0], v[0]); | ||
| 1282 | ep2 = Pixel(0xFF, v[1], v[1], v[1]); | ||
| 1283 | } break; | ||
| 1284 | |||
| 1285 | case 1: { | ||
| 1286 | READ_UINT_VALUES(2) | ||
| 1287 | uint32_t L0 = (v[0] >> 2) | (v[1] & 0xC0); | ||
| 1288 | uint32_t L1 = std::max(L0 + (v[1] & 0x3F), 0xFFU); | ||
| 1289 | ep1 = Pixel(0xFF, L0, L0, L0); | ||
| 1290 | ep2 = Pixel(0xFF, L1, L1, L1); | ||
| 1291 | } break; | ||
| 1292 | |||
| 1293 | case 4: { | ||
| 1294 | READ_UINT_VALUES(4) | ||
| 1295 | ep1 = Pixel(v[2], v[0], v[0], v[0]); | ||
| 1296 | ep2 = Pixel(v[3], v[1], v[1], v[1]); | ||
| 1297 | } break; | ||
| 1298 | |||
| 1299 | case 5: { | ||
| 1300 | READ_INT_VALUES(4) | ||
| 1301 | BitTransferSigned(v[1], v[0]); | ||
| 1302 | BitTransferSigned(v[3], v[2]); | ||
| 1303 | ep1 = Pixel(v[2], v[0], v[0], v[0]); | ||
| 1304 | ep2 = Pixel(v[2] + v[3], v[0] + v[1], v[0] + v[1], v[0] + v[1]); | ||
| 1305 | ep1.ClampByte(); | ||
| 1306 | ep2.ClampByte(); | ||
| 1307 | } break; | ||
| 1308 | |||
| 1309 | case 6: { | ||
| 1310 | READ_UINT_VALUES(4) | ||
| 1311 | ep1 = Pixel(0xFF, v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8); | ||
| 1312 | ep2 = Pixel(0xFF, v[0], v[1], v[2]); | ||
| 1313 | } break; | ||
| 1314 | |||
| 1315 | case 8: { | ||
| 1316 | READ_UINT_VALUES(6) | ||
| 1317 | if (v[1] + v[3] + v[5] >= v[0] + v[2] + v[4]) { | ||
| 1318 | ep1 = Pixel(0xFF, v[0], v[2], v[4]); | ||
| 1319 | ep2 = Pixel(0xFF, v[1], v[3], v[5]); | ||
| 1320 | } else { | ||
| 1321 | ep1 = BlueContract(0xFF, v[1], v[3], v[5]); | ||
| 1322 | ep2 = BlueContract(0xFF, v[0], v[2], v[4]); | ||
| 1323 | } | ||
| 1324 | } break; | ||
| 1325 | |||
| 1326 | case 9: { | ||
| 1327 | READ_INT_VALUES(6) | ||
| 1328 | BitTransferSigned(v[1], v[0]); | ||
| 1329 | BitTransferSigned(v[3], v[2]); | ||
| 1330 | BitTransferSigned(v[5], v[4]); | ||
| 1331 | if (v[1] + v[3] + v[5] >= 0) { | ||
| 1332 | ep1 = Pixel(0xFF, v[0], v[2], v[4]); | ||
| 1333 | ep2 = Pixel(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]); | ||
| 1334 | } else { | ||
| 1335 | ep1 = BlueContract(0xFF, v[0] + v[1], v[2] + v[3], v[4] + v[5]); | ||
| 1336 | ep2 = BlueContract(0xFF, v[0], v[2], v[4]); | ||
| 1337 | } | ||
| 1338 | ep1.ClampByte(); | ||
| 1339 | ep2.ClampByte(); | ||
| 1340 | } break; | ||
| 1341 | |||
| 1342 | case 10: { | ||
| 1343 | READ_UINT_VALUES(6) | ||
| 1344 | ep1 = Pixel(v[4], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8); | ||
| 1345 | ep2 = Pixel(v[5], v[0], v[1], v[2]); | ||
| 1346 | } break; | ||
| 1347 | |||
| 1348 | case 12: { | ||
| 1349 | READ_UINT_VALUES(8) | ||
| 1350 | if (v[1] + v[3] + v[5] >= v[0] + v[2] + v[4]) { | ||
| 1351 | ep1 = Pixel(v[6], v[0], v[2], v[4]); | ||
| 1352 | ep2 = Pixel(v[7], v[1], v[3], v[5]); | ||
| 1353 | } else { | ||
| 1354 | ep1 = BlueContract(v[7], v[1], v[3], v[5]); | ||
| 1355 | ep2 = BlueContract(v[6], v[0], v[2], v[4]); | ||
| 1356 | } | ||
| 1357 | } break; | ||
| 1358 | |||
| 1359 | case 13: { | ||
| 1360 | READ_INT_VALUES(8) | ||
| 1361 | BitTransferSigned(v[1], v[0]); | ||
| 1362 | BitTransferSigned(v[3], v[2]); | ||
| 1363 | BitTransferSigned(v[5], v[4]); | ||
| 1364 | BitTransferSigned(v[7], v[6]); | ||
| 1365 | if (v[1] + v[3] + v[5] >= 0) { | ||
| 1366 | ep1 = Pixel(v[6], v[0], v[2], v[4]); | ||
| 1367 | ep2 = Pixel(v[7] + v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5]); | ||
| 1368 | } else { | ||
| 1369 | ep1 = BlueContract(v[6] + v[7], v[0] + v[1], v[2] + v[3], v[4] + v[5]); | ||
| 1370 | ep2 = BlueContract(v[6], v[0], v[2], v[4]); | ||
| 1371 | } | ||
| 1372 | ep1.ClampByte(); | ||
| 1373 | ep2.ClampByte(); | ||
| 1374 | } break; | ||
| 1375 | |||
| 1376 | default: | ||
| 1377 | assert(!"Unsupported color endpoint mode (is it HDR?)"); | ||
| 1378 | break; | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | #undef READ_UINT_VALUES | ||
| 1382 | #undef READ_INT_VALUES | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | void DecompressBlock(uint8_t inBuf[16], const uint32_t blockWidth, const uint32_t blockHeight, | ||
| 1386 | uint32_t* outBuf) { | ||
| 1387 | BitStream strm(inBuf); | ||
| 1388 | TexelWeightParams weightParams = DecodeBlockInfo(strm); | ||
| 1389 | |||
| 1390 | // Was there an error? | ||
| 1391 | if (weightParams.m_bError) { | ||
| 1392 | assert(!"Invalid block mode"); | ||
| 1393 | FillError(outBuf, blockWidth, blockHeight); | ||
| 1394 | return; | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | if (weightParams.m_bVoidExtentLDR) { | ||
| 1398 | FillVoidExtentLDR(strm, outBuf, blockWidth, blockHeight); | ||
| 1399 | return; | ||
| 1400 | } | ||
| 1401 | |||
| 1402 | if (weightParams.m_bVoidExtentHDR) { | ||
| 1403 | assert(!"HDR void extent blocks are unsupported!"); | ||
| 1404 | FillError(outBuf, blockWidth, blockHeight); | ||
| 1405 | return; | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | if (weightParams.m_Width > blockWidth) { | ||
| 1409 | assert(!"Texel weight grid width should be smaller than block width"); | ||
| 1410 | FillError(outBuf, blockWidth, blockHeight); | ||
| 1411 | return; | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | if (weightParams.m_Height > blockHeight) { | ||
| 1415 | assert(!"Texel weight grid height should be smaller than block height"); | ||
| 1416 | FillError(outBuf, blockWidth, blockHeight); | ||
| 1417 | return; | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | // Read num partitions | ||
| 1421 | uint32_t nPartitions = strm.ReadBits(2) + 1; | ||
| 1422 | assert(nPartitions <= 4); | ||
| 1423 | |||
| 1424 | if (nPartitions == 4 && weightParams.m_bDualPlane) { | ||
| 1425 | assert(!"Dual plane mode is incompatible with four partition blocks"); | ||
| 1426 | FillError(outBuf, blockWidth, blockHeight); | ||
| 1427 | return; | ||
| 1428 | } | ||
| 1429 | |||
| 1430 | // Based on the number of partitions, read the color endpoint mode for | ||
| 1431 | // each partition. | ||
| 1432 | |||
| 1433 | // Determine partitions, partition index, and color endpoint modes | ||
| 1434 | int32_t planeIdx = -1; | ||
| 1435 | uint32_t partitionIndex; | ||
| 1436 | uint32_t colorEndpointMode[4] = {0, 0, 0, 0}; | ||
| 1437 | |||
| 1438 | // Define color data. | ||
| 1439 | uint8_t colorEndpointData[16]; | ||
| 1440 | memset(colorEndpointData, 0, sizeof(colorEndpointData)); | ||
| 1441 | BitStream colorEndpointStream(colorEndpointData, 16 * 8, 0); | ||
| 1442 | |||
| 1443 | // Read extra config data... | ||
| 1444 | uint32_t baseCEM = 0; | ||
| 1445 | if (nPartitions == 1) { | ||
| 1446 | colorEndpointMode[0] = strm.ReadBits(4); | ||
| 1447 | partitionIndex = 0; | ||
| 1448 | } else { | ||
| 1449 | partitionIndex = strm.ReadBits(10); | ||
| 1450 | baseCEM = strm.ReadBits(6); | ||
| 1451 | } | ||
| 1452 | uint32_t baseMode = (baseCEM & 3); | ||
| 1453 | |||
| 1454 | // Remaining bits are color endpoint data... | ||
| 1455 | uint32_t nWeightBits = weightParams.GetPackedBitSize(); | ||
| 1456 | int32_t remainingBits = 128 - nWeightBits - strm.GetBitsRead(); | ||
| 1457 | |||
| 1458 | // Consider extra bits prior to texel data... | ||
| 1459 | uint32_t extraCEMbits = 0; | ||
| 1460 | if (baseMode) { | ||
| 1461 | switch (nPartitions) { | ||
| 1462 | case 2: | ||
| 1463 | extraCEMbits += 2; | ||
| 1464 | break; | ||
| 1465 | case 3: | ||
| 1466 | extraCEMbits += 5; | ||
| 1467 | break; | ||
| 1468 | case 4: | ||
| 1469 | extraCEMbits += 8; | ||
| 1470 | break; | ||
| 1471 | default: | ||
| 1472 | assert(false); | ||
| 1473 | break; | ||
| 1474 | } | ||
| 1475 | } | ||
| 1476 | remainingBits -= extraCEMbits; | ||
| 1477 | |||
| 1478 | // Do we have a dual plane situation? | ||
| 1479 | uint32_t planeSelectorBits = 0; | ||
| 1480 | if (weightParams.m_bDualPlane) { | ||
| 1481 | planeSelectorBits = 2; | ||
| 1482 | } | ||
| 1483 | remainingBits -= planeSelectorBits; | ||
| 1484 | |||
| 1485 | // Read color data... | ||
| 1486 | uint32_t colorDataBits = remainingBits; | ||
| 1487 | while (remainingBits > 0) { | ||
| 1488 | uint32_t nb = std::min(remainingBits, 8); | ||
| 1489 | uint32_t b = strm.ReadBits(nb); | ||
| 1490 | colorEndpointStream.WriteBits(b, nb); | ||
| 1491 | remainingBits -= 8; | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | // Read the plane selection bits | ||
| 1495 | planeIdx = strm.ReadBits(planeSelectorBits); | ||
| 1496 | |||
| 1497 | // Read the rest of the CEM | ||
| 1498 | if (baseMode) { | ||
| 1499 | uint32_t extraCEM = strm.ReadBits(extraCEMbits); | ||
| 1500 | uint32_t CEM = (extraCEM << 6) | baseCEM; | ||
| 1501 | CEM >>= 2; | ||
| 1502 | |||
| 1503 | bool C[4] = {0}; | ||
| 1504 | for (uint32_t i = 0; i < nPartitions; i++) { | ||
| 1505 | C[i] = CEM & 1; | ||
| 1506 | CEM >>= 1; | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | uint8_t M[4] = {0}; | ||
| 1510 | for (uint32_t i = 0; i < nPartitions; i++) { | ||
| 1511 | M[i] = CEM & 3; | ||
| 1512 | CEM >>= 2; | ||
| 1513 | assert(M[i] <= 3); | ||
| 1514 | } | ||
| 1515 | |||
| 1516 | for (uint32_t i = 0; i < nPartitions; i++) { | ||
| 1517 | colorEndpointMode[i] = baseMode; | ||
| 1518 | if (!(C[i])) | ||
| 1519 | colorEndpointMode[i] -= 1; | ||
| 1520 | colorEndpointMode[i] <<= 2; | ||
| 1521 | colorEndpointMode[i] |= M[i]; | ||
| 1522 | } | ||
| 1523 | } else if (nPartitions > 1) { | ||
| 1524 | uint32_t CEM = baseCEM >> 2; | ||
| 1525 | for (uint32_t i = 0; i < nPartitions; i++) { | ||
| 1526 | colorEndpointMode[i] = CEM; | ||
| 1527 | } | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | // Make sure everything up till here is sane. | ||
| 1531 | for (uint32_t i = 0; i < nPartitions; i++) { | ||
| 1532 | assert(colorEndpointMode[i] < 16); | ||
| 1533 | } | ||
| 1534 | assert(strm.GetBitsRead() + weightParams.GetPackedBitSize() == 128); | ||
| 1535 | |||
| 1536 | // Decode both color data and texel weight data | ||
| 1537 | uint32_t colorValues[32]; // Four values, two endpoints, four maximum paritions | ||
| 1538 | DecodeColorValues(colorValues, colorEndpointData, colorEndpointMode, nPartitions, | ||
| 1539 | colorDataBits); | ||
| 1540 | |||
| 1541 | Pixel endpoints[4][2]; | ||
| 1542 | const uint32_t* colorValuesPtr = colorValues; | ||
| 1543 | for (uint32_t i = 0; i < nPartitions; i++) { | ||
| 1544 | ComputeEndpoints(endpoints[i][0], endpoints[i][1], colorValuesPtr, colorEndpointMode[i]); | ||
| 1545 | } | ||
| 1546 | |||
| 1547 | // Read the texel weight data.. | ||
| 1548 | uint8_t texelWeightData[16]; | ||
| 1549 | memcpy(texelWeightData, inBuf, sizeof(texelWeightData)); | ||
| 1550 | |||
| 1551 | // Reverse everything | ||
| 1552 | for (uint32_t i = 0; i < 8; i++) { | ||
| 1553 | // Taken from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits | ||
| 1554 | #define REVERSE_BYTE(b) (((b)*0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32 | ||
| 1555 | unsigned char a = static_cast<unsigned char>(REVERSE_BYTE(texelWeightData[i])); | ||
| 1556 | unsigned char b = static_cast<unsigned char>(REVERSE_BYTE(texelWeightData[15 - i])); | ||
| 1557 | #undef REVERSE_BYTE | ||
| 1558 | |||
| 1559 | texelWeightData[i] = b; | ||
| 1560 | texelWeightData[15 - i] = a; | ||
| 1561 | } | ||
| 1562 | |||
| 1563 | // Make sure that higher non-texel bits are set to zero | ||
| 1564 | const uint32_t clearByteStart = (weightParams.GetPackedBitSize() >> 3) + 1; | ||
| 1565 | texelWeightData[clearByteStart - 1] &= (1 << (weightParams.GetPackedBitSize() % 8)) - 1; | ||
| 1566 | memset(texelWeightData + clearByteStart, 0, 16 - clearByteStart); | ||
| 1567 | |||
| 1568 | std::vector<IntegerEncodedValue> texelWeightValues; | ||
| 1569 | BitStream weightStream(texelWeightData); | ||
| 1570 | |||
| 1571 | IntegerEncodedValue::DecodeIntegerSequence(texelWeightValues, weightStream, | ||
| 1572 | weightParams.m_MaxWeight, | ||
| 1573 | weightParams.GetNumWeightValues()); | ||
| 1574 | |||
| 1575 | // Blocks can be at most 12x12, so we can have as many as 144 weights | ||
| 1576 | uint32_t weights[2][144]; | ||
| 1577 | UnquantizeTexelWeights(weights, texelWeightValues, weightParams, blockWidth, blockHeight); | ||
| 1578 | |||
| 1579 | // Now that we have endpoints and weights, we can interpolate and generate | ||
| 1580 | // the proper decoding... | ||
| 1581 | for (uint32_t j = 0; j < blockHeight; j++) | ||
| 1582 | for (uint32_t i = 0; i < blockWidth; i++) { | ||
| 1583 | uint32_t partition = Select2DPartition(partitionIndex, i, j, nPartitions, | ||
| 1584 | (blockHeight * blockWidth) < 32); | ||
| 1585 | assert(partition < nPartitions); | ||
| 1586 | |||
| 1587 | Pixel p; | ||
| 1588 | for (uint32_t c = 0; c < 4; c++) { | ||
| 1589 | uint32_t C0 = endpoints[partition][0].Component(c); | ||
| 1590 | C0 = Replicate(C0, 8, 16); | ||
| 1591 | uint32_t C1 = endpoints[partition][1].Component(c); | ||
| 1592 | C1 = Replicate(C1, 8, 16); | ||
| 1593 | |||
| 1594 | uint32_t plane = 0; | ||
| 1595 | if (weightParams.m_bDualPlane && (((planeIdx + 1) & 3) == c)) { | ||
| 1596 | plane = 1; | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | uint32_t weight = weights[plane][j * blockWidth + i]; | ||
| 1600 | uint32_t C = (C0 * (64 - weight) + C1 * weight + 32) / 64; | ||
| 1601 | if (C == 65535) { | ||
| 1602 | p.Component(c) = 255; | ||
| 1603 | } else { | ||
| 1604 | double Cf = static_cast<double>(C); | ||
| 1605 | p.Component(c) = static_cast<uint16_t>(255.0 * (Cf / 65536.0) + 0.5); | ||
| 1606 | } | ||
| 1607 | } | ||
| 1608 | |||
| 1609 | outBuf[j * blockWidth + i] = p.Pack(); | ||
| 1610 | } | ||
| 1611 | } | ||
| 1612 | |||
| 1613 | } // namespace ASTCC | ||
| 1614 | |||
| 1615 | namespace Tegra::Texture::ASTC { | ||
| 1616 | |||
| 1617 | std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height, | ||
| 1618 | uint32_t block_width, uint32_t block_height) { | ||
| 1619 | uint32_t blockIdx = 0; | ||
| 1620 | std::vector<uint8_t> outData; | ||
| 1621 | outData.resize(height * width * 4); | ||
| 1622 | for (uint32_t j = 0; j < height; j += block_height) { | ||
| 1623 | for (uint32_t i = 0; i < width; i += block_width) { | ||
| 1624 | |||
| 1625 | uint8_t* blockPtr = data.data() + blockIdx * 16; | ||
| 1626 | |||
| 1627 | // Blocks can be at most 12x12 | ||
| 1628 | uint32_t uncompData[144]; | ||
| 1629 | ASTCC::DecompressBlock(blockPtr, block_width, block_height, uncompData); | ||
| 1630 | |||
| 1631 | uint32_t decompWidth = std::min(block_width, width - i); | ||
| 1632 | uint32_t decompHeight = std::min(block_height, height - j); | ||
| 1633 | |||
| 1634 | uint8_t* outRow = outData.data() + (j * width + i) * 4; | ||
| 1635 | for (uint32_t jj = 0; jj < decompHeight; jj++) { | ||
| 1636 | memcpy(outRow + jj * width * 4, uncompData + jj * block_width, decompWidth * 4); | ||
| 1637 | } | ||
| 1638 | |||
| 1639 | blockIdx++; | ||
| 1640 | } | ||
| 1641 | } | ||
| 1642 | |||
| 1643 | return outData; | ||
| 1644 | } | ||
| 1645 | |||
| 1646 | } // namespace Tegra::Texture::ASTC | ||
diff --git a/src/video_core/textures/astc.h b/src/video_core/textures/astc.h new file mode 100644 index 000000000..f0d7c0e56 --- /dev/null +++ b/src/video_core/textures/astc.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstdint> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | namespace Tegra::Texture::ASTC { | ||
| 11 | |||
| 12 | std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height, | ||
| 13 | uint32_t block_width, uint32_t block_height); | ||
| 14 | |||
| 15 | } // namespace Tegra::Texture::ASTC | ||
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 7bf9c4c4b..b3937b2fe 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "core/memory.h" | 7 | #include "core/memory.h" |
| 8 | #include "video_core/gpu.h" | ||
| 8 | #include "video_core/textures/decoders.h" | 9 | #include "video_core/textures/decoders.h" |
| 9 | #include "video_core/textures/texture.h" | 10 | #include "video_core/textures/texture.h" |
| 10 | 11 | ||
| @@ -51,8 +52,10 @@ u32 BytesPerPixel(TextureFormat format) { | |||
| 51 | return 8; | 52 | return 8; |
| 52 | case TextureFormat::DXT23: | 53 | case TextureFormat::DXT23: |
| 53 | case TextureFormat::DXT45: | 54 | case TextureFormat::DXT45: |
| 55 | case TextureFormat::BC7U: | ||
| 54 | // In this case a 'pixel' actually refers to a 4x4 tile. | 56 | // In this case a 'pixel' actually refers to a 4x4 tile. |
| 55 | return 16; | 57 | return 16; |
| 58 | case TextureFormat::ASTC_2D_4X4: | ||
| 56 | case TextureFormat::A8R8G8B8: | 59 | case TextureFormat::A8R8G8B8: |
| 57 | case TextureFormat::A2B10G10R10: | 60 | case TextureFormat::A2B10G10R10: |
| 58 | case TextureFormat::BF10GF11RF11: | 61 | case TextureFormat::BF10GF11RF11: |
| @@ -64,6 +67,20 @@ u32 BytesPerPixel(TextureFormat format) { | |||
| 64 | return 1; | 67 | return 1; |
| 65 | case TextureFormat::R16_G16_B16_A16: | 68 | case TextureFormat::R16_G16_B16_A16: |
| 66 | return 8; | 69 | return 8; |
| 70 | case TextureFormat::R32_G32_B32_A32: | ||
| 71 | return 16; | ||
| 72 | default: | ||
| 73 | UNIMPLEMENTED_MSG("Format not implemented"); | ||
| 74 | break; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | static u32 DepthBytesPerPixel(DepthFormat format) { | ||
| 79 | switch (format) { | ||
| 80 | case DepthFormat::S8_Z24_UNORM: | ||
| 81 | case DepthFormat::Z24_S8_UNORM: | ||
| 82 | case DepthFormat::Z32_FLOAT: | ||
| 83 | return 4; | ||
| 67 | default: | 84 | default: |
| 68 | UNIMPLEMENTED_MSG("Format not implemented"); | 85 | UNIMPLEMENTED_MSG("Format not implemented"); |
| 69 | break; | 86 | break; |
| @@ -82,6 +99,7 @@ std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, | |||
| 82 | case TextureFormat::DXT23: | 99 | case TextureFormat::DXT23: |
| 83 | case TextureFormat::DXT45: | 100 | case TextureFormat::DXT45: |
| 84 | case TextureFormat::DXN1: | 101 | case TextureFormat::DXN1: |
| 102 | case TextureFormat::BC7U: | ||
| 85 | // In the DXT and DXN formats, each 4x4 tile is swizzled instead of just individual pixel | 103 | // In the DXT and DXN formats, each 4x4 tile is swizzled instead of just individual pixel |
| 86 | // values. | 104 | // values. |
| 87 | CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data, | 105 | CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data, |
| @@ -93,7 +111,31 @@ std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, | |||
| 93 | case TextureFormat::B5G6R5: | 111 | case TextureFormat::B5G6R5: |
| 94 | case TextureFormat::R8: | 112 | case TextureFormat::R8: |
| 95 | case TextureFormat::R16_G16_B16_A16: | 113 | case TextureFormat::R16_G16_B16_A16: |
| 114 | case TextureFormat::R32_G32_B32_A32: | ||
| 96 | case TextureFormat::BF10GF11RF11: | 115 | case TextureFormat::BF10GF11RF11: |
| 116 | case TextureFormat::ASTC_2D_4X4: | ||
| 117 | CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, | ||
| 118 | unswizzled_data.data(), true, block_height); | ||
| 119 | break; | ||
| 120 | default: | ||
| 121 | UNIMPLEMENTED_MSG("Format not implemented"); | ||
| 122 | break; | ||
| 123 | } | ||
| 124 | |||
| 125 | return unswizzled_data; | ||
| 126 | } | ||
| 127 | |||
| 128 | std::vector<u8> UnswizzleDepthTexture(VAddr address, DepthFormat format, u32 width, u32 height, | ||
| 129 | u32 block_height) { | ||
| 130 | u8* data = Memory::GetPointer(address); | ||
| 131 | u32 bytes_per_pixel = DepthBytesPerPixel(format); | ||
| 132 | |||
| 133 | std::vector<u8> unswizzled_data(width * height * bytes_per_pixel); | ||
| 134 | |||
| 135 | switch (format) { | ||
| 136 | case DepthFormat::S8_Z24_UNORM: | ||
| 137 | case DepthFormat::Z24_S8_UNORM: | ||
| 138 | case DepthFormat::Z32_FLOAT: | ||
| 97 | CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, | 139 | CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, |
| 98 | unswizzled_data.data(), true, block_height); | 140 | unswizzled_data.data(), true, block_height); |
| 99 | break; | 141 | break; |
| @@ -115,12 +157,15 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat | |||
| 115 | case TextureFormat::DXT23: | 157 | case TextureFormat::DXT23: |
| 116 | case TextureFormat::DXT45: | 158 | case TextureFormat::DXT45: |
| 117 | case TextureFormat::DXN1: | 159 | case TextureFormat::DXN1: |
| 160 | case TextureFormat::BC7U: | ||
| 161 | case TextureFormat::ASTC_2D_4X4: | ||
| 118 | case TextureFormat::A8R8G8B8: | 162 | case TextureFormat::A8R8G8B8: |
| 119 | case TextureFormat::A2B10G10R10: | 163 | case TextureFormat::A2B10G10R10: |
| 120 | case TextureFormat::A1B5G5R5: | 164 | case TextureFormat::A1B5G5R5: |
| 121 | case TextureFormat::B5G6R5: | 165 | case TextureFormat::B5G6R5: |
| 122 | case TextureFormat::R8: | 166 | case TextureFormat::R8: |
| 123 | case TextureFormat::BF10GF11RF11: | 167 | case TextureFormat::BF10GF11RF11: |
| 168 | case TextureFormat::R32_G32_B32_A32: | ||
| 124 | // TODO(Subv): For the time being just forward the same data without any decoding. | 169 | // TODO(Subv): For the time being just forward the same data without any decoding. |
| 125 | rgba_data = texture_data; | 170 | rgba_data = texture_data; |
| 126 | break; | 171 | break; |
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index 2562c4b06..2b088c077 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h | |||
| @@ -17,6 +17,12 @@ namespace Texture { | |||
| 17 | std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height, | 17 | std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height, |
| 18 | u32 block_height = TICEntry::DefaultBlockHeight); | 18 | u32 block_height = TICEntry::DefaultBlockHeight); |
| 19 | 19 | ||
| 20 | /** | ||
| 21 | * Unswizzles a swizzled depth texture without changing its format. | ||
| 22 | */ | ||
| 23 | std::vector<u8> UnswizzleDepthTexture(VAddr address, DepthFormat format, u32 width, u32 height, | ||
| 24 | u32 block_height = TICEntry::DefaultBlockHeight); | ||
| 25 | |||
| 20 | /// Copies texture data from a buffer and performs swizzling/unswizzling as necessary. | 26 | /// Copies texture data from a buffer and performs swizzling/unswizzling as necessary. |
| 21 | void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, | 27 | void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, |
| 22 | u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height); | 28 | u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height); |
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 89dc8ed1e..289140f31 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp | |||
| @@ -24,9 +24,9 @@ bool Init(EmuWindow* emu_window) { | |||
| 24 | g_renderer = std::make_unique<RendererOpenGL>(); | 24 | g_renderer = std::make_unique<RendererOpenGL>(); |
| 25 | g_renderer->SetWindow(g_emu_window); | 25 | g_renderer->SetWindow(g_emu_window); |
| 26 | if (g_renderer->Init()) { | 26 | if (g_renderer->Init()) { |
| 27 | NGLOG_DEBUG(Render, "initialized OK"); | 27 | LOG_DEBUG(Render, "initialized OK"); |
| 28 | } else { | 28 | } else { |
| 29 | NGLOG_CRITICAL(Render, "initialization failed !"); | 29 | LOG_CRITICAL(Render, "initialization failed !"); |
| 30 | return false; | 30 | return false; |
| 31 | } | 31 | } |
| 32 | return true; | 32 | return true; |
| @@ -36,7 +36,7 @@ bool Init(EmuWindow* emu_window) { | |||
| 36 | void Shutdown() { | 36 | void Shutdown() { |
| 37 | g_renderer.reset(); | 37 | g_renderer.reset(); |
| 38 | 38 | ||
| 39 | NGLOG_DEBUG(Render, "shutdown OK"); | 39 | LOG_DEBUG(Render, "shutdown OK"); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | } // namespace VideoCore | 42 | } // namespace VideoCore |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 5af3154d7..7de919a8e 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -30,10 +30,10 @@ add_executable(yuzu | |||
| 30 | debugger/graphics/graphics_breakpoints_p.h | 30 | debugger/graphics/graphics_breakpoints_p.h |
| 31 | debugger/graphics/graphics_surface.cpp | 31 | debugger/graphics/graphics_surface.cpp |
| 32 | debugger/graphics/graphics_surface.h | 32 | debugger/graphics/graphics_surface.h |
| 33 | debugger/console.cpp | ||
| 34 | debugger/console.h | ||
| 33 | debugger/profiler.cpp | 35 | debugger/profiler.cpp |
| 34 | debugger/profiler.h | 36 | debugger/profiler.h |
| 35 | debugger/registers.cpp | ||
| 36 | debugger/registers.h | ||
| 37 | debugger/wait_tree.cpp | 37 | debugger/wait_tree.cpp |
| 38 | debugger/wait_tree.h | 38 | debugger/wait_tree.h |
| 39 | game_list.cpp | 39 | game_list.cpp |
| @@ -60,7 +60,6 @@ set(UIS | |||
| 60 | configuration/configure_graphics.ui | 60 | configuration/configure_graphics.ui |
| 61 | configuration/configure_input.ui | 61 | configuration/configure_input.ui |
| 62 | configuration/configure_system.ui | 62 | configuration/configure_system.ui |
| 63 | debugger/registers.ui | ||
| 64 | hotkeys.ui | 63 | hotkeys.ui |
| 65 | main.ui | 64 | main.ui |
| 66 | ) | 65 | ) |
| @@ -84,6 +83,14 @@ if (APPLE) | |||
| 84 | target_sources(yuzu PRIVATE ${MACOSX_ICON}) | 83 | target_sources(yuzu PRIVATE ${MACOSX_ICON}) |
| 85 | set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE) | 84 | set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE) |
| 86 | set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) | 85 | set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) |
| 86 | elseif(WIN32) | ||
| 87 | # compile as a win32 gui application instead of a console application | ||
| 88 | target_link_libraries(yuzu PRIVATE Qt5::WinMain) | ||
| 89 | if(MSVC) | ||
| 90 | set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") | ||
| 91 | elseif(MINGW) | ||
| 92 | set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "-mwindows") | ||
| 93 | endif() | ||
| 87 | endif() | 94 | endif() |
| 88 | 95 | ||
| 89 | create_target_directory_groups(yuzu) | 96 | create_target_directory_groups(yuzu) |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 5c17cd0d9..833085559 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -127,13 +127,14 @@ void GRenderWindow::moveContext() { | |||
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | void GRenderWindow::SwapBuffers() { | 129 | void GRenderWindow::SwapBuffers() { |
| 130 | #if !defined(QT_NO_DEBUG) | 130 | // In our multi-threaded QGLWidget use case we shouldn't need to call `makeCurrent`, |
| 131 | // Qt debug runtime prints a bogus warning on the console if you haven't called makeCurrent | 131 | // since we never call `doneCurrent` in this thread. |
| 132 | // since the last time you called swapBuffers. This presumably means something if you're using | 132 | // However: |
| 133 | // QGLWidget the "regular" way, but in our multi-threaded use case is harmless since we never | 133 | // - The Qt debug runtime prints a bogus warning on the console if `makeCurrent` wasn't called |
| 134 | // call doneCurrent in this thread. | 134 | // since the last time `swapBuffers` was executed; |
| 135 | // - On macOS, if `makeCurrent` isn't called explicitely, resizing the buffer breaks. | ||
| 135 | child->makeCurrent(); | 136 | child->makeCurrent(); |
| 136 | #endif | 137 | |
| 137 | child->swapBuffers(); | 138 | child->swapBuffers(); |
| 138 | } | 139 | } |
| 139 | 140 | ||
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 8316db708..a32134fbe 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -84,6 +84,8 @@ void Config::ReadValues() { | |||
| 84 | qt_config->beginGroup("Renderer"); | 84 | qt_config->beginGroup("Renderer"); |
| 85 | Settings::values.resolution_factor = qt_config->value("resolution_factor", 1.0).toFloat(); | 85 | Settings::values.resolution_factor = qt_config->value("resolution_factor", 1.0).toFloat(); |
| 86 | Settings::values.toggle_framelimit = qt_config->value("toggle_framelimit", true).toBool(); | 86 | Settings::values.toggle_framelimit = qt_config->value("toggle_framelimit", true).toBool(); |
| 87 | Settings::values.use_accurate_framebuffers = | ||
| 88 | qt_config->value("use_accurate_framebuffers", false).toBool(); | ||
| 87 | 89 | ||
| 88 | Settings::values.bg_red = qt_config->value("bg_red", 0.0).toFloat(); | 90 | Settings::values.bg_red = qt_config->value("bg_red", 0.0).toFloat(); |
| 89 | Settings::values.bg_green = qt_config->value("bg_green", 0.0).toFloat(); | 91 | Settings::values.bg_green = qt_config->value("bg_green", 0.0).toFloat(); |
| @@ -158,6 +160,7 @@ void Config::ReadValues() { | |||
| 158 | UISettings::values.confirm_before_closing = qt_config->value("confirmClose", true).toBool(); | 160 | UISettings::values.confirm_before_closing = qt_config->value("confirmClose", true).toBool(); |
| 159 | UISettings::values.first_start = qt_config->value("firstStart", true).toBool(); | 161 | UISettings::values.first_start = qt_config->value("firstStart", true).toBool(); |
| 160 | UISettings::values.callout_flags = qt_config->value("calloutFlags", 0).toUInt(); | 162 | UISettings::values.callout_flags = qt_config->value("calloutFlags", 0).toUInt(); |
| 163 | UISettings::values.show_console = qt_config->value("showConsole", false).toBool(); | ||
| 161 | 164 | ||
| 162 | qt_config->endGroup(); | 165 | qt_config->endGroup(); |
| 163 | } | 166 | } |
| @@ -184,6 +187,7 @@ void Config::SaveValues() { | |||
| 184 | qt_config->beginGroup("Renderer"); | 187 | qt_config->beginGroup("Renderer"); |
| 185 | qt_config->setValue("resolution_factor", (double)Settings::values.resolution_factor); | 188 | qt_config->setValue("resolution_factor", (double)Settings::values.resolution_factor); |
| 186 | qt_config->setValue("toggle_framelimit", Settings::values.toggle_framelimit); | 189 | qt_config->setValue("toggle_framelimit", Settings::values.toggle_framelimit); |
| 190 | qt_config->setValue("use_accurate_framebuffers", Settings::values.use_accurate_framebuffers); | ||
| 187 | 191 | ||
| 188 | // Cast to double because Qt's written float values are not human-readable | 192 | // Cast to double because Qt's written float values are not human-readable |
| 189 | qt_config->setValue("bg_red", (double)Settings::values.bg_red); | 193 | qt_config->setValue("bg_red", (double)Settings::values.bg_red); |
| @@ -243,7 +247,7 @@ void Config::SaveValues() { | |||
| 243 | qt_config->setValue("confirmClose", UISettings::values.confirm_before_closing); | 247 | qt_config->setValue("confirmClose", UISettings::values.confirm_before_closing); |
| 244 | qt_config->setValue("firstStart", UISettings::values.first_start); | 248 | qt_config->setValue("firstStart", UISettings::values.first_start); |
| 245 | qt_config->setValue("calloutFlags", UISettings::values.callout_flags); | 249 | qt_config->setValue("calloutFlags", UISettings::values.callout_flags); |
| 246 | 250 | qt_config->setValue("showConsole", UISettings::values.show_console); | |
| 247 | qt_config->endGroup(); | 251 | qt_config->endGroup(); |
| 248 | } | 252 | } |
| 249 | 253 | ||
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index a45edd510..241db4ae3 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp | |||
| @@ -2,13 +2,26 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <QDesktopServices> | ||
| 6 | #include <QUrl> | ||
| 7 | #include "common/file_util.h" | ||
| 8 | #include "common/logging/backend.h" | ||
| 9 | #include "common/logging/filter.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "core/core.h" | ||
| 5 | #include "core/settings.h" | 12 | #include "core/settings.h" |
| 6 | #include "ui_configure_debug.h" | 13 | #include "ui_configure_debug.h" |
| 7 | #include "yuzu/configuration/configure_debug.h" | 14 | #include "yuzu/configuration/configure_debug.h" |
| 15 | #include "yuzu/debugger/console.h" | ||
| 16 | #include "yuzu/ui_settings.h" | ||
| 8 | 17 | ||
| 9 | ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureDebug) { | 18 | ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureDebug) { |
| 10 | ui->setupUi(this); | 19 | ui->setupUi(this); |
| 11 | this->setConfiguration(); | 20 | this->setConfiguration(); |
| 21 | connect(ui->open_log_button, &QPushButton::pressed, []() { | ||
| 22 | QString path = QString::fromStdString(FileUtil::GetUserPath(D_LOGS_IDX)); | ||
| 23 | QDesktopServices::openUrl(QUrl::fromLocalFile(path)); | ||
| 24 | }); | ||
| 12 | } | 25 | } |
| 13 | 26 | ||
| 14 | ConfigureDebug::~ConfigureDebug() {} | 27 | ConfigureDebug::~ConfigureDebug() {} |
| @@ -17,10 +30,19 @@ void ConfigureDebug::setConfiguration() { | |||
| 17 | ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub); | 30 | ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub); |
| 18 | ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub); | 31 | ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub); |
| 19 | ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port); | 32 | ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port); |
| 33 | ui->toggle_console->setEnabled(!Core::System::GetInstance().IsPoweredOn()); | ||
| 34 | ui->toggle_console->setChecked(UISettings::values.show_console); | ||
| 35 | ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); | ||
| 20 | } | 36 | } |
| 21 | 37 | ||
| 22 | void ConfigureDebug::applyConfiguration() { | 38 | void ConfigureDebug::applyConfiguration() { |
| 23 | Settings::values.use_gdbstub = ui->toggle_gdbstub->isChecked(); | 39 | Settings::values.use_gdbstub = ui->toggle_gdbstub->isChecked(); |
| 24 | Settings::values.gdbstub_port = ui->gdbport_spinbox->value(); | 40 | Settings::values.gdbstub_port = ui->gdbport_spinbox->value(); |
| 41 | UISettings::values.show_console = ui->toggle_console->isChecked(); | ||
| 42 | Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); | ||
| 43 | Debugger::ToggleConsole(); | ||
| 44 | Log::Filter filter; | ||
| 45 | filter.ParseFilterString(Settings::values.log_filter); | ||
| 46 | Log::SetGlobalFilter(filter); | ||
| 25 | Settings::Apply(); | 47 | Settings::Apply(); |
| 26 | } | 48 | } |
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index a10bea2f4..118e91cf1 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui | |||
| @@ -73,6 +73,47 @@ | |||
| 73 | </layout> | 73 | </layout> |
| 74 | </item> | 74 | </item> |
| 75 | <item> | 75 | <item> |
| 76 | <widget class="QGroupBox" name="groupBox_2"> | ||
| 77 | <property name="title"> | ||
| 78 | <string>Logging</string> | ||
| 79 | </property> | ||
| 80 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
| 81 | <item> | ||
| 82 | <layout class="QHBoxLayout" name="horizontalLayout"> | ||
| 83 | <item> | ||
| 84 | <widget class="QLabel" name="label"> | ||
| 85 | <property name="text"> | ||
| 86 | <string>Global Log Filter</string> | ||
| 87 | </property> | ||
| 88 | </widget> | ||
| 89 | </item> | ||
| 90 | <item> | ||
| 91 | <widget class="QLineEdit" name="log_filter_edit"/> | ||
| 92 | </item> | ||
| 93 | </layout> | ||
| 94 | </item> | ||
| 95 | <item> | ||
| 96 | <layout class="QHBoxLayout" name="horizontalLayout_2"> | ||
| 97 | <item> | ||
| 98 | <widget class="QCheckBox" name="toggle_console"> | ||
| 99 | <property name="text"> | ||
| 100 | <string>Show Log Console (Windows Only)</string> | ||
| 101 | </property> | ||
| 102 | </widget> | ||
| 103 | </item> | ||
| 104 | <item> | ||
| 105 | <widget class="QPushButton" name="open_log_button"> | ||
| 106 | <property name="text"> | ||
| 107 | <string>Open Log Location</string> | ||
| 108 | </property> | ||
| 109 | </widget> | ||
| 110 | </item> | ||
| 111 | </layout> | ||
| 112 | </item> | ||
| 113 | </layout> | ||
| 114 | </widget> | ||
| 115 | </item> | ||
| 116 | <item> | ||
| 76 | <spacer name="verticalSpacer"> | 117 | <spacer name="verticalSpacer"> |
| 77 | <property name="orientation"> | 118 | <property name="orientation"> |
| 78 | <enum>Qt::Vertical</enum> | 119 | <enum>Qt::Vertical</enum> |
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 47b9b6e95..7664880d5 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -59,11 +59,13 @@ void ConfigureGraphics::setConfiguration() { | |||
| 59 | ui->resolution_factor_combobox->setCurrentIndex( | 59 | ui->resolution_factor_combobox->setCurrentIndex( |
| 60 | static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor))); | 60 | static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor))); |
| 61 | ui->toggle_framelimit->setChecked(Settings::values.toggle_framelimit); | 61 | ui->toggle_framelimit->setChecked(Settings::values.toggle_framelimit); |
| 62 | ui->use_accurate_framebuffers->setChecked(Settings::values.use_accurate_framebuffers); | ||
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | void ConfigureGraphics::applyConfiguration() { | 65 | void ConfigureGraphics::applyConfiguration() { |
| 65 | Settings::values.resolution_factor = | 66 | Settings::values.resolution_factor = |
| 66 | ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex())); | 67 | ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex())); |
| 67 | Settings::values.toggle_framelimit = ui->toggle_framelimit->isChecked(); | 68 | Settings::values.toggle_framelimit = ui->toggle_framelimit->isChecked(); |
| 69 | Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked(); | ||
| 68 | Settings::Apply(); | 70 | Settings::Apply(); |
| 69 | } | 71 | } |
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 366931a9a..7d092df03 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui | |||
| @@ -30,6 +30,13 @@ | |||
| 30 | </widget> | 30 | </widget> |
| 31 | </item> | 31 | </item> |
| 32 | <item> | 32 | <item> |
| 33 | <widget class="QCheckBox" name="use_accurate_framebuffers"> | ||
| 34 | <property name="text"> | ||
| 35 | <string>Use accurate framebuffers (slow)</string> | ||
| 36 | </property> | ||
| 37 | </widget> | ||
| 38 | </item> | ||
| 39 | <item> | ||
| 33 | <layout class="QHBoxLayout" name="horizontalLayout"> | 40 | <layout class="QHBoxLayout" name="horizontalLayout"> |
| 34 | <item> | 41 | <item> |
| 35 | <widget class="QLabel" name="label"> | 42 | <widget class="QLabel" name="label"> |
diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp new file mode 100644 index 000000000..e3d2d975f --- /dev/null +++ b/src/yuzu/debugger/console.cpp | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #ifdef _WIN32 | ||
| 6 | #include <windows.h> | ||
| 7 | |||
| 8 | #include <wincon.h> | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #include "common/logging/backend.h" | ||
| 12 | #include "yuzu/debugger/console.h" | ||
| 13 | #include "yuzu/ui_settings.h" | ||
| 14 | |||
| 15 | namespace Debugger { | ||
| 16 | void ToggleConsole() { | ||
| 17 | #if defined(_WIN32) && !defined(_DEBUG) | ||
| 18 | FILE* temp; | ||
| 19 | if (UISettings::values.show_console) { | ||
| 20 | if (AllocConsole()) { | ||
| 21 | // The first parameter for freopen_s is a out parameter, so we can just ignore it | ||
| 22 | freopen_s(&temp, "CONIN$", "r", stdin); | ||
| 23 | freopen_s(&temp, "CONOUT$", "w", stdout); | ||
| 24 | freopen_s(&temp, "CONOUT$", "w", stderr); | ||
| 25 | Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); | ||
| 26 | } | ||
| 27 | } else { | ||
| 28 | if (FreeConsole()) { | ||
| 29 | // In order to close the console, we have to also detach the streams on it. | ||
| 30 | // Just redirect them to NUL if there is no console window | ||
| 31 | Log::RemoveBackend(Log::ColorConsoleBackend::Name()); | ||
| 32 | freopen_s(&temp, "NUL", "r", stdin); | ||
| 33 | freopen_s(&temp, "NUL", "w", stdout); | ||
| 34 | freopen_s(&temp, "NUL", "w", stderr); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | #else | ||
| 38 | if (UISettings::values.show_console) { | ||
| 39 | Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); | ||
| 40 | } else { | ||
| 41 | Log::RemoveBackend(Log::ColorConsoleBackend::Name()); | ||
| 42 | } | ||
| 43 | #endif | ||
| 44 | } | ||
| 45 | } // namespace Debugger | ||
diff --git a/src/yuzu/debugger/console.h b/src/yuzu/debugger/console.h new file mode 100644 index 000000000..d1990c496 --- /dev/null +++ b/src/yuzu/debugger/console.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Debugger { | ||
| 8 | |||
| 9 | /** | ||
| 10 | * Uses the WINAPI to hide or show the stderr console. This function is a placeholder until we can | ||
| 11 | * get a real qt logging window which would work for all platforms. | ||
| 12 | */ | ||
| 13 | void ToggleConsole(); | ||
| 14 | } // namespace Debugger \ No newline at end of file | ||
diff --git a/src/yuzu/debugger/registers.cpp b/src/yuzu/debugger/registers.cpp deleted file mode 100644 index 178cc65a7..000000000 --- a/src/yuzu/debugger/registers.cpp +++ /dev/null | |||
| @@ -1,190 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QTreeWidgetItem> | ||
| 6 | #include "core/arm/arm_interface.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "yuzu/debugger/registers.h" | ||
| 9 | #include "yuzu/util/util.h" | ||
| 10 | |||
| 11 | RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) { | ||
| 12 | cpu_regs_ui.setupUi(this); | ||
| 13 | |||
| 14 | tree = cpu_regs_ui.treeWidget; | ||
| 15 | tree->addTopLevelItem(core_registers = new QTreeWidgetItem(QStringList(tr("Registers")))); | ||
| 16 | tree->addTopLevelItem(vfp_registers = new QTreeWidgetItem(QStringList(tr("VFP Registers")))); | ||
| 17 | tree->addTopLevelItem(vfp_system_registers = | ||
| 18 | new QTreeWidgetItem(QStringList(tr("VFP System Registers")))); | ||
| 19 | tree->addTopLevelItem(cpsr = new QTreeWidgetItem(QStringList("CPSR"))); | ||
| 20 | |||
| 21 | for (int i = 0; i < 16; ++i) { | ||
| 22 | QTreeWidgetItem* child = new QTreeWidgetItem(QStringList(QString("R[%1]").arg(i))); | ||
| 23 | core_registers->addChild(child); | ||
| 24 | } | ||
| 25 | |||
| 26 | for (int i = 0; i < 32; ++i) { | ||
| 27 | QTreeWidgetItem* child = new QTreeWidgetItem(QStringList(QString("S[%1]").arg(i))); | ||
| 28 | vfp_registers->addChild(child); | ||
| 29 | } | ||
| 30 | |||
| 31 | QFont font = GetMonospaceFont(); | ||
| 32 | |||
| 33 | CreateCPSRChildren(); | ||
| 34 | CreateVFPSystemRegisterChildren(); | ||
| 35 | |||
| 36 | // Set Registers to display in monospace font | ||
| 37 | for (int i = 0; i < core_registers->childCount(); ++i) | ||
| 38 | core_registers->child(i)->setFont(1, font); | ||
| 39 | |||
| 40 | for (int i = 0; i < vfp_registers->childCount(); ++i) | ||
| 41 | vfp_registers->child(i)->setFont(1, font); | ||
| 42 | |||
| 43 | for (int i = 0; i < vfp_system_registers->childCount(); ++i) { | ||
| 44 | vfp_system_registers->child(i)->setFont(1, font); | ||
| 45 | for (int x = 0; x < vfp_system_registers->child(i)->childCount(); ++x) { | ||
| 46 | vfp_system_registers->child(i)->child(x)->setFont(1, font); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | // Set CSPR to display in monospace font | ||
| 50 | cpsr->setFont(1, font); | ||
| 51 | for (int i = 0; i < cpsr->childCount(); ++i) { | ||
| 52 | cpsr->child(i)->setFont(1, font); | ||
| 53 | for (int x = 0; x < cpsr->child(i)->childCount(); ++x) { | ||
| 54 | cpsr->child(i)->child(x)->setFont(1, font); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | setEnabled(false); | ||
| 58 | } | ||
| 59 | |||
| 60 | void RegistersWidget::OnDebugModeEntered() { | ||
| 61 | if (!Core::System::GetInstance().IsPoweredOn()) | ||
| 62 | return; | ||
| 63 | |||
| 64 | for (int i = 0; i < core_registers->childCount(); ++i) | ||
| 65 | core_registers->child(i)->setText( | ||
| 66 | 1, QString("0x%1").arg(Core::CurrentArmInterface().GetReg(i), 8, 16, QLatin1Char('0'))); | ||
| 67 | |||
| 68 | UpdateCPSRValues(); | ||
| 69 | } | ||
| 70 | |||
| 71 | void RegistersWidget::OnDebugModeLeft() {} | ||
| 72 | |||
| 73 | void RegistersWidget::OnEmulationStarting(EmuThread* emu_thread) { | ||
| 74 | setEnabled(true); | ||
| 75 | } | ||
| 76 | |||
| 77 | void RegistersWidget::OnEmulationStopping() { | ||
| 78 | // Reset widget text | ||
| 79 | for (int i = 0; i < core_registers->childCount(); ++i) | ||
| 80 | core_registers->child(i)->setText(1, QString("")); | ||
| 81 | |||
| 82 | for (int i = 0; i < vfp_registers->childCount(); ++i) | ||
| 83 | vfp_registers->child(i)->setText(1, QString("")); | ||
| 84 | |||
| 85 | for (int i = 0; i < cpsr->childCount(); ++i) | ||
| 86 | cpsr->child(i)->setText(1, QString("")); | ||
| 87 | |||
| 88 | cpsr->setText(1, QString("")); | ||
| 89 | |||
| 90 | // FPSCR | ||
| 91 | for (int i = 0; i < vfp_system_registers->child(0)->childCount(); ++i) | ||
| 92 | vfp_system_registers->child(0)->child(i)->setText(1, QString("")); | ||
| 93 | |||
| 94 | // FPEXC | ||
| 95 | for (int i = 0; i < vfp_system_registers->child(1)->childCount(); ++i) | ||
| 96 | vfp_system_registers->child(1)->child(i)->setText(1, QString("")); | ||
| 97 | |||
| 98 | vfp_system_registers->child(0)->setText(1, QString("")); | ||
| 99 | vfp_system_registers->child(1)->setText(1, QString("")); | ||
| 100 | vfp_system_registers->child(2)->setText(1, QString("")); | ||
| 101 | vfp_system_registers->child(3)->setText(1, QString("")); | ||
| 102 | |||
| 103 | setEnabled(false); | ||
| 104 | } | ||
| 105 | |||
| 106 | void RegistersWidget::CreateCPSRChildren() { | ||
| 107 | cpsr->addChild(new QTreeWidgetItem(QStringList("M"))); | ||
| 108 | cpsr->addChild(new QTreeWidgetItem(QStringList("T"))); | ||
| 109 | cpsr->addChild(new QTreeWidgetItem(QStringList("F"))); | ||
| 110 | cpsr->addChild(new QTreeWidgetItem(QStringList("I"))); | ||
| 111 | cpsr->addChild(new QTreeWidgetItem(QStringList("A"))); | ||
| 112 | cpsr->addChild(new QTreeWidgetItem(QStringList("E"))); | ||
| 113 | cpsr->addChild(new QTreeWidgetItem(QStringList("IT"))); | ||
| 114 | cpsr->addChild(new QTreeWidgetItem(QStringList("GE"))); | ||
| 115 | cpsr->addChild(new QTreeWidgetItem(QStringList("DNM"))); | ||
| 116 | cpsr->addChild(new QTreeWidgetItem(QStringList("J"))); | ||
| 117 | cpsr->addChild(new QTreeWidgetItem(QStringList("Q"))); | ||
| 118 | cpsr->addChild(new QTreeWidgetItem(QStringList("V"))); | ||
| 119 | cpsr->addChild(new QTreeWidgetItem(QStringList("C"))); | ||
| 120 | cpsr->addChild(new QTreeWidgetItem(QStringList("Z"))); | ||
| 121 | cpsr->addChild(new QTreeWidgetItem(QStringList("N"))); | ||
| 122 | } | ||
| 123 | |||
| 124 | void RegistersWidget::UpdateCPSRValues() { | ||
| 125 | const u32 cpsr_val = Core::CurrentArmInterface().GetCPSR(); | ||
| 126 | |||
| 127 | cpsr->setText(1, QString("0x%1").arg(cpsr_val, 8, 16, QLatin1Char('0'))); | ||
| 128 | cpsr->child(0)->setText( | ||
| 129 | 1, QString("b%1").arg(cpsr_val & 0x1F, 5, 2, QLatin1Char('0'))); // M - Mode | ||
| 130 | cpsr->child(1)->setText(1, QString::number((cpsr_val >> 5) & 1)); // T - State | ||
| 131 | cpsr->child(2)->setText(1, QString::number((cpsr_val >> 6) & 1)); // F - FIQ disable | ||
| 132 | cpsr->child(3)->setText(1, QString::number((cpsr_val >> 7) & 1)); // I - IRQ disable | ||
| 133 | cpsr->child(4)->setText(1, QString::number((cpsr_val >> 8) & 1)); // A - Imprecise abort | ||
| 134 | cpsr->child(5)->setText(1, QString::number((cpsr_val >> 9) & 1)); // E - Data endianness | ||
| 135 | cpsr->child(6)->setText(1, | ||
| 136 | QString::number((cpsr_val >> 10) & 0x3F)); // IT - If-Then state (DNM) | ||
| 137 | cpsr->child(7)->setText(1, | ||
| 138 | QString::number((cpsr_val >> 16) & 0xF)); // GE - Greater-than-or-Equal | ||
| 139 | cpsr->child(8)->setText(1, QString::number((cpsr_val >> 20) & 0xF)); // DNM - Do not modify | ||
| 140 | cpsr->child(9)->setText(1, QString::number((cpsr_val >> 24) & 1)); // J - Jazelle | ||
| 141 | cpsr->child(10)->setText(1, QString::number((cpsr_val >> 27) & 1)); // Q - Saturation | ||
| 142 | cpsr->child(11)->setText(1, QString::number((cpsr_val >> 28) & 1)); // V - Overflow | ||
| 143 | cpsr->child(12)->setText(1, QString::number((cpsr_val >> 29) & 1)); // C - Carry/Borrow/Extend | ||
| 144 | cpsr->child(13)->setText(1, QString::number((cpsr_val >> 30) & 1)); // Z - Zero | ||
| 145 | cpsr->child(14)->setText(1, QString::number((cpsr_val >> 31) & 1)); // N - Negative/Less than | ||
| 146 | } | ||
| 147 | |||
| 148 | void RegistersWidget::CreateVFPSystemRegisterChildren() { | ||
| 149 | QTreeWidgetItem* const fpscr = new QTreeWidgetItem(QStringList("FPSCR")); | ||
| 150 | fpscr->addChild(new QTreeWidgetItem(QStringList("IOC"))); | ||
| 151 | fpscr->addChild(new QTreeWidgetItem(QStringList("DZC"))); | ||
| 152 | fpscr->addChild(new QTreeWidgetItem(QStringList("OFC"))); | ||
| 153 | fpscr->addChild(new QTreeWidgetItem(QStringList("UFC"))); | ||
| 154 | fpscr->addChild(new QTreeWidgetItem(QStringList("IXC"))); | ||
| 155 | fpscr->addChild(new QTreeWidgetItem(QStringList("IDC"))); | ||
| 156 | fpscr->addChild(new QTreeWidgetItem(QStringList("IOE"))); | ||
| 157 | fpscr->addChild(new QTreeWidgetItem(QStringList("DZE"))); | ||
| 158 | fpscr->addChild(new QTreeWidgetItem(QStringList("OFE"))); | ||
| 159 | fpscr->addChild(new QTreeWidgetItem(QStringList("UFE"))); | ||
| 160 | fpscr->addChild(new QTreeWidgetItem(QStringList("IXE"))); | ||
| 161 | fpscr->addChild(new QTreeWidgetItem(QStringList("IDE"))); | ||
| 162 | fpscr->addChild(new QTreeWidgetItem(QStringList(tr("Vector Length")))); | ||
| 163 | fpscr->addChild(new QTreeWidgetItem(QStringList(tr("Vector Stride")))); | ||
| 164 | fpscr->addChild(new QTreeWidgetItem(QStringList(tr("Rounding Mode")))); | ||
| 165 | fpscr->addChild(new QTreeWidgetItem(QStringList("FZ"))); | ||
| 166 | fpscr->addChild(new QTreeWidgetItem(QStringList("DN"))); | ||
| 167 | fpscr->addChild(new QTreeWidgetItem(QStringList("V"))); | ||
| 168 | fpscr->addChild(new QTreeWidgetItem(QStringList("C"))); | ||
| 169 | fpscr->addChild(new QTreeWidgetItem(QStringList("Z"))); | ||
| 170 | fpscr->addChild(new QTreeWidgetItem(QStringList("N"))); | ||
| 171 | |||
| 172 | QTreeWidgetItem* const fpexc = new QTreeWidgetItem(QStringList("FPEXC")); | ||
| 173 | fpexc->addChild(new QTreeWidgetItem(QStringList("IOC"))); | ||
| 174 | fpexc->addChild(new QTreeWidgetItem(QStringList("OFC"))); | ||
| 175 | fpexc->addChild(new QTreeWidgetItem(QStringList("UFC"))); | ||
| 176 | fpexc->addChild(new QTreeWidgetItem(QStringList("INV"))); | ||
| 177 | fpexc->addChild(new QTreeWidgetItem(QStringList(tr("Vector Iteration Count")))); | ||
| 178 | fpexc->addChild(new QTreeWidgetItem(QStringList("FP2V"))); | ||
| 179 | fpexc->addChild(new QTreeWidgetItem(QStringList("EN"))); | ||
| 180 | fpexc->addChild(new QTreeWidgetItem(QStringList("EX"))); | ||
| 181 | |||
| 182 | vfp_system_registers->addChild(fpscr); | ||
| 183 | vfp_system_registers->addChild(fpexc); | ||
| 184 | vfp_system_registers->addChild(new QTreeWidgetItem(QStringList("FPINST"))); | ||
| 185 | vfp_system_registers->addChild(new QTreeWidgetItem(QStringList("FPINST2"))); | ||
| 186 | } | ||
| 187 | |||
| 188 | void RegistersWidget::UpdateVFPSystemRegisterValues() { | ||
| 189 | UNIMPLEMENTED(); | ||
| 190 | } | ||
diff --git a/src/yuzu/debugger/registers.h b/src/yuzu/debugger/registers.h deleted file mode 100644 index 55bda5b59..000000000 --- a/src/yuzu/debugger/registers.h +++ /dev/null | |||
| @@ -1,42 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <QDockWidget> | ||
| 8 | #include "ui_registers.h" | ||
| 9 | |||
| 10 | class QTreeWidget; | ||
| 11 | class QTreeWidgetItem; | ||
| 12 | class EmuThread; | ||
| 13 | |||
| 14 | class RegistersWidget : public QDockWidget { | ||
| 15 | Q_OBJECT | ||
| 16 | |||
| 17 | public: | ||
| 18 | explicit RegistersWidget(QWidget* parent = nullptr); | ||
| 19 | |||
| 20 | public slots: | ||
| 21 | void OnDebugModeEntered(); | ||
| 22 | void OnDebugModeLeft(); | ||
| 23 | |||
| 24 | void OnEmulationStarting(EmuThread* emu_thread); | ||
| 25 | void OnEmulationStopping(); | ||
| 26 | |||
| 27 | private: | ||
| 28 | void CreateCPSRChildren(); | ||
| 29 | void UpdateCPSRValues(); | ||
| 30 | |||
| 31 | void CreateVFPSystemRegisterChildren(); | ||
| 32 | void UpdateVFPSystemRegisterValues(); | ||
| 33 | |||
| 34 | Ui::ARMRegisters cpu_regs_ui; | ||
| 35 | |||
| 36 | QTreeWidget* tree; | ||
| 37 | |||
| 38 | QTreeWidgetItem* core_registers; | ||
| 39 | QTreeWidgetItem* vfp_registers; | ||
| 40 | QTreeWidgetItem* vfp_system_registers; | ||
| 41 | QTreeWidgetItem* cpsr; | ||
| 42 | }; | ||
diff --git a/src/yuzu/debugger/registers.ui b/src/yuzu/debugger/registers.ui deleted file mode 100644 index c81ae03f9..000000000 --- a/src/yuzu/debugger/registers.ui +++ /dev/null | |||
| @@ -1,40 +0,0 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ARMRegisters</class> | ||
| 4 | <widget class="QDockWidget" name="ARMRegisters"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>400</width> | ||
| 10 | <height>300</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>ARM Registers</string> | ||
| 15 | </property> | ||
| 16 | <widget class="QWidget" name="dockWidgetContents"> | ||
| 17 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
| 18 | <item> | ||
| 19 | <widget class="QTreeWidget" name="treeWidget"> | ||
| 20 | <property name="alternatingRowColors"> | ||
| 21 | <bool>true</bool> | ||
| 22 | </property> | ||
| 23 | <column> | ||
| 24 | <property name="text"> | ||
| 25 | <string>Register</string> | ||
| 26 | </property> | ||
| 27 | </column> | ||
| 28 | <column> | ||
| 29 | <property name="text"> | ||
| 30 | <string>Value</string> | ||
| 31 | </property> | ||
| 32 | </column> | ||
| 33 | </widget> | ||
| 34 | </item> | ||
| 35 | </layout> | ||
| 36 | </widget> | ||
| 37 | </widget> | ||
| 38 | <resources/> | ||
| 39 | <connections/> | ||
| 40 | </ui> | ||
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 017bef13c..7101b381e 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -213,6 +213,9 @@ QString WaitTreeThread::GetText() const { | |||
| 213 | case THREADSTATUS_WAIT_MUTEX: | 213 | case THREADSTATUS_WAIT_MUTEX: |
| 214 | status = tr("waiting for mutex"); | 214 | status = tr("waiting for mutex"); |
| 215 | break; | 215 | break; |
| 216 | case THREADSTATUS_WAIT_ARB: | ||
| 217 | status = tr("waiting for address arbiter"); | ||
| 218 | break; | ||
| 216 | case THREADSTATUS_DORMANT: | 219 | case THREADSTATUS_DORMANT: |
| 217 | status = tr("dormant"); | 220 | status = tr("dormant"); |
| 218 | break; | 221 | break; |
| @@ -240,6 +243,7 @@ QColor WaitTreeThread::GetColor() const { | |||
| 240 | case THREADSTATUS_WAIT_SYNCH_ALL: | 243 | case THREADSTATUS_WAIT_SYNCH_ALL: |
| 241 | case THREADSTATUS_WAIT_SYNCH_ANY: | 244 | case THREADSTATUS_WAIT_SYNCH_ANY: |
| 242 | case THREADSTATUS_WAIT_MUTEX: | 245 | case THREADSTATUS_WAIT_MUTEX: |
| 246 | case THREADSTATUS_WAIT_ARB: | ||
| 243 | return QColor(Qt::GlobalColor::red); | 247 | return QColor(Qt::GlobalColor::red); |
| 244 | case THREADSTATUS_DORMANT: | 248 | case THREADSTATUS_DORMANT: |
| 245 | return QColor(Qt::GlobalColor::darkCyan); | 249 | return QColor(Qt::GlobalColor::darkCyan); |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index bbd681eae..5a708dc73 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <QApplication> | 5 | #include <QApplication> |
| 6 | #include <QDir> | ||
| 6 | #include <QFileInfo> | 7 | #include <QFileInfo> |
| 7 | #include <QHeaderView> | 8 | #include <QHeaderView> |
| 8 | #include <QKeyEvent> | 9 | #include <QKeyEvent> |
| @@ -264,8 +265,17 @@ void GameList::ValidateEntry(const QModelIndex& item) { | |||
| 264 | if (file_path.isEmpty()) | 265 | if (file_path.isEmpty()) |
| 265 | return; | 266 | return; |
| 266 | std::string std_file_path(file_path.toStdString()); | 267 | std::string std_file_path(file_path.toStdString()); |
| 267 | if (!FileUtil::Exists(std_file_path) || FileUtil::IsDirectory(std_file_path)) | 268 | if (!FileUtil::Exists(std_file_path)) |
| 268 | return; | 269 | return; |
| 270 | if (FileUtil::IsDirectory(std_file_path)) { | ||
| 271 | QDir dir(std_file_path.c_str()); | ||
| 272 | QStringList matching_main = dir.entryList(QStringList("main"), QDir::Files); | ||
| 273 | if (matching_main.size() == 1) { | ||
| 274 | emit GameChosen(dir.path() + DIR_SEP + matching_main[0]); | ||
| 275 | } | ||
| 276 | return; | ||
| 277 | } | ||
| 278 | |||
| 269 | // Users usually want to run a diffrent game after closing one | 279 | // Users usually want to run a diffrent game after closing one |
| 270 | search_field->clear(); | 280 | search_field->clear(); |
| 271 | emit GameChosen(file_path); | 281 | emit GameChosen(file_path); |
| @@ -315,8 +325,7 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { | |||
| 315 | void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) { | 325 | void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) { |
| 316 | if (!FileUtil::Exists(dir_path.toStdString()) || | 326 | if (!FileUtil::Exists(dir_path.toStdString()) || |
| 317 | !FileUtil::IsDirectory(dir_path.toStdString())) { | 327 | !FileUtil::IsDirectory(dir_path.toStdString())) { |
| 318 | NGLOG_ERROR(Frontend, "Could not find game list folder at {}", | 328 | LOG_ERROR(Frontend, "Could not find game list folder at {}", dir_path.toLocal8Bit().data()); |
| 319 | dir_path.toLocal8Bit().data()); | ||
| 320 | search_field->setFilterResult(0, 0); | 329 | search_field->setFilterResult(0, 0); |
| 321 | return; | 330 | return; |
| 322 | } | 331 | } |
| @@ -356,16 +365,29 @@ void GameList::LoadInterfaceLayout() { | |||
| 356 | item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder()); | 365 | item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder()); |
| 357 | } | 366 | } |
| 358 | 367 | ||
| 359 | const QStringList GameList::supported_file_extensions = {"nso", "nro"}; | 368 | const QStringList GameList::supported_file_extensions = {"nso", "nro", "nca"}; |
| 360 | 369 | ||
| 361 | static bool HasSupportedFileExtension(const std::string& file_name) { | 370 | static bool HasSupportedFileExtension(const std::string& file_name) { |
| 362 | QFileInfo file = QFileInfo(file_name.c_str()); | 371 | QFileInfo file = QFileInfo(file_name.c_str()); |
| 363 | return GameList::supported_file_extensions.contains(file.suffix(), Qt::CaseInsensitive); | 372 | return GameList::supported_file_extensions.contains(file.suffix(), Qt::CaseInsensitive); |
| 364 | } | 373 | } |
| 365 | 374 | ||
| 375 | static bool IsExtractedNCAMain(const std::string& file_name) { | ||
| 376 | return QFileInfo(file_name.c_str()).fileName() == "main"; | ||
| 377 | } | ||
| 378 | |||
| 379 | static QString FormatGameName(const std::string& physical_name) { | ||
| 380 | QFileInfo file_info(physical_name.c_str()); | ||
| 381 | if (IsExtractedNCAMain(physical_name)) { | ||
| 382 | return file_info.dir().path(); | ||
| 383 | } else { | ||
| 384 | return QString::fromStdString(physical_name); | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 366 | void GameList::RefreshGameDirectory() { | 388 | void GameList::RefreshGameDirectory() { |
| 367 | if (!UISettings::values.gamedir.isEmpty() && current_worker != nullptr) { | 389 | if (!UISettings::values.gamedir.isEmpty() && current_worker != nullptr) { |
| 368 | NGLOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); | 390 | LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); |
| 369 | search_field->clear(); | 391 | search_field->clear(); |
| 370 | PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); | 392 | PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); |
| 371 | } | 393 | } |
| @@ -380,7 +402,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign | |||
| 380 | return false; // Breaks the callback loop. | 402 | return false; // Breaks the callback loop. |
| 381 | 403 | ||
| 382 | bool is_dir = FileUtil::IsDirectory(physical_name); | 404 | bool is_dir = FileUtil::IsDirectory(physical_name); |
| 383 | if (!is_dir && HasSupportedFileExtension(physical_name)) { | 405 | if (!is_dir && |
| 406 | (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { | ||
| 384 | std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(physical_name); | 407 | std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(physical_name); |
| 385 | if (!loader) | 408 | if (!loader) |
| 386 | return true; | 409 | return true; |
| @@ -392,7 +415,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign | |||
| 392 | loader->ReadProgramId(program_id); | 415 | loader->ReadProgramId(program_id); |
| 393 | 416 | ||
| 394 | emit EntryReady({ | 417 | emit EntryReady({ |
| 395 | new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id), | 418 | new GameListItemPath(FormatGameName(physical_name), smdh, program_id), |
| 396 | new GameListItem( | 419 | new GameListItem( |
| 397 | QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), | 420 | QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), |
| 398 | new GameListItemSize(FileUtil::GetSize(physical_name)), | 421 | new GameListItemSize(FileUtil::GetSize(physical_name)), |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 3038bd6da..05a8ae6d2 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <QMessageBox> | 13 | #include <QMessageBox> |
| 14 | #include <QtGui> | 14 | #include <QtGui> |
| 15 | #include <QtWidgets> | 15 | #include <QtWidgets> |
| 16 | #include "common/common_paths.h" | ||
| 16 | #include "common/logging/backend.h" | 17 | #include "common/logging/backend.h" |
| 17 | #include "common/logging/filter.h" | 18 | #include "common/logging/filter.h" |
| 18 | #include "common/logging/log.h" | 19 | #include "common/logging/log.h" |
| @@ -30,10 +31,10 @@ | |||
| 30 | #include "yuzu/bootmanager.h" | 31 | #include "yuzu/bootmanager.h" |
| 31 | #include "yuzu/configuration/config.h" | 32 | #include "yuzu/configuration/config.h" |
| 32 | #include "yuzu/configuration/configure_dialog.h" | 33 | #include "yuzu/configuration/configure_dialog.h" |
| 34 | #include "yuzu/debugger/console.h" | ||
| 33 | #include "yuzu/debugger/graphics/graphics_breakpoints.h" | 35 | #include "yuzu/debugger/graphics/graphics_breakpoints.h" |
| 34 | #include "yuzu/debugger/graphics/graphics_surface.h" | 36 | #include "yuzu/debugger/graphics/graphics_surface.h" |
| 35 | #include "yuzu/debugger/profiler.h" | 37 | #include "yuzu/debugger/profiler.h" |
| 36 | #include "yuzu/debugger/registers.h" | ||
| 37 | #include "yuzu/debugger/wait_tree.h" | 38 | #include "yuzu/debugger/wait_tree.h" |
| 38 | #include "yuzu/game_list.h" | 39 | #include "yuzu/game_list.h" |
| 39 | #include "yuzu/hotkeys.h" | 40 | #include "yuzu/hotkeys.h" |
| @@ -169,15 +170,6 @@ void GMainWindow::InitializeDebugWidgets() { | |||
| 169 | debug_menu->addAction(microProfileDialog->toggleViewAction()); | 170 | debug_menu->addAction(microProfileDialog->toggleViewAction()); |
| 170 | #endif | 171 | #endif |
| 171 | 172 | ||
| 172 | registersWidget = new RegistersWidget(this); | ||
| 173 | addDockWidget(Qt::RightDockWidgetArea, registersWidget); | ||
| 174 | registersWidget->hide(); | ||
| 175 | debug_menu->addAction(registersWidget->toggleViewAction()); | ||
| 176 | connect(this, &GMainWindow::EmulationStarting, registersWidget, | ||
| 177 | &RegistersWidget::OnEmulationStarting); | ||
| 178 | connect(this, &GMainWindow::EmulationStopping, registersWidget, | ||
| 179 | &RegistersWidget::OnEmulationStopping); | ||
| 180 | |||
| 181 | graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(debug_context, this); | 173 | graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(debug_context, this); |
| 182 | addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget); | 174 | addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget); |
| 183 | graphicsBreakpointsWidget->hide(); | 175 | graphicsBreakpointsWidget->hide(); |
| @@ -270,6 +262,7 @@ void GMainWindow::RestoreUIState() { | |||
| 270 | 262 | ||
| 271 | ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar); | 263 | ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar); |
| 272 | statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); | 264 | statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); |
| 265 | Debugger::ToggleConsole(); | ||
| 273 | } | 266 | } |
| 274 | 267 | ||
| 275 | void GMainWindow::ConnectWidgetEvents() { | 268 | void GMainWindow::ConnectWidgetEvents() { |
| @@ -288,6 +281,7 @@ void GMainWindow::ConnectWidgetEvents() { | |||
| 288 | void GMainWindow::ConnectMenuEvents() { | 281 | void GMainWindow::ConnectMenuEvents() { |
| 289 | // File | 282 | // File |
| 290 | connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); | 283 | connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); |
| 284 | connect(ui.action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder); | ||
| 291 | connect(ui.action_Select_Game_List_Root, &QAction::triggered, this, | 285 | connect(ui.action_Select_Game_List_Root, &QAction::triggered, this, |
| 292 | &GMainWindow::OnMenuSelectGameListRoot); | 286 | &GMainWindow::OnMenuSelectGameListRoot); |
| 293 | connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); | 287 | connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); |
| @@ -342,13 +336,11 @@ bool GMainWindow::SupportsRequiredGLExtensions() { | |||
| 342 | unsupported_ext.append("ARB_program_interface_query"); | 336 | unsupported_ext.append("ARB_program_interface_query"); |
| 343 | if (!GLAD_GL_ARB_separate_shader_objects) | 337 | if (!GLAD_GL_ARB_separate_shader_objects) |
| 344 | unsupported_ext.append("ARB_separate_shader_objects"); | 338 | unsupported_ext.append("ARB_separate_shader_objects"); |
| 345 | if (!GLAD_GL_ARB_shader_storage_buffer_object) | ||
| 346 | unsupported_ext.append("ARB_shader_storage_buffer_object"); | ||
| 347 | if (!GLAD_GL_ARB_vertex_attrib_binding) | 339 | if (!GLAD_GL_ARB_vertex_attrib_binding) |
| 348 | unsupported_ext.append("ARB_vertex_attrib_binding"); | 340 | unsupported_ext.append("ARB_vertex_attrib_binding"); |
| 349 | 341 | ||
| 350 | for (const QString& ext : unsupported_ext) | 342 | for (const QString& ext : unsupported_ext) |
| 351 | NGLOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext.toStdString()); | 343 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext.toStdString()); |
| 352 | 344 | ||
| 353 | return unsupported_ext.empty(); | 345 | return unsupported_ext.empty(); |
| 354 | } | 346 | } |
| @@ -385,17 +377,17 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 385 | if (result != Core::System::ResultStatus::Success) { | 377 | if (result != Core::System::ResultStatus::Success) { |
| 386 | switch (result) { | 378 | switch (result) { |
| 387 | case Core::System::ResultStatus::ErrorGetLoader: | 379 | case Core::System::ResultStatus::ErrorGetLoader: |
| 388 | NGLOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filename.toStdString()); | 380 | LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filename.toStdString()); |
| 389 | QMessageBox::critical(this, tr("Error while loading ROM!"), | 381 | QMessageBox::critical(this, tr("Error while loading ROM!"), |
| 390 | tr("The ROM format is not supported.")); | 382 | tr("The ROM format is not supported.")); |
| 391 | break; | 383 | break; |
| 392 | case Core::System::ResultStatus::ErrorUnsupportedArch: | 384 | case Core::System::ResultStatus::ErrorUnsupportedArch: |
| 393 | NGLOG_CRITICAL(Frontend, "Unsupported architecture detected!", filename.toStdString()); | 385 | LOG_CRITICAL(Frontend, "Unsupported architecture detected!", filename.toStdString()); |
| 394 | QMessageBox::critical(this, tr("Error while loading ROM!"), | 386 | QMessageBox::critical(this, tr("Error while loading ROM!"), |
| 395 | tr("The ROM uses currently unusable 32-bit architecture")); | 387 | tr("The ROM uses currently unusable 32-bit architecture")); |
| 396 | break; | 388 | break; |
| 397 | case Core::System::ResultStatus::ErrorSystemMode: | 389 | case Core::System::ResultStatus::ErrorSystemMode: |
| 398 | NGLOG_CRITICAL(Frontend, "Failed to load ROM!"); | 390 | LOG_CRITICAL(Frontend, "Failed to load ROM!"); |
| 399 | QMessageBox::critical(this, tr("Error while loading ROM!"), | 391 | QMessageBox::critical(this, tr("Error while loading ROM!"), |
| 400 | tr("Could not determine the system mode.")); | 392 | tr("Could not determine the system mode.")); |
| 401 | break; | 393 | break; |
| @@ -445,7 +437,7 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 445 | } | 437 | } |
| 446 | 438 | ||
| 447 | void GMainWindow::BootGame(const QString& filename) { | 439 | void GMainWindow::BootGame(const QString& filename) { |
| 448 | NGLOG_INFO(Frontend, "yuzu starting..."); | 440 | LOG_INFO(Frontend, "yuzu starting..."); |
| 449 | StoreRecentFile(filename); // Put the filename on top of the list | 441 | StoreRecentFile(filename); // Put the filename on top of the list |
| 450 | 442 | ||
| 451 | if (!LoadROM(filename)) | 443 | if (!LoadROM(filename)) |
| @@ -460,17 +452,12 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 460 | connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); | 452 | connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); |
| 461 | // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views | 453 | // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views |
| 462 | // before the CPU continues | 454 | // before the CPU continues |
| 463 | connect(emu_thread.get(), &EmuThread::DebugModeEntered, registersWidget, | ||
| 464 | &RegistersWidget::OnDebugModeEntered, Qt::BlockingQueuedConnection); | ||
| 465 | connect(emu_thread.get(), &EmuThread::DebugModeEntered, waitTreeWidget, | 455 | connect(emu_thread.get(), &EmuThread::DebugModeEntered, waitTreeWidget, |
| 466 | &WaitTreeWidget::OnDebugModeEntered, Qt::BlockingQueuedConnection); | 456 | &WaitTreeWidget::OnDebugModeEntered, Qt::BlockingQueuedConnection); |
| 467 | connect(emu_thread.get(), &EmuThread::DebugModeLeft, registersWidget, | ||
| 468 | &RegistersWidget::OnDebugModeLeft, Qt::BlockingQueuedConnection); | ||
| 469 | connect(emu_thread.get(), &EmuThread::DebugModeLeft, waitTreeWidget, | 457 | connect(emu_thread.get(), &EmuThread::DebugModeLeft, waitTreeWidget, |
| 470 | &WaitTreeWidget::OnDebugModeLeft, Qt::BlockingQueuedConnection); | 458 | &WaitTreeWidget::OnDebugModeLeft, Qt::BlockingQueuedConnection); |
| 471 | 459 | ||
| 472 | // Update the GUI | 460 | // Update the GUI |
| 473 | registersWidget->OnDebugModeEntered(); | ||
| 474 | if (ui.action_Single_Window_Mode->isChecked()) { | 461 | if (ui.action_Single_Window_Mode->isChecked()) { |
| 475 | game_list->hide(); | 462 | game_list->hide(); |
| 476 | } | 463 | } |
| @@ -565,6 +552,8 @@ void GMainWindow::OnMenuLoadFile() { | |||
| 565 | for (const auto& piece : game_list->supported_file_extensions) | 552 | for (const auto& piece : game_list->supported_file_extensions) |
| 566 | extensions += "*." + piece + " "; | 553 | extensions += "*." + piece + " "; |
| 567 | 554 | ||
| 555 | extensions += "main "; | ||
| 556 | |||
| 568 | QString file_filter = tr("Switch Executable") + " (" + extensions + ")"; | 557 | QString file_filter = tr("Switch Executable") + " (" + extensions + ")"; |
| 569 | file_filter += ";;" + tr("All Files (*.*)"); | 558 | file_filter += ";;" + tr("All Files (*.*)"); |
| 570 | 559 | ||
| @@ -577,6 +566,18 @@ void GMainWindow::OnMenuLoadFile() { | |||
| 577 | } | 566 | } |
| 578 | } | 567 | } |
| 579 | 568 | ||
| 569 | void GMainWindow::OnMenuLoadFolder() { | ||
| 570 | QDir dir = QFileDialog::getExistingDirectory(this, tr("Open Extracted ROM Directory")); | ||
| 571 | |||
| 572 | QStringList matching_main = dir.entryList(QStringList("main"), QDir::Files); | ||
| 573 | if (matching_main.size() == 1) { | ||
| 574 | BootGame(dir.path() + DIR_SEP + matching_main[0]); | ||
| 575 | } else { | ||
| 576 | QMessageBox::warning(this, tr("Invalid Directory Selected"), | ||
| 577 | tr("The directory you have selected does not contain a 'main' file.")); | ||
| 578 | } | ||
| 579 | } | ||
| 580 | |||
| 580 | void GMainWindow::OnMenuSelectGameListRoot() { | 581 | void GMainWindow::OnMenuSelectGameListRoot() { |
| 581 | QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory")); | 582 | QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory")); |
| 582 | if (!dir_path.isEmpty()) { | 583 | if (!dir_path.isEmpty()) { |
| @@ -883,7 +884,7 @@ void GMainWindow::UpdateUITheme() { | |||
| 883 | QString theme_uri(":" + UISettings::values.theme + "/style.qss"); | 884 | QString theme_uri(":" + UISettings::values.theme + "/style.qss"); |
| 884 | QFile f(theme_uri); | 885 | QFile f(theme_uri); |
| 885 | if (!f.exists()) { | 886 | if (!f.exists()) { |
| 886 | NGLOG_ERROR(Frontend, "Unable to set style, stylesheet file not found"); | 887 | LOG_ERROR(Frontend, "Unable to set style, stylesheet file not found"); |
| 887 | } else { | 888 | } else { |
| 888 | f.open(QFile::ReadOnly | QFile::Text); | 889 | f.open(QFile::ReadOnly | QFile::Text); |
| 889 | QTextStream ts(&f); | 890 | QTextStream ts(&f); |
| @@ -907,8 +908,7 @@ void GMainWindow::UpdateUITheme() { | |||
| 907 | #endif | 908 | #endif |
| 908 | 909 | ||
| 909 | int main(int argc, char* argv[]) { | 910 | int main(int argc, char* argv[]) { |
| 910 | Log::Filter log_filter(Log::Level::Info); | 911 | Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); |
| 911 | Log::SetFilter(&log_filter); | ||
| 912 | 912 | ||
| 913 | MicroProfileOnThreadCreate("Frontend"); | 913 | MicroProfileOnThreadCreate("Frontend"); |
| 914 | SCOPE_EXIT({ MicroProfileShutdown(); }); | 914 | SCOPE_EXIT({ MicroProfileShutdown(); }); |
| @@ -926,7 +926,12 @@ int main(int argc, char* argv[]) { | |||
| 926 | 926 | ||
| 927 | GMainWindow main_window; | 927 | GMainWindow main_window; |
| 928 | // After settings have been loaded by GMainWindow, apply the filter | 928 | // After settings have been loaded by GMainWindow, apply the filter |
| 929 | Log::Filter log_filter; | ||
| 929 | log_filter.ParseFilterString(Settings::values.log_filter); | 930 | log_filter.ParseFilterString(Settings::values.log_filter); |
| 931 | Log::SetGlobalFilter(log_filter); | ||
| 932 | FileUtil::CreateFullPath(FileUtil::GetUserPath(D_LOGS_IDX)); | ||
| 933 | Log::AddBackend( | ||
| 934 | std::make_unique<Log::FileBackend>(FileUtil::GetUserPath(D_LOGS_IDX) + LOG_FILE)); | ||
| 930 | 935 | ||
| 931 | main_window.show(); | 936 | main_window.show(); |
| 932 | return app.exec(); | 937 | return app.exec(); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index ac3024d8a..074bba3f9 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -19,7 +19,6 @@ class GraphicsSurfaceWidget; | |||
| 19 | class GRenderWindow; | 19 | class GRenderWindow; |
| 20 | class MicroProfileDialog; | 20 | class MicroProfileDialog; |
| 21 | class ProfilerWidget; | 21 | class ProfilerWidget; |
| 22 | class RegistersWidget; | ||
| 23 | class WaitTreeWidget; | 22 | class WaitTreeWidget; |
| 24 | 23 | ||
| 25 | namespace Tegra { | 24 | namespace Tegra { |
| @@ -124,6 +123,7 @@ private slots: | |||
| 124 | void OnGameListLoadFile(QString game_path); | 123 | void OnGameListLoadFile(QString game_path); |
| 125 | void OnGameListOpenSaveFolder(u64 program_id); | 124 | void OnGameListOpenSaveFolder(u64 program_id); |
| 126 | void OnMenuLoadFile(); | 125 | void OnMenuLoadFile(); |
| 126 | void OnMenuLoadFolder(); | ||
| 127 | /// Called whenever a user selects the "File->Select Game List Root" menu item | 127 | /// Called whenever a user selects the "File->Select Game List Root" menu item |
| 128 | void OnMenuSelectGameListRoot(); | 128 | void OnMenuSelectGameListRoot(); |
| 129 | void OnMenuRecentFile(); | 129 | void OnMenuRecentFile(); |
| @@ -163,7 +163,6 @@ private: | |||
| 163 | // Debugger panes | 163 | // Debugger panes |
| 164 | ProfilerWidget* profilerWidget; | 164 | ProfilerWidget* profilerWidget; |
| 165 | MicroProfileDialog* microProfileDialog; | 165 | MicroProfileDialog* microProfileDialog; |
| 166 | RegistersWidget* registersWidget; | ||
| 167 | GraphicsBreakPointsWidget* graphicsBreakpointsWidget; | 166 | GraphicsBreakPointsWidget* graphicsBreakpointsWidget; |
| 168 | GraphicsSurfaceWidget* graphicsSurfaceWidget; | 167 | GraphicsSurfaceWidget* graphicsSurfaceWidget; |
| 169 | WaitTreeWidget* waitTreeWidget; | 168 | WaitTreeWidget* waitTreeWidget; |
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 0fcd93cc2..22c4cad08 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui | |||
| @@ -58,6 +58,7 @@ | |||
| 58 | </property> | 58 | </property> |
| 59 | </widget> | 59 | </widget> |
| 60 | <addaction name="action_Load_File"/> | 60 | <addaction name="action_Load_File"/> |
| 61 | <addaction name="action_Load_Folder"/> | ||
| 61 | <addaction name="separator"/> | 62 | <addaction name="separator"/> |
| 62 | <addaction name="action_Select_Game_List_Root"/> | 63 | <addaction name="action_Select_Game_List_Root"/> |
| 63 | <addaction name="menu_recent_files"/> | 64 | <addaction name="menu_recent_files"/> |
| @@ -106,6 +107,11 @@ | |||
| 106 | <string>Load File...</string> | 107 | <string>Load File...</string> |
| 107 | </property> | 108 | </property> |
| 108 | </action> | 109 | </action> |
| 110 | <action name="action_Load_Folder"> | ||
| 111 | <property name="text"> | ||
| 112 | <string>Load Folder...</string> | ||
| 113 | </property> | ||
| 114 | </action> | ||
| 109 | <action name="action_Load_Symbol_Map"> | 115 | <action name="action_Load_Symbol_Map"> |
| 110 | <property name="text"> | 116 | <property name="text"> |
| 111 | <string>Load Symbol Map...</string> | 117 | <string>Load Symbol Map...</string> |
diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h index 8e215a002..2286c2559 100644 --- a/src/yuzu/ui_settings.h +++ b/src/yuzu/ui_settings.h | |||
| @@ -51,6 +51,9 @@ struct Values { | |||
| 51 | std::vector<Shortcut> shortcuts; | 51 | std::vector<Shortcut> shortcuts; |
| 52 | 52 | ||
| 53 | uint32_t callout_flags; | 53 | uint32_t callout_flags; |
| 54 | |||
| 55 | // logging | ||
| 56 | bool show_console; | ||
| 54 | }; | 57 | }; |
| 55 | 58 | ||
| 56 | extern Values values; | 59 | extern Values values; |
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index ee6e4d658..3a311b69f 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -27,17 +27,17 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) { | |||
| 27 | const char* location = this->sdl2_config_loc.c_str(); | 27 | const char* location = this->sdl2_config_loc.c_str(); |
| 28 | if (sdl2_config->ParseError() < 0) { | 28 | if (sdl2_config->ParseError() < 0) { |
| 29 | if (retry) { | 29 | if (retry) { |
| 30 | NGLOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location); | 30 | LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location); |
| 31 | FileUtil::CreateFullPath(location); | 31 | FileUtil::CreateFullPath(location); |
| 32 | FileUtil::WriteStringToFile(true, default_contents, location); | 32 | FileUtil::WriteStringToFile(true, default_contents, location); |
| 33 | sdl2_config = std::make_unique<INIReader>(location); // Reopen file | 33 | sdl2_config = std::make_unique<INIReader>(location); // Reopen file |
| 34 | 34 | ||
| 35 | return LoadINI(default_contents, false); | 35 | return LoadINI(default_contents, false); |
| 36 | } | 36 | } |
| 37 | NGLOG_ERROR(Config, "Failed."); | 37 | LOG_ERROR(Config, "Failed."); |
| 38 | return false; | 38 | return false; |
| 39 | } | 39 | } |
| 40 | NGLOG_INFO(Config, "Successfully loaded {}", location); | 40 | LOG_INFO(Config, "Successfully loaded {}", location); |
| 41 | return true; | 41 | return true; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| @@ -98,6 +98,8 @@ void Config::ReadValues() { | |||
| 98 | (float)sdl2_config->GetReal("Renderer", "resolution_factor", 1.0); | 98 | (float)sdl2_config->GetReal("Renderer", "resolution_factor", 1.0); |
| 99 | Settings::values.toggle_framelimit = | 99 | Settings::values.toggle_framelimit = |
| 100 | sdl2_config->GetBoolean("Renderer", "toggle_framelimit", true); | 100 | sdl2_config->GetBoolean("Renderer", "toggle_framelimit", true); |
| 101 | Settings::values.use_accurate_framebuffers = | ||
| 102 | sdl2_config->GetBoolean("Renderer", "use_accurate_framebuffers", false); | ||
| 101 | 103 | ||
| 102 | Settings::values.bg_red = (float)sdl2_config->GetReal("Renderer", "bg_red", 0.0); | 104 | Settings::values.bg_red = (float)sdl2_config->GetReal("Renderer", "bg_red", 0.0); |
| 103 | Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 0.0); | 105 | Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 0.0); |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 1c438c3f5..71d2e040f 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -102,6 +102,10 @@ resolution_factor = | |||
| 102 | # 0 (default): Off, 1: On | 102 | # 0 (default): Off, 1: On |
| 103 | use_vsync = | 103 | use_vsync = |
| 104 | 104 | ||
| 105 | # Whether to use accurate framebuffers | ||
| 106 | # 0 (default): Off (fast), 1 : On (slow) | ||
| 107 | use_accurate_framebuffers = | ||
| 108 | |||
| 105 | # The clear color for the renderer. What shows up on the sides of the bottom screen. | 109 | # The clear color for the renderer. What shows up on the sides of the bottom screen. |
| 106 | # Must be in range of 0.0-1.0. Defaults to 1.0 for all. | 110 | # Must be in range of 0.0-1.0. Defaults to 1.0 for all. |
| 107 | bg_red = | 111 | bg_red = |
| @@ -162,7 +166,7 @@ use_virtual_sd = | |||
| 162 | # 1 (default): Yes, 0: No | 166 | # 1 (default): Yes, 0: No |
| 163 | use_docked_mode = | 167 | use_docked_mode = |
| 164 | 168 | ||
| 165 | # The system region that Citra will use during emulation | 169 | # The system region that yuzu will use during emulation |
| 166 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan | 170 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan |
| 167 | region_value = | 171 | region_value = |
| 168 | 172 | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index cfd8eb7e6..e6f0bbe8f 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -62,19 +62,19 @@ void EmuWindow_SDL2::Fullscreen() { | |||
| 62 | return; | 62 | return; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | NGLOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError()); | 65 | LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError()); |
| 66 | 66 | ||
| 67 | // Try a different fullscreening method | 67 | // Try a different fullscreening method |
| 68 | NGLOG_INFO(Frontend, "Attempting to use borderless fullscreen..."); | 68 | LOG_INFO(Frontend, "Attempting to use borderless fullscreen..."); |
| 69 | if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { | 69 | if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { |
| 70 | return; | 70 | return; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | NGLOG_ERROR(Frontend, "Borderless fullscreening failed: {}", SDL_GetError()); | 73 | LOG_ERROR(Frontend, "Borderless fullscreening failed: {}", SDL_GetError()); |
| 74 | 74 | ||
| 75 | // Fallback algorithm: Maximise window. | 75 | // Fallback algorithm: Maximise window. |
| 76 | // Works on all systems (unless something is seriously wrong), so no fallback for this one. | 76 | // Works on all systems (unless something is seriously wrong), so no fallback for this one. |
| 77 | NGLOG_INFO(Frontend, "Falling back on a maximised window..."); | 77 | LOG_INFO(Frontend, "Falling back on a maximised window..."); |
| 78 | SDL_MaximizeWindow(render_window); | 78 | SDL_MaximizeWindow(render_window); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| @@ -91,7 +91,7 @@ bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { | |||
| 91 | unsupported_ext.push_back("ARB_vertex_attrib_binding"); | 91 | unsupported_ext.push_back("ARB_vertex_attrib_binding"); |
| 92 | 92 | ||
| 93 | for (const std::string& ext : unsupported_ext) | 93 | for (const std::string& ext : unsupported_ext) |
| 94 | NGLOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext); | 94 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext); |
| 95 | 95 | ||
| 96 | return unsupported_ext.empty(); | 96 | return unsupported_ext.empty(); |
| 97 | } | 97 | } |
| @@ -103,7 +103,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | |||
| 103 | 103 | ||
| 104 | // Initialize the window | 104 | // Initialize the window |
| 105 | if (SDL_Init(SDL_INIT_VIDEO) < 0) { | 105 | if (SDL_Init(SDL_INIT_VIDEO) < 0) { |
| 106 | NGLOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); | 106 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); |
| 107 | exit(1); | 107 | exit(1); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| @@ -126,7 +126,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | |||
| 126 | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); | 126 | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); |
| 127 | 127 | ||
| 128 | if (render_window == nullptr) { | 128 | if (render_window == nullptr) { |
| 129 | NGLOG_CRITICAL(Frontend, "Failed to create SDL2 window! Exiting..."); | 129 | LOG_CRITICAL(Frontend, "Failed to create SDL2 window! Exiting..."); |
| 130 | exit(1); | 130 | exit(1); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| @@ -137,17 +137,17 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | |||
| 137 | gl_context = SDL_GL_CreateContext(render_window); | 137 | gl_context = SDL_GL_CreateContext(render_window); |
| 138 | 138 | ||
| 139 | if (gl_context == nullptr) { | 139 | if (gl_context == nullptr) { |
| 140 | NGLOG_CRITICAL(Frontend, "Failed to create SDL2 GL context! Exiting..."); | 140 | LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context! Exiting..."); |
| 141 | exit(1); | 141 | exit(1); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | if (!gladLoadGLLoader(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) { | 144 | if (!gladLoadGLLoader(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) { |
| 145 | NGLOG_CRITICAL(Frontend, "Failed to initialize GL functions! Exiting..."); | 145 | LOG_CRITICAL(Frontend, "Failed to initialize GL functions! Exiting..."); |
| 146 | exit(1); | 146 | exit(1); |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | if (!SupportsRequiredGLExtensions()) { | 149 | if (!SupportsRequiredGLExtensions()) { |
| 150 | NGLOG_CRITICAL(Frontend, "GPU does not support all required OpenGL extensions! Exiting..."); | 150 | LOG_CRITICAL(Frontend, "GPU does not support all required OpenGL extensions! Exiting..."); |
| 151 | exit(1); | 151 | exit(1); |
| 152 | } | 152 | } |
| 153 | 153 | ||
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 95e568b7b..8ddd202d8 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include <thread> | 8 | #include <thread> |
| 9 | 9 | ||
| 10 | #include "common/common_paths.h" | ||
| 10 | #include "common/logging/backend.h" | 11 | #include "common/logging/backend.h" |
| 11 | #include "common/logging/filter.h" | 12 | #include "common/logging/filter.h" |
| 12 | #include "common/logging/log.h" | 13 | #include "common/logging/log.h" |
| @@ -69,7 +70,7 @@ int main(int argc, char** argv) { | |||
| 69 | auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w); | 70 | auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w); |
| 70 | 71 | ||
| 71 | if (argv_w == nullptr) { | 72 | if (argv_w == nullptr) { |
| 72 | NGLOG_CRITICAL(Frontend, "Failed to get command line arguments"); | 73 | LOG_CRITICAL(Frontend, "Failed to get command line arguments"); |
| 73 | return -1; | 74 | return -1; |
| 74 | } | 75 | } |
| 75 | #endif | 76 | #endif |
| @@ -102,7 +103,7 @@ int main(int argc, char** argv) { | |||
| 102 | break; | 103 | break; |
| 103 | case 'f': | 104 | case 'f': |
| 104 | fullscreen = true; | 105 | fullscreen = true; |
| 105 | NGLOG_INFO(Frontend, "Starting in fullscreen mode..."); | 106 | LOG_INFO(Frontend, "Starting in fullscreen mode..."); |
| 106 | break; | 107 | break; |
| 107 | case 'h': | 108 | case 'h': |
| 108 | PrintHelp(argv[0]); | 109 | PrintHelp(argv[0]); |
| @@ -126,13 +127,18 @@ int main(int argc, char** argv) { | |||
| 126 | #endif | 127 | #endif |
| 127 | 128 | ||
| 128 | Log::Filter log_filter(Log::Level::Debug); | 129 | Log::Filter log_filter(Log::Level::Debug); |
| 129 | Log::SetFilter(&log_filter); | 130 | Log::SetGlobalFilter(log_filter); |
| 131 | |||
| 132 | Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); | ||
| 133 | FileUtil::CreateFullPath(FileUtil::GetUserPath(D_LOGS_IDX)); | ||
| 134 | Log::AddBackend( | ||
| 135 | std::make_unique<Log::FileBackend>(FileUtil::GetUserPath(D_LOGS_IDX) + LOG_FILE)); | ||
| 130 | 136 | ||
| 131 | MicroProfileOnThreadCreate("EmuThread"); | 137 | MicroProfileOnThreadCreate("EmuThread"); |
| 132 | SCOPE_EXIT({ MicroProfileShutdown(); }); | 138 | SCOPE_EXIT({ MicroProfileShutdown(); }); |
| 133 | 139 | ||
| 134 | if (filepath.empty()) { | 140 | if (filepath.empty()) { |
| 135 | NGLOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); | 141 | LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); |
| 136 | return -1; | 142 | return -1; |
| 137 | } | 143 | } |
| 138 | 144 | ||
| @@ -153,28 +159,28 @@ int main(int argc, char** argv) { | |||
| 153 | 159 | ||
| 154 | switch (load_result) { | 160 | switch (load_result) { |
| 155 | case Core::System::ResultStatus::ErrorGetLoader: | 161 | case Core::System::ResultStatus::ErrorGetLoader: |
| 156 | NGLOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filepath.c_str()); | 162 | LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filepath.c_str()); |
| 157 | return -1; | 163 | return -1; |
| 158 | case Core::System::ResultStatus::ErrorLoader: | 164 | case Core::System::ResultStatus::ErrorLoader: |
| 159 | NGLOG_CRITICAL(Frontend, "Failed to load ROM!"); | 165 | LOG_CRITICAL(Frontend, "Failed to load ROM!"); |
| 160 | return -1; | 166 | return -1; |
| 161 | case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: | 167 | case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: |
| 162 | NGLOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before " | 168 | LOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before " |
| 163 | "being used with yuzu. \n\n For more information on dumping and " | 169 | "being used with yuzu. \n\n For more information on dumping and " |
| 164 | "decrypting games, please refer to: " | 170 | "decrypting games, please refer to: " |
| 165 | "https://yuzu-emu.org/wiki/dumping-game-cartridges/"); | 171 | "https://yuzu-emu.org/wiki/dumping-game-cartridges/"); |
| 166 | return -1; | 172 | return -1; |
| 167 | case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: | 173 | case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: |
| 168 | NGLOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported."); | 174 | LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported."); |
| 169 | return -1; | 175 | return -1; |
| 170 | case Core::System::ResultStatus::ErrorNotInitialized: | 176 | case Core::System::ResultStatus::ErrorNotInitialized: |
| 171 | NGLOG_CRITICAL(Frontend, "CPUCore not initialized"); | 177 | LOG_CRITICAL(Frontend, "CPUCore not initialized"); |
| 172 | return -1; | 178 | return -1; |
| 173 | case Core::System::ResultStatus::ErrorSystemMode: | 179 | case Core::System::ResultStatus::ErrorSystemMode: |
| 174 | NGLOG_CRITICAL(Frontend, "Failed to determine system mode!"); | 180 | LOG_CRITICAL(Frontend, "Failed to determine system mode!"); |
| 175 | return -1; | 181 | return -1; |
| 176 | case Core::System::ResultStatus::ErrorVideoCore: | 182 | case Core::System::ResultStatus::ErrorVideoCore: |
| 177 | NGLOG_CRITICAL(Frontend, "VideoCore not initialized"); | 183 | LOG_CRITICAL(Frontend, "VideoCore not initialized"); |
| 178 | return -1; | 184 | return -1; |
| 179 | case Core::System::ResultStatus::Success: | 185 | case Core::System::ResultStatus::Success: |
| 180 | break; // Expected case | 186 | break; // Expected case |