Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bd8edee77f | |||
| 787619cdba | |||
| 7d70be42af | |||
| 9671a654b7 | |||
| 6963157e63 | |||
| 9452c6b08c | |||
| 035875825e | |||
| 837e06e85b | |||
| 9e3132c3fc | |||
| 843d0ed298 | |||
| f7f4c049fc | |||
| 1072540e3e | |||
| 0c8c13b8b7 | |||
| 303a109286 | |||
| f0dc38cadd | |||
| 4efa2266e6 | |||
| 1f7a1e4078 | |||
| 2ead9b1f21 | |||
| ddf5b52360 | |||
| f66468ffcd | |||
| d3405da5c4 | |||
| 020d282868 | |||
| 137821c866 | |||
| e6d2e05b6e | |||
| 7b889a10cc | |||
| 1e1c2007a3 | |||
| 660f491310 | |||
| 670660c244 | |||
| 3d960064ef | |||
| f6d2409b20 | |||
| 39bc897b93 | |||
| 5f35f2ac7d | |||
| e1eb075604 | |||
| d19d9ccd0b | |||
| b4b4ae7a78 | |||
| 149fa9d750 | |||
| 791070c158 | |||
| 3bd2114815 | |||
| 46de48593c | |||
| acd384ae2d | |||
| b77666cbba | |||
| 128ee67bba | |||
| 7417033d7f | |||
| e8a940172c | |||
| 290bdc4566 | |||
| 220aab1fd0 | |||
| 8e9f456029 | |||
| aa450b56f1 | |||
| 6d70f3c237 | |||
| 6384541345 | |||
| ffb014ca3d | |||
| 3c3f92f29b | |||
| 24255f7883 | |||
| 40fa836b81 | |||
| b71caa94ac | |||
| 39658c0c52 | |||
| 9b8522e734 | |||
| 9875bf9c7b | |||
| 4ce4cf5242 | |||
| 52110e0647 | |||
| 19ce0cdc09 | |||
| 2e58f312d5 | |||
| 7523d01e0f | |||
| 7972cb5bdc | |||
| 685d5d3ea3 | |||
| 9f7caf90e3 | |||
| f453194e32 | |||
| 440c637b1f | |||
| d95809a069 | |||
| 6aac972bda | |||
| df3fddc026 | |||
| 1ce49b60d9 | |||
| 8b5b23e6c0 | |||
| 26f329d186 | |||
| 5ace4438e2 | |||
| b8e10225f9 | |||
| 224facf3ba | |||
| 9c12d8ff22 | |||
| 3b4339c8e0 | |||
| 8e12c4cb00 | |||
| efe1678088 | |||
| 2f5be3559e | |||
| 960668ecf1 | |||
| 83084467c6 | |||
| 8464ab6a23 | |||
| 74ec128e62 | |||
| 194c6b8bee | |||
| 69272edba6 | |||
| 38531459df | |||
| b3e3c68f15 | |||
| 5029dff73a | |||
| 689dee9944 | |||
| 68f9898171 | |||
| 08622a41b4 | |||
| 669a3277ff | |||
| e6bd681227 | |||
| 0c5cfdddba | |||
| d08ce79d04 | |||
| bab52c132d | |||
| cc1efd2a46 | |||
| 8297d963bf | |||
| a17c41b4e1 | |||
| b055747d4f | |||
| 4ef76866a5 | |||
| 675ccd4510 | |||
| 31a925b4f0 | |||
| d153575e59 | |||
| 3afc62e525 | |||
| f8446b227b | |||
| 8f937bda0f | |||
| 9d1208bf95 | |||
| e7591439f4 | |||
| fef0b1dd46 | |||
| 3281a1982e | |||
| b8486a489d | |||
| f97d791fe8 | |||
| 657a6c9511 | |||
| aa4fb80465 |
@@ -19,3 +19,9 @@
|
||||
[submodule "rsx_program_decompiler"]
|
||||
path = rsx_program_decompiler
|
||||
url = https://github.com/RPCS3/rsx_program_decompiler
|
||||
[submodule "GSL"]
|
||||
path = GSL
|
||||
url = https://github.com/Microsoft/GSL.git
|
||||
[submodule "libpng"]
|
||||
path = libpng
|
||||
url = https://github.com/RPCS3/libpng
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"userBlacklist": [AlexAltea]
|
||||
"userBlacklist": ["AlexAltea"]
|
||||
}
|
||||
+9
-5
@@ -33,11 +33,13 @@ git:
|
||||
before_install:
|
||||
# shutdown services on Travis, which may have a memory impact
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
echo "yes" | sudo apt-add-repository 'deb http://repos.codelite.org/wx3.0/ubuntu/ precise universe';
|
||||
sudo apt-get install libwxgtk3.0-dev;
|
||||
sudo apt-add-repository -y ppa:libreoffice/ppa;
|
||||
sudo apt-get update;
|
||||
sudo apt-get install libglew-dev;
|
||||
fi;
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$CXX" = "g++" ]; then
|
||||
export CXX="g++-4.9" CC="gcc-4.9" CXXFLAGS="-Wno-format-security";
|
||||
export CXX="g++-5" CC="gcc-5" CXXFLAGS="-Wno-format-security";
|
||||
export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01';
|
||||
elif [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export CXX="clang++-3.6" CC="clang-3.6";
|
||||
@@ -51,7 +53,7 @@ before_install:
|
||||
fi;
|
||||
|
||||
before_script:
|
||||
- git submodule update --init asmjit ffmpeg rsx_program_decompiler
|
||||
- git submodule update --init asmjit ffmpeg rsx_program_decompiler GSL libpng
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cmake ..; else cmake .. -DLLVM_DIR=/usr/local/opt/llvm36/lib/llvm-3.6/share/llvm/cmake; fi
|
||||
@@ -73,15 +75,17 @@ addons:
|
||||
- cmake
|
||||
- libopenal-dev
|
||||
- freeglut3-dev
|
||||
- libglew-dev
|
||||
# - libglew-dev apt version is too old
|
||||
- libc6-dev
|
||||
- llvm-3.6
|
||||
- llvm-3.6-dev
|
||||
- libedit-dev
|
||||
- g++-4.9
|
||||
- g++-5
|
||||
- gcc-5
|
||||
- clang-3.6
|
||||
- libstdc++-4.8-dev
|
||||
- lib32stdc++6
|
||||
- zlib1g-dev
|
||||
coverity_scan:
|
||||
project:
|
||||
name: $TRAVIS_REPO_SLUG
|
||||
|
||||
@@ -11,7 +11,12 @@ if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
message( FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms." )
|
||||
endif()
|
||||
|
||||
# We use libpng's static library and don't need to build the shared library and run the tests
|
||||
set(PNG_SHARED OFF CACHE BOOL "Build shared lib." FORCE)
|
||||
set(PNG_TESTS OFF CACHE BOOL "Build tests." FORCE)
|
||||
|
||||
add_subdirectory( asmjit )
|
||||
add_subdirectory( libpng )
|
||||
# TODO: do real installation, including copying directory structure
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_BINARY_DIR}/bin")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/bin")
|
||||
|
||||
Submodule
+1
Submodule GSL added at fc5fce4f4f
@@ -25,7 +25,7 @@ __Windows__
|
||||
* [Python](https://www.python.org/downloads/) (optional, required only for LLVM build; add to PATH)
|
||||
|
||||
__Linux__
|
||||
* GCC 4.9.0+ or Clang 3.5.0+
|
||||
* GCC 5.1+ or Clang 3.5.0+
|
||||
* Debian & Ubuntu: `sudo apt-get install libopenal-dev libwxgtk3.0-dev build-essential libglew-dev`
|
||||
* Arch: `sudo pacman -S glew openal wxgtk cmake llvm`
|
||||
|
||||
|
||||
+2
-2
@@ -530,7 +530,7 @@ template<typename T> class se_t<T, true>
|
||||
static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)");
|
||||
static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)");
|
||||
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
|
||||
static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
|
||||
//static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
|
||||
static_assert(alignof(type) == alignof(stype), "se_t<> error: unexpected alignment");
|
||||
|
||||
template<typename T2, typename = void> struct bool_converter
|
||||
@@ -642,7 +642,7 @@ template<typename T> class se_t<T, false>
|
||||
static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)");
|
||||
static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)");
|
||||
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
|
||||
static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
|
||||
//static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
|
||||
|
||||
public:
|
||||
se_t() = default;
|
||||
|
||||
+490
-316
File diff suppressed because it is too large
Load Diff
+115
-55
@@ -1,15 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
enum class fsm : u32 // file seek mode
|
||||
{
|
||||
begin,
|
||||
cur,
|
||||
end,
|
||||
};
|
||||
|
||||
namespace fom // file open mode
|
||||
{
|
||||
enum : u32
|
||||
enum open_mode : u32
|
||||
{
|
||||
read = 1 << 0, // enable reading
|
||||
write = 1 << 1, // enable writing
|
||||
@@ -18,19 +11,18 @@ namespace fom // file open mode
|
||||
trunc = 1 << 4, // clear opened file if it's not empty
|
||||
excl = 1 << 5, // failure if the file already exists (used with `create`)
|
||||
|
||||
rewrite = write | create | trunc, // write + create + trunc
|
||||
rewrite = write | create | trunc,
|
||||
};
|
||||
};
|
||||
|
||||
enum class fse : u32 // filesystem (file or dir) error
|
||||
{
|
||||
ok, // no error
|
||||
invalid_arguments,
|
||||
};
|
||||
|
||||
namespace fs
|
||||
{
|
||||
thread_local extern fse g_tls_error;
|
||||
enum seek_mode : u32 // file seek mode
|
||||
{
|
||||
seek_set,
|
||||
seek_cur,
|
||||
seek_end,
|
||||
};
|
||||
|
||||
struct stat_t
|
||||
{
|
||||
@@ -42,6 +34,9 @@ namespace fs
|
||||
s64 ctime;
|
||||
};
|
||||
|
||||
// Get parent directory for the path (returns empty string on failure)
|
||||
std::string get_parent_dir(const std::string& path);
|
||||
|
||||
// Get file information
|
||||
bool stat(const std::string& path, stat_t& info);
|
||||
|
||||
@@ -49,16 +44,16 @@ namespace fs
|
||||
bool exists(const std::string& path);
|
||||
|
||||
// Check whether the file exists and is NOT a directory
|
||||
bool is_file(const std::string& file);
|
||||
bool is_file(const std::string& path);
|
||||
|
||||
// Check whether the directory exists and is NOT a file
|
||||
bool is_dir(const std::string& dir);
|
||||
bool is_dir(const std::string& path);
|
||||
|
||||
// Delete empty directory
|
||||
bool remove_dir(const std::string& dir);
|
||||
bool remove_dir(const std::string& path);
|
||||
|
||||
// Create directory
|
||||
bool create_dir(const std::string& dir);
|
||||
bool create_dir(const std::string& path);
|
||||
|
||||
// Create directories
|
||||
bool create_path(const std::string& path);
|
||||
@@ -70,10 +65,10 @@ namespace fs
|
||||
bool copy_file(const std::string& from, const std::string& to, bool overwrite);
|
||||
|
||||
// Delete file
|
||||
bool remove_file(const std::string& file);
|
||||
bool remove_file(const std::string& path);
|
||||
|
||||
// Change file size (possibly appending zeros)
|
||||
bool truncate_file(const std::string& file, u64 length);
|
||||
bool truncate_file(const std::string& path, u64 length);
|
||||
|
||||
class file final
|
||||
{
|
||||
@@ -83,14 +78,15 @@ namespace fs
|
||||
|
||||
handle_type m_fd = null;
|
||||
|
||||
friend class file_ptr;
|
||||
friend class file_read_map;
|
||||
friend class file_write_map;
|
||||
|
||||
public:
|
||||
file() = default;
|
||||
|
||||
explicit file(const std::string& filename, u32 mode = fom::read)
|
||||
explicit file(const std::string& path, u32 mode = fom::read)
|
||||
{
|
||||
open(filename, mode);
|
||||
open(path, mode);
|
||||
}
|
||||
|
||||
file(file&& other)
|
||||
@@ -120,7 +116,7 @@ namespace fs
|
||||
}
|
||||
|
||||
// Open specified file with specified mode
|
||||
bool open(const std::string& filename, u32 mode = fom::read);
|
||||
bool open(const std::string& path, u32 mode = fom::read);
|
||||
|
||||
// Change file size (possibly appending zero bytes)
|
||||
bool trunc(u64 size) const;
|
||||
@@ -129,7 +125,7 @@ namespace fs
|
||||
bool stat(stat_t& info) const;
|
||||
|
||||
// Close the file explicitly (destructor automatically closes the file)
|
||||
bool close();
|
||||
void close();
|
||||
|
||||
// Read the data from the file and return the amount of data written in buffer
|
||||
u64 read(void* buffer, u64 count) const;
|
||||
@@ -138,92 +134,112 @@ namespace fs
|
||||
u64 write(const void* buffer, u64 count) const;
|
||||
|
||||
// Move file pointer
|
||||
u64 seek(s64 offset, fsm seek_mode = fsm::begin) const;
|
||||
u64 seek(s64 offset, seek_mode whence = seek_set) const;
|
||||
|
||||
// Get file size
|
||||
u64 size() const;
|
||||
|
||||
// Write std::string
|
||||
const file& operator <<(const std::string& str) const
|
||||
// Write std::string unconditionally
|
||||
const file& write(const std::string& str) const
|
||||
{
|
||||
CHECK_ASSERTION(write(str.data(), str.size()) == str.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Write POD
|
||||
// Write POD unconditionally
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> operator <<(const T& data) const
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const T& data) const
|
||||
{
|
||||
CHECK_ASSERTION(write(std::addressof(data), sizeof(T)) == sizeof(T));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Write POD std::vector
|
||||
// Write POD std::vector unconditionally
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> operator <<(const std::vector<T>& vec) const
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const std::vector<T>& vec) const
|
||||
{
|
||||
CHECK_ASSERTION(write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Read std::string
|
||||
// Read std::string, size must be set by resize() method
|
||||
bool read(std::string& str) const
|
||||
{
|
||||
return read(&str[0], str.size()) == str.size();
|
||||
}
|
||||
|
||||
// Read POD
|
||||
// Read POD, sizeof(T) is used
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(T& data) const
|
||||
{
|
||||
return read(&data, sizeof(T)) == sizeof(T);
|
||||
}
|
||||
|
||||
// Read POD std::vector
|
||||
// Read POD std::vector, size must be set by resize() method
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(std::vector<T>& vec) const
|
||||
{
|
||||
return read(vec.data(), sizeof(T) * vec.size()) == sizeof(T) * vec.size();
|
||||
}
|
||||
|
||||
// Convert to std::string
|
||||
operator std::string() const
|
||||
// Read POD (experimental)
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, T> read() const
|
||||
{
|
||||
T result;
|
||||
CHECK_ASSERTION(read(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read full file to std::string
|
||||
std::string to_string() const
|
||||
{
|
||||
std::string result;
|
||||
result.resize(size() - seek(0, fsm::cur));
|
||||
CHECK_ASSERTION(read(result));
|
||||
result.resize(size());
|
||||
CHECK_ASSERTION(seek(0) != -1 && read(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read full file to std::vector
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, std::vector<T>> to_vector() const
|
||||
{
|
||||
std::vector<T> result;
|
||||
result.resize(size() / sizeof(T));
|
||||
CHECK_ASSERTION(seek(0) != -1 && read(result));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class file_ptr final
|
||||
// TODO
|
||||
class file_read_map final
|
||||
{
|
||||
char* m_ptr = nullptr;
|
||||
u64 m_size;
|
||||
|
||||
public:
|
||||
file_ptr() = default;
|
||||
file_read_map() = default;
|
||||
|
||||
file_ptr(file_ptr&& right)
|
||||
file_read_map(file_read_map&& right)
|
||||
: m_ptr(right.m_ptr)
|
||||
, m_size(right.m_size)
|
||||
{
|
||||
right.m_ptr = 0;
|
||||
}
|
||||
|
||||
file_ptr& operator =(file_ptr&& right)
|
||||
file_read_map& operator =(file_read_map&& right)
|
||||
{
|
||||
std::swap(m_ptr, right.m_ptr);
|
||||
std::swap(m_size, right.m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
file_ptr(const file& f)
|
||||
file_read_map(const file& f)
|
||||
{
|
||||
reset(f);
|
||||
}
|
||||
|
||||
~file_ptr()
|
||||
~file_read_map()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
@@ -234,6 +250,52 @@ namespace fs
|
||||
// Close file mapping
|
||||
void reset();
|
||||
|
||||
// Get pointer
|
||||
operator const char*() const
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO
|
||||
class file_write_map final
|
||||
{
|
||||
char* m_ptr = nullptr;
|
||||
u64 m_size;
|
||||
|
||||
public:
|
||||
file_write_map() = default;
|
||||
|
||||
file_write_map(file_write_map&& right)
|
||||
: m_ptr(right.m_ptr)
|
||||
, m_size(right.m_size)
|
||||
{
|
||||
right.m_ptr = 0;
|
||||
}
|
||||
|
||||
file_write_map& operator =(file_write_map&& right)
|
||||
{
|
||||
std::swap(m_ptr, right.m_ptr);
|
||||
std::swap(m_size, right.m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
file_write_map(const file& f)
|
||||
{
|
||||
reset(f);
|
||||
}
|
||||
|
||||
~file_write_map()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// Open file mapping
|
||||
void reset(const file& f);
|
||||
|
||||
// Close file mapping
|
||||
void reset();
|
||||
|
||||
// Get pointer
|
||||
operator char*() const
|
||||
{
|
||||
@@ -285,7 +347,7 @@ namespace fs
|
||||
bool open(const std::string& dirname);
|
||||
|
||||
// Close the directory explicitly (destructor automatically closes the directory)
|
||||
bool close();
|
||||
void close();
|
||||
|
||||
// Get next directory entry (UTF-8 name and file stat)
|
||||
bool read(std::string& name, stat_t& info);
|
||||
@@ -318,18 +380,16 @@ namespace fs
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_ok;
|
||||
|
||||
if (mode_ == mode::from_first)
|
||||
{
|
||||
is_ok = m_parent->first(m_entry.name, m_entry.info);
|
||||
m_parent->first(m_entry.name, m_entry.info);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_ok = m_parent->read(m_entry.name, m_entry.info);
|
||||
m_parent->read(m_entry.name, m_entry.info);
|
||||
}
|
||||
|
||||
if (!is_ok)
|
||||
if (m_entry.name.empty())
|
||||
{
|
||||
m_parent = nullptr;
|
||||
}
|
||||
@@ -364,8 +424,8 @@ namespace fs
|
||||
};
|
||||
|
||||
// Get configuration directory
|
||||
std::string get_config_dir();
|
||||
const std::string& get_config_dir();
|
||||
|
||||
// Get executable directory
|
||||
std::string get_executable_dir();
|
||||
const std::string& get_executable_dir();
|
||||
}
|
||||
|
||||
@@ -35,10 +35,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <cstdint>
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#define _fpclass(x) std::fpclassify(x)
|
||||
#define INFINITE 0xFFFFFFFF
|
||||
|
||||
|
||||
+121
-256
@@ -1,6 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include <iostream>
|
||||
#include <cinttypes>
|
||||
#include "stdafx.h"
|
||||
#include "Thread.h"
|
||||
#include "File.h"
|
||||
#include "Log.h"
|
||||
@@ -9,277 +7,144 @@
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
using namespace Log;
|
||||
|
||||
std::unique_ptr<LogManager> g_log_manager;
|
||||
|
||||
u32 LogMessage::size() const
|
||||
namespace _log
|
||||
{
|
||||
//1 byte for NULL terminator
|
||||
return (u32)(sizeof(LogMessage::size_type) + sizeof(LogType) + sizeof(Severity) + sizeof(std::string::value_type) * mText.size() + 1);
|
||||
}
|
||||
|
||||
void LogMessage::serialize(char *output) const
|
||||
{
|
||||
LogMessage::size_type size = this->size();
|
||||
memcpy(output, &size, sizeof(LogMessage::size_type));
|
||||
output += sizeof(LogMessage::size_type);
|
||||
memcpy(output, &mType, sizeof(LogType));
|
||||
output += sizeof(LogType);
|
||||
memcpy(output, &mServerity, sizeof(Severity));
|
||||
output += sizeof(Severity);
|
||||
memcpy(output, mText.c_str(), mText.size() );
|
||||
output += sizeof(std::string::value_type)*mText.size();
|
||||
*output = '\0';
|
||||
|
||||
}
|
||||
LogMessage LogMessage::deserialize(char *input, u32* size_out)
|
||||
{
|
||||
LogMessage msg;
|
||||
LogMessage::size_type msgSize = *(reinterpret_cast<LogMessage::size_type*>(input));
|
||||
input += sizeof(LogMessage::size_type);
|
||||
msg.mType = *(reinterpret_cast<LogType*>(input));
|
||||
input += sizeof(LogType);
|
||||
msg.mServerity = *(reinterpret_cast<Severity*>(input));
|
||||
input += sizeof(Severity);
|
||||
if (msgSize > 9000)
|
||||
logger& get_logger()
|
||||
{
|
||||
int wtf = 6;
|
||||
// Use magic static for global logger instance
|
||||
static logger instance;
|
||||
return instance;
|
||||
}
|
||||
msg.mText.append(input, msgSize - 1 - sizeof(Severity) - sizeof(LogType));
|
||||
if (size_out){(*size_out) = msgSize;}
|
||||
return msg;
|
||||
|
||||
file_listener g_log_file(_PRGNAME_ ".log");
|
||||
|
||||
file_writer g_tty_file("TTY.log");
|
||||
|
||||
channel GENERAL("", level::notice);
|
||||
channel LOADER("LDR", level::notice);
|
||||
channel MEMORY("MEM", level::notice);
|
||||
channel RSX("RSX", level::notice);
|
||||
channel HLE("HLE", level::notice);
|
||||
channel PPU("PPU", level::notice);
|
||||
channel SPU("SPU", level::notice);
|
||||
channel ARMv7("ARMv7");
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogChannel::LogChannel() : LogChannel("unknown")
|
||||
{}
|
||||
|
||||
LogChannel::LogChannel(const std::string& name) :
|
||||
name(name)
|
||||
, mEnabled(true)
|
||||
, mLogLevel(Severity::Warning)
|
||||
{}
|
||||
|
||||
void LogChannel::log(const LogMessage &msg)
|
||||
_log::listener::listener()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mListenerLock);
|
||||
for (auto &listener : mListeners)
|
||||
// Register self
|
||||
get_logger().add_listener(this);
|
||||
}
|
||||
|
||||
_log::listener::~listener()
|
||||
{
|
||||
// Unregister self
|
||||
get_logger().remove_listener(this);
|
||||
}
|
||||
|
||||
_log::channel::channel(const std::string& name, _log::level init_level)
|
||||
: name{ name }
|
||||
, enabled{ init_level }
|
||||
{
|
||||
// TODO: register config property "name" associated with "enabled" member
|
||||
}
|
||||
|
||||
void _log::logger::add_listener(_log::listener* listener)
|
||||
{
|
||||
std::lock_guard<shared_mutex> lock(m_mutex);
|
||||
|
||||
m_listeners.emplace(listener);
|
||||
}
|
||||
|
||||
void _log::logger::remove_listener(_log::listener* listener)
|
||||
{
|
||||
std::lock_guard<shared_mutex> lock(m_mutex);
|
||||
|
||||
m_listeners.erase(listener);
|
||||
}
|
||||
|
||||
void _log::logger::broadcast(const _log::channel& ch, _log::level sev, const std::string& text) const
|
||||
{
|
||||
reader_lock lock(m_mutex);
|
||||
|
||||
for (auto listener : m_listeners)
|
||||
{
|
||||
listener->log(msg);
|
||||
listener->log(ch, sev, text);
|
||||
}
|
||||
}
|
||||
|
||||
void LogChannel::addListener(std::shared_ptr<LogListener> listener)
|
||||
void _log::broadcast(const _log::channel& ch, _log::level sev, const std::string& text)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mListenerLock);
|
||||
mListeners.insert(listener);
|
||||
}
|
||||
void LogChannel::removeListener(std::shared_ptr<LogListener> listener)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mListenerLock);
|
||||
mListeners.erase(listener);
|
||||
get_logger().broadcast(ch, sev, text);
|
||||
}
|
||||
|
||||
struct CoutListener : LogListener
|
||||
_log::file_writer::file_writer(const std::string& name)
|
||||
{
|
||||
void log(const LogMessage &msg) override
|
||||
try
|
||||
{
|
||||
std::cerr << msg.mText << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct FileListener : LogListener
|
||||
{
|
||||
fs::file mFile;
|
||||
bool mPrependChannelName;
|
||||
|
||||
FileListener(const std::string& name = _PRGNAME_ ".log", bool prependChannel = true)
|
||||
: mFile(fs::get_config_dir() + name, fom::rewrite)
|
||||
, mPrependChannelName(prependChannel)
|
||||
{
|
||||
if (!mFile)
|
||||
if (!m_file.open(fs::get_config_dir() + name, fom::rewrite | fom::append))
|
||||
{
|
||||
throw EXCEPTION("Can't create log file %s (error %d)", name, errno);
|
||||
}
|
||||
}
|
||||
catch (const fmt::exception& e)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
MessageBoxA(0, ("Can't create log file: " + name).c_str(), "Error", MB_ICONERROR);
|
||||
MessageBoxA(0, e.what(), "_log::file_writer() failed", MB_ICONERROR);
|
||||
#else
|
||||
std::printf("Can't create log file: %s\n", name.c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void log(const LogMessage &msg) override
|
||||
{
|
||||
std::string text = msg.mText;
|
||||
if (mPrependChannelName)
|
||||
{
|
||||
text.insert(0, gTypeNameTable[static_cast<u32>(msg.mType)].mName);
|
||||
|
||||
if (msg.mType == Log::TTY)
|
||||
{
|
||||
text = fmt::escape(text);
|
||||
if (text[text.length() - 1] != '\n')
|
||||
{
|
||||
text += '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mFile << text;
|
||||
}
|
||||
};
|
||||
|
||||
LogManager::LogManager()
|
||||
#ifdef BUFFERED_LOGGING
|
||||
: mExiting(false), mLogConsumer()
|
||||
#endif
|
||||
{
|
||||
auto it = mChannels.begin();
|
||||
std::shared_ptr<LogListener> listener(new FileListener());
|
||||
for (const LogTypeName& name : gTypeNameTable)
|
||||
{
|
||||
it->name = name.mName;
|
||||
it->addListener(listener);
|
||||
it++;
|
||||
}
|
||||
std::shared_ptr<LogListener> TTYListener(new FileListener("TTY.log", false));
|
||||
getChannel(TTY).addListener(TTYListener);
|
||||
#ifdef BUFFERED_LOGGING
|
||||
mLogConsumer = std::thread(&LogManager::consumeLog, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
LogManager::~LogManager()
|
||||
{
|
||||
#ifdef BUFFERED_LOGGING
|
||||
mExiting = true;
|
||||
mBufferReady.notify_all();
|
||||
mLogConsumer.join();
|
||||
}
|
||||
|
||||
void LogManager::consumeLog()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mStatusMut);
|
||||
while (!mExiting)
|
||||
{
|
||||
mBufferReady.wait(lock);
|
||||
mBuffer.lockGet();
|
||||
size_t size = mBuffer.size();
|
||||
std::vector<char> local_messages(size);
|
||||
mBuffer.popN(&local_messages.front(), size);
|
||||
mBuffer.unlockGet();
|
||||
|
||||
u32 cursor = 0;
|
||||
u32 removed = 0;
|
||||
while (cursor < size)
|
||||
{
|
||||
Log::LogMessage msg = Log::LogMessage::deserialize(local_messages.data() + cursor, &removed);
|
||||
cursor += removed;
|
||||
getChannel(msg.mType).log(msg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LogManager::log(LogMessage msg)
|
||||
{
|
||||
//don't do any formatting changes or filtering to the TTY output since we
|
||||
//use the raw output to do diffs with the output of a real PS3 and some
|
||||
//programs write text in single bytes to the console
|
||||
if (msg.mType != TTY)
|
||||
{
|
||||
std::string prefix;
|
||||
switch (msg.mServerity)
|
||||
{
|
||||
case Severity::Success:
|
||||
prefix = "S ";
|
||||
break;
|
||||
case Severity::Notice:
|
||||
prefix = "! ";
|
||||
break;
|
||||
case Severity::Warning:
|
||||
prefix = "W ";
|
||||
break;
|
||||
case Severity::Error:
|
||||
prefix = "E ";
|
||||
break;
|
||||
}
|
||||
if (auto thr = thread_ctrl::get_current())
|
||||
{
|
||||
prefix += "{" + thr->get_name() + "} ";
|
||||
}
|
||||
msg.mText.insert(0, prefix);
|
||||
msg.mText.append(1,'\n');
|
||||
}
|
||||
#ifdef BUFFERED_LOGGING
|
||||
size_t size = msg.size();
|
||||
std::vector<char> temp_buffer(size);
|
||||
msg.serialize(temp_buffer.data());
|
||||
mBuffer.pushRange(temp_buffer.begin(), temp_buffer.end());
|
||||
mBufferReady.notify_one();
|
||||
#else
|
||||
mChannels[static_cast<u32>(msg.mType)].log(msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LogManager::addListener(std::shared_ptr<LogListener> listener)
|
||||
{
|
||||
for (auto& channel : mChannels)
|
||||
{
|
||||
channel.addListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void LogManager::removeListener(std::shared_ptr<LogListener> listener)
|
||||
{
|
||||
for (auto& channel : mChannels)
|
||||
{
|
||||
channel.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
LogManager& LogManager::getInstance()
|
||||
{
|
||||
if (!g_log_manager)
|
||||
{
|
||||
g_log_manager.reset(new LogManager());
|
||||
}
|
||||
|
||||
return *g_log_manager;
|
||||
}
|
||||
|
||||
LogChannel &LogManager::getChannel(LogType type)
|
||||
{
|
||||
return mChannels[static_cast<u32>(type)];
|
||||
}
|
||||
|
||||
void log_message(Log::LogType type, Log::Severity sev, const char* text)
|
||||
{
|
||||
log_message(type, sev, std::string(text));
|
||||
}
|
||||
|
||||
void log_message(Log::LogType type, Log::Severity sev, std::string text)
|
||||
{
|
||||
if (g_log_manager)
|
||||
{
|
||||
g_log_manager->log({ type, sev, std::move(text) });
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto severity =
|
||||
sev == Severity::Notice ? "Notice" :
|
||||
sev == Severity::Warning ? "Warning" :
|
||||
sev == Severity::Success ? "Success" :
|
||||
sev == Severity::Error ? "Error" : "Unknown";
|
||||
|
||||
#ifdef _WIN32
|
||||
MessageBoxA(0, text.c_str(), severity,
|
||||
sev == Severity::Notice ? MB_ICONINFORMATION :
|
||||
sev == Severity::Warning ? MB_ICONEXCLAMATION :
|
||||
sev == Severity::Error ? MB_ICONERROR : MB_ICONINFORMATION);
|
||||
#else
|
||||
std::printf("[Log:%s] %s\n", severity, text.c_str());
|
||||
std::printf("_log::file_writer() failed: %s\n", e.what());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void _log::file_writer::log(const std::string& text)
|
||||
{
|
||||
m_file.write(text);
|
||||
}
|
||||
|
||||
std::size_t _log::file_writer::size() const
|
||||
{
|
||||
return m_file.seek(0, fs::seek_cur);
|
||||
}
|
||||
|
||||
void _log::file_listener::log(const _log::channel& ch, _log::level sev, const std::string& text)
|
||||
{
|
||||
std::string msg; msg.reserve(text.size() + 200);
|
||||
|
||||
// Used character: U+00B7 (Middle Dot)
|
||||
switch (sev)
|
||||
{
|
||||
case level::always: msg = u8"·A "; break;
|
||||
case level::fatal: msg = u8"·F "; break;
|
||||
case level::error: msg = u8"·E "; break;
|
||||
case level::todo: msg = u8"·U "; break;
|
||||
case level::success: msg = u8"·S "; break;
|
||||
case level::warning: msg = u8"·W "; break;
|
||||
case level::notice: msg = u8"·! "; break;
|
||||
case level::trace: msg = u8"·T "; break;
|
||||
}
|
||||
|
||||
// TODO: print time?
|
||||
|
||||
if (auto t = thread_ctrl::get_current())
|
||||
{
|
||||
msg += '{';
|
||||
msg += t->get_name();
|
||||
msg += "} ";
|
||||
}
|
||||
|
||||
if (ch.name.size())
|
||||
{
|
||||
msg += ch.name;
|
||||
msg += sev == level::todo ? " TODO: " : ": ";
|
||||
}
|
||||
else if (sev == level::todo)
|
||||
{
|
||||
msg += "TODO: ";
|
||||
}
|
||||
|
||||
msg += text;
|
||||
msg += '\n';
|
||||
|
||||
file_writer::log(msg);
|
||||
}
|
||||
|
||||
+127
-106
@@ -1,134 +1,155 @@
|
||||
#pragma once
|
||||
#include "Utilities/MTRingbuffer.h"
|
||||
|
||||
//#define BUFFERED_LOGGING 1
|
||||
#include "SharedMutex.h"
|
||||
|
||||
//first parameter is of type Log::LogType and text is of type std::string
|
||||
|
||||
#define LOG_SUCCESS(logType, text, ...) log_message(logType, Log::Severity::Success, text, ##__VA_ARGS__)
|
||||
#define LOG_NOTICE(logType, text, ...) log_message(logType, Log::Severity::Notice, text, ##__VA_ARGS__)
|
||||
#define LOG_WARNING(logType, text, ...) log_message(logType, Log::Severity::Warning, text, ##__VA_ARGS__)
|
||||
#define LOG_ERROR(logType, text, ...) log_message(logType, Log::Severity::Error, text, ##__VA_ARGS__)
|
||||
|
||||
namespace Log
|
||||
namespace _log
|
||||
{
|
||||
const unsigned int MAX_LOG_BUFFER_LENGTH = 1024*1024;
|
||||
const unsigned int gBuffSize = 1000;
|
||||
|
||||
enum LogType : u32
|
||||
enum class level : uint
|
||||
{
|
||||
GENERAL = 0,
|
||||
LOADER,
|
||||
MEMORY,
|
||||
RSX,
|
||||
HLE,
|
||||
PPU,
|
||||
SPU,
|
||||
ARMv7,
|
||||
TTY,
|
||||
always, // highest level (unused, cannot be disabled)
|
||||
fatal,
|
||||
error,
|
||||
todo,
|
||||
success,
|
||||
warning,
|
||||
notice,
|
||||
trace, // lowest level (usually disabled)
|
||||
};
|
||||
|
||||
struct channel;
|
||||
struct listener;
|
||||
|
||||
struct LogTypeName
|
||||
// Log manager
|
||||
class logger final
|
||||
{
|
||||
LogType mType;
|
||||
std::string mName;
|
||||
mutable shared_mutex m_mutex;
|
||||
|
||||
std::set<listener*> m_listeners;
|
||||
|
||||
public:
|
||||
// Register listener
|
||||
void add_listener(listener* listener);
|
||||
|
||||
// Unregister listener
|
||||
void remove_listener(listener* listener);
|
||||
|
||||
// Send log message to all listeners
|
||||
void broadcast(const channel& ch, level sev, const std::string& text) const;
|
||||
};
|
||||
|
||||
//well I'd love make_array() but alas manually counting is not the end of the world
|
||||
static const std::array<LogTypeName, 9> gTypeNameTable = { {
|
||||
{ GENERAL, "G: " },
|
||||
{ LOADER, "LDR: " },
|
||||
{ MEMORY, "MEM: " },
|
||||
{ RSX, "RSX: " },
|
||||
{ HLE, "HLE: " },
|
||||
{ PPU, "PPU: " },
|
||||
{ SPU, "SPU: " },
|
||||
{ ARMv7, "ARM: " },
|
||||
{ TTY, "TTY: " }
|
||||
} };
|
||||
// Send log message to global logger instance
|
||||
void broadcast(const channel& ch, level sev, const std::string& text);
|
||||
|
||||
enum class Severity : u32
|
||||
// Log channel (source)
|
||||
struct channel
|
||||
{
|
||||
Notice = 0,
|
||||
Warning,
|
||||
Success,
|
||||
Error,
|
||||
// Channel prefix (also used for identification)
|
||||
const std::string name;
|
||||
|
||||
// The lowest logging level enabled for this channel (used for early filtering)
|
||||
std::atomic<level> enabled;
|
||||
|
||||
// Initialization (max level enabled by default)
|
||||
channel(const std::string& name, level = level::trace);
|
||||
|
||||
virtual ~channel() = default;
|
||||
|
||||
// Log without formatting
|
||||
force_inline void log(level sev, const std::string& text) const
|
||||
{
|
||||
if (sev <= enabled)
|
||||
broadcast(*this, sev, text);
|
||||
}
|
||||
|
||||
// Log with formatting
|
||||
template<typename... Args>
|
||||
force_inline safe_buffers void format(level sev, const char* fmt, const Args&... args) const
|
||||
{
|
||||
if (sev <= enabled)
|
||||
broadcast(*this, sev, fmt::format(fmt, fmt::do_unveil(args)...));
|
||||
}
|
||||
|
||||
#define GEN_LOG_METHOD(_sev)\
|
||||
template<typename... Args>\
|
||||
force_inline void _sev(const char* fmt, const Args&... args)\
|
||||
{\
|
||||
return format<Args...>(level::_sev, fmt, args...);\
|
||||
}
|
||||
|
||||
GEN_LOG_METHOD(fatal)
|
||||
GEN_LOG_METHOD(error)
|
||||
GEN_LOG_METHOD(todo)
|
||||
GEN_LOG_METHOD(success)
|
||||
GEN_LOG_METHOD(warning)
|
||||
GEN_LOG_METHOD(notice)
|
||||
GEN_LOG_METHOD(trace)
|
||||
|
||||
#undef GEN_LOG_METHOD
|
||||
};
|
||||
|
||||
struct LogMessage
|
||||
// Log listener (destination)
|
||||
struct listener
|
||||
{
|
||||
using size_type = u32;
|
||||
LogType mType;
|
||||
Severity mServerity;
|
||||
std::string mText;
|
||||
listener();
|
||||
|
||||
virtual ~listener();
|
||||
|
||||
u32 size() const;
|
||||
void serialize(char *output) const;
|
||||
static LogMessage deserialize(char *input, u32* size_out=nullptr);
|
||||
virtual void log(const channel& ch, level sev, const std::string& text) = 0;
|
||||
};
|
||||
|
||||
struct LogListener
|
||||
class file_writer
|
||||
{
|
||||
virtual ~LogListener() {};
|
||||
virtual void log(const LogMessage &msg) = 0;
|
||||
// Could be memory-mapped file
|
||||
fs::file m_file;
|
||||
|
||||
public:
|
||||
file_writer(const std::string& name);
|
||||
|
||||
virtual ~file_writer() = default;
|
||||
|
||||
// Append raw data
|
||||
void log(const std::string& text);
|
||||
|
||||
// Get current file size (may be used by secondary readers)
|
||||
std::size_t size() const;
|
||||
};
|
||||
|
||||
struct LogChannel
|
||||
struct file_listener : public file_writer, public listener
|
||||
{
|
||||
LogChannel();
|
||||
LogChannel(const std::string& name);
|
||||
LogChannel(LogChannel& other) = delete;
|
||||
void log(const LogMessage &msg);
|
||||
void addListener(std::shared_ptr<LogListener> listener);
|
||||
void removeListener(std::shared_ptr<LogListener> listener);
|
||||
std::string name;
|
||||
private:
|
||||
bool mEnabled;
|
||||
Severity mLogLevel;
|
||||
std::mutex mListenerLock;
|
||||
std::set<std::shared_ptr<LogListener>> mListeners;
|
||||
file_listener(const std::string& name)
|
||||
: file_writer(name)
|
||||
, listener()
|
||||
{
|
||||
}
|
||||
|
||||
// Encode level, current thread name, channel name and write log message
|
||||
virtual void log(const channel& ch, level sev, const std::string& text) override;
|
||||
};
|
||||
|
||||
struct LogManager
|
||||
{
|
||||
LogManager();
|
||||
~LogManager();
|
||||
static LogManager& getInstance();
|
||||
LogChannel& getChannel(LogType type);
|
||||
void log(LogMessage msg);
|
||||
void addListener(std::shared_ptr<LogListener> listener);
|
||||
void removeListener(std::shared_ptr<LogListener> listener);
|
||||
#ifdef BUFFERED_LOGGING
|
||||
void consumeLog();
|
||||
#endif
|
||||
private:
|
||||
#ifdef BUFFERED_LOGGING
|
||||
MTRingbuffer<char, MAX_LOG_BUFFER_LENGTH> mBuffer;
|
||||
std::condition_variable mBufferReady;
|
||||
std::mutex mStatusMut;
|
||||
std::atomic<bool> mExiting;
|
||||
std::thread mLogConsumer;
|
||||
#endif
|
||||
std::array<LogChannel, std::tuple_size<decltype(gTypeNameTable)>::value> mChannels;
|
||||
//std::array<LogChannel,gTypeNameTable.size()> mChannels; //TODO: use this once Microsoft sorts their shit out
|
||||
};
|
||||
// Global variable for RPCS3.log
|
||||
extern file_listener g_log_file;
|
||||
|
||||
// Global variable for TTY.log
|
||||
extern file_writer g_tty_file;
|
||||
|
||||
// Small set of predefined channels:
|
||||
|
||||
extern channel GENERAL;
|
||||
extern channel LOADER;
|
||||
extern channel MEMORY;
|
||||
extern channel RSX;
|
||||
extern channel HLE;
|
||||
extern channel PPU;
|
||||
extern channel SPU;
|
||||
extern channel ARMv7;
|
||||
}
|
||||
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::GENERAL; } } GENERAL;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::LOADER; } } LOADER;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::MEMORY; } } MEMORY;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::RSX; } } RSX;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::HLE; } } HLE;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::PPU; } } PPU;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::SPU; } } SPU;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::ARMv7; } } ARMv7;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::TTY; } } TTY;
|
||||
// Legacy:
|
||||
|
||||
void log_message(Log::LogType type, Log::Severity sev, const char* text);
|
||||
void log_message(Log::LogType type, Log::Severity sev, std::string text);
|
||||
|
||||
template<typename... Args> never_inline void log_message(Log::LogType type, Log::Severity sev, const char* fmt, Args... args)
|
||||
{
|
||||
log_message(type, sev, fmt::format(fmt, fmt::do_unveil(args)...));
|
||||
}
|
||||
#define LOG_SUCCESS(ch, fmt, ...) _log::ch.success(fmt, ##__VA_ARGS__)
|
||||
#define LOG_NOTICE(ch, fmt, ...) _log::ch.notice (fmt, ##__VA_ARGS__)
|
||||
#define LOG_WARNING(ch, fmt, ...) _log::ch.warning(fmt, ##__VA_ARGS__)
|
||||
#define LOG_ERROR(ch, fmt, ...) _log::ch.error (fmt, ##__VA_ARGS__)
|
||||
#define LOG_TODO(ch, fmt, ...) _log::ch.todo (fmt, ##__VA_ARGS__)
|
||||
#define LOG_TRACE(ch, fmt, ...) _log::ch.trace (fmt, ##__VA_ARGS__)
|
||||
#define LOG_FATAL(ch, fmt, ...) _log::ch.fatal (fmt, ##__VA_ARGS__)
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
//Simple non-resizable FIFO Ringbuffer that can be simultaneously be read from and written to
|
||||
//if we ever get to use boost please replace this with boost::circular_buffer, there's no reason
|
||||
//why we would have to keep this amateur attempt at such a fundamental data-structure around
|
||||
template< typename T, unsigned int MAX_MTRINGBUFFER_BUFFER_SIZE>
|
||||
class MTRingbuffer{
|
||||
std::array<T, MAX_MTRINGBUFFER_BUFFER_SIZE> mBuffer;
|
||||
//this is a recursive mutex because the get methods lock it but the only
|
||||
//way to be sure that they do not block is to check the size and the only
|
||||
//way to check the size and use get atomically is to lock this mutex,
|
||||
//so it goes:
|
||||
//lock get mutex-->check size-->call get-->lock get mutex-->unlock get mutex-->return from get-->unlock get mutex
|
||||
std::recursive_mutex mMutGet;
|
||||
std::mutex mMutPut;
|
||||
|
||||
size_t mGet;
|
||||
size_t mPut;
|
||||
size_t moveGet(size_t by = 1){ return (mGet + by) % MAX_MTRINGBUFFER_BUFFER_SIZE; }
|
||||
size_t movePut(size_t by = 1){ return (mPut + by) % MAX_MTRINGBUFFER_BUFFER_SIZE; }
|
||||
public:
|
||||
MTRingbuffer() : mGet(0), mPut(0){}
|
||||
|
||||
//blocks until there's something to get, so check "spaceLeft()" if you want to avoid blocking
|
||||
//also lock the get mutex around the spaceLeft() check and the pop if you want to avoid racing
|
||||
T pop()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mMutGet);
|
||||
while (mGet == mPut)
|
||||
{
|
||||
//wait until there's actually something to get
|
||||
//throwing an exception might be better, blocking here is a little awkward
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
}
|
||||
size_t ret = mGet;
|
||||
mGet = moveGet();
|
||||
return mBuffer[ret];
|
||||
}
|
||||
|
||||
//blocks if the buffer is full until there's enough room
|
||||
void push(T &putEle)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutPut);
|
||||
while (movePut() == mGet)
|
||||
{
|
||||
//if this is reached a lot it's time to increase the buffer size
|
||||
//or implement dynamic re-sizing
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
}
|
||||
mBuffer[mPut] = std::forward(putEle);
|
||||
mPut = movePut();
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return mGet == mPut;
|
||||
}
|
||||
|
||||
//returns the amount of free places, this is the amount of actual free spaces-1
|
||||
//since mGet==mPut signals an empty buffer we can't actually use the last free
|
||||
//space, so we shouldn't report it as free.
|
||||
size_t spaceLeft() //apparently free() is a macro definition in msvc in some conditions
|
||||
{
|
||||
if (mGet < mPut)
|
||||
{
|
||||
return mBuffer.size() - (mPut - mGet) - 1;
|
||||
}
|
||||
else if (mGet > mPut)
|
||||
{
|
||||
return mGet - mPut - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mBuffer.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t size()
|
||||
{
|
||||
//the magic -1 is the same magic 1 that is explained in the spaceLeft() function
|
||||
return mBuffer.size() - spaceLeft() - 1;
|
||||
}
|
||||
|
||||
//takes random access iterator to T
|
||||
template<typename IteratorType>
|
||||
void pushRange(IteratorType from, IteratorType until)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutPut);
|
||||
size_t length = until - from;
|
||||
|
||||
//if whatever we're trying to store is greater than the entire buffer the following loop will be infinite
|
||||
assert(mBuffer.size() > length);
|
||||
while (spaceLeft() < length)
|
||||
{
|
||||
//if this is reached a lot it's time to increase the buffer size
|
||||
//or implement dynamic re-sizing
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
}
|
||||
if (mPut + length <= mBuffer.size())
|
||||
{
|
||||
std::copy(from, until, mBuffer.begin() + mPut);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t tillEnd = mBuffer.size() - mPut;
|
||||
std::copy(from, from + tillEnd, mBuffer.begin() + mPut);
|
||||
std::copy(from + tillEnd, until, mBuffer.begin());
|
||||
}
|
||||
mPut = movePut(length);
|
||||
|
||||
}
|
||||
|
||||
//takes output iterator to T
|
||||
template<typename IteratorType>
|
||||
void popN(IteratorType output, size_t n)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mMutGet);
|
||||
//make sure we're not trying to retrieve more than is in
|
||||
assert(n <= size());
|
||||
peekN<IteratorType>(output, n);
|
||||
mGet = moveGet(n);
|
||||
}
|
||||
|
||||
//takes output iterator to T
|
||||
template<typename IteratorType>
|
||||
void peekN(IteratorType output, size_t n)
|
||||
{
|
||||
size_t lGet = mGet;
|
||||
if (lGet + n <= mBuffer.size())
|
||||
{
|
||||
std::copy_n(mBuffer.begin() + lGet, n, output);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto next = std::copy(mBuffer.begin() + lGet, mBuffer.end(), output);
|
||||
std::copy_n(mBuffer.begin(), n - (mBuffer.size() - lGet), next);
|
||||
}
|
||||
}
|
||||
|
||||
//well this is just asking for trouble
|
||||
//but the comment above the declaration of mMutGet explains why it's there
|
||||
//if there's a better way please remove this
|
||||
void lockGet()
|
||||
{
|
||||
mMutGet.lock();
|
||||
}
|
||||
|
||||
//well this is just asking for trouble
|
||||
//but the comment above the declaration of mMutGet explains why it's there
|
||||
//if there's a better way please remove this
|
||||
void unlockGet()
|
||||
{
|
||||
mMutGet.unlock();
|
||||
}
|
||||
};
|
||||
+7
-6
@@ -155,19 +155,19 @@ namespace fmt
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct unveil<char*, false>
|
||||
template<> struct unveil<const char*, false>
|
||||
{
|
||||
using result_type = const char*;
|
||||
using result_type = const char* const;
|
||||
|
||||
force_inline static result_type get_value(const char* arg)
|
||||
force_inline static result_type get_value(const char* const& arg)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
template<std::size_t N> struct unveil<const char[N], false>
|
||||
template<std::size_t N> struct unveil<char[N], false>
|
||||
{
|
||||
using result_type = const char*;
|
||||
using result_type = const char* const;
|
||||
|
||||
force_inline static result_type get_value(const char(&arg)[N])
|
||||
{
|
||||
@@ -220,7 +220,8 @@ namespace fmt
|
||||
// vm::ptr, vm::bptr, ... (fmt::do_unveil) (vm_ptr.h) (with appropriate address type, using .addr() can be avoided)
|
||||
// vm::ref, vm::bref, ... (fmt::do_unveil) (vm_ref.h)
|
||||
//
|
||||
template<typename... Args> safe_buffers std::string format(const char* fmt, Args... args)
|
||||
template<typename... Args>
|
||||
safe_buffers std::string format(const char* fmt, const Args&... args)
|
||||
{
|
||||
// fixed stack buffer for the first attempt
|
||||
std::array<char, 4096> fixed_buf;
|
||||
|
||||
+48
-41
@@ -19,7 +19,7 @@
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
|
||||
void report_fatal_error(const std::string& msg)
|
||||
static void report_fatal_error(const std::string& msg)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const auto& text = msg + "\n\nPlease report this error to the developers. Press (Ctrl+C) to copy this message.";
|
||||
@@ -794,16 +794,18 @@ size_t get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, siz
|
||||
return d_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that can be customised by GSRender backends to track memory access.
|
||||
* Backends can protect memory pages and get this callback called when an access
|
||||
* violation is met.
|
||||
* Should return true if the backend handles the access violation.
|
||||
*/
|
||||
std::function<bool(u32 addr)> gfxHandler = [](u32) { return false; };
|
||||
namespace rsx
|
||||
{
|
||||
extern std::function<bool(u32 addr, bool is_writing)> g_access_violation_handler;
|
||||
}
|
||||
|
||||
bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
{
|
||||
if (rsx::g_access_violation_handler && rsx::g_access_violation_handler(addr, is_writing))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
auto code = (const u8*)RIP(context);
|
||||
|
||||
x64_op_t op;
|
||||
@@ -811,9 +813,6 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
size_t d_size;
|
||||
size_t i_size;
|
||||
|
||||
if (gfxHandler(addr))
|
||||
return true;
|
||||
|
||||
// decode single x64 instruction that causes memory access
|
||||
decode_x64_reg_op(code, op, reg, d_size, i_size);
|
||||
|
||||
@@ -1148,7 +1147,7 @@ void prepare_throw_access_violation(x64_context* context, const char* cause, u32
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
const auto g_exception_handler = AddVectoredExceptionHandler(1, [](PEXCEPTION_POINTERS pExp) -> LONG
|
||||
static LONG exception_handler(PEXCEPTION_POINTERS pExp)
|
||||
{
|
||||
const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0);
|
||||
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
||||
@@ -1161,9 +1160,9 @@ const auto g_exception_handler = AddVectoredExceptionHandler(1, [](PEXCEPTION_PO
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const auto g_exception_filter = SetUnhandledExceptionFilter([](PEXCEPTION_POINTERS pExp) -> LONG
|
||||
static LONG exception_filter(PEXCEPTION_POINTERS pExp)
|
||||
{
|
||||
std::string msg = fmt::format("Unhandled Win32 exception 0x%08X.\n", pExp->ExceptionRecord->ExceptionCode);
|
||||
|
||||
@@ -1191,16 +1190,36 @@ const auto g_exception_filter = SetUnhandledExceptionFilter([](PEXCEPTION_POINTE
|
||||
}
|
||||
}
|
||||
|
||||
msg += fmt::format("Instruction address: %p.\n", pExp->ContextRecord->Rip);
|
||||
msg += fmt::format("Image base: %p.", GetModuleHandle(NULL));
|
||||
|
||||
// TODO: print registers and the callstack
|
||||
|
||||
// Report fatal error
|
||||
report_fatal_error(msg);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
});
|
||||
}
|
||||
|
||||
const bool g_exception_handler_set = []() -> bool
|
||||
{
|
||||
if (!AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)exception_handler))
|
||||
{
|
||||
report_fatal_error("AddVectoredExceptionHandler() failed.");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (!SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)exception_filter))
|
||||
{
|
||||
report_fatal_error("SetUnhandledExceptionFilter() failed.");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return true;
|
||||
}();
|
||||
|
||||
#else
|
||||
|
||||
void signal_handler(int sig, siginfo_t* info, void* uct)
|
||||
static void signal_handler(int sig, siginfo_t* info, void* uct)
|
||||
{
|
||||
x64_context* context = (ucontext_t*)uct;
|
||||
|
||||
@@ -1230,17 +1249,21 @@ void signal_handler(int sig, siginfo_t* info, void* uct)
|
||||
}
|
||||
}
|
||||
|
||||
int setup_signal_handler()
|
||||
const bool g_exception_handler_set = []() -> bool
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
struct ::sigaction sa;
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_sigaction = signal_handler;
|
||||
return sigaction(SIGSEGV, &sa, NULL);
|
||||
}
|
||||
|
||||
const int g_sigaction_result = setup_signal_handler();
|
||||
if (::sigaction(SIGSEGV, &sa, NULL) == -1)
|
||||
{
|
||||
std::printf("sigaction() failed (0x%x).", errno);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
return true;
|
||||
}();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1253,16 +1276,6 @@ void thread_ctrl::initialize()
|
||||
{
|
||||
SetCurrentThreadDebugName(g_tls_this_thread->m_name().c_str());
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!g_exception_handler || !g_exception_filter)
|
||||
#else
|
||||
if (g_sigaction_result == -1)
|
||||
#endif
|
||||
{
|
||||
report_fatal_error("Exception handler is not set correctly.");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// TODO
|
||||
g_thread_count++;
|
||||
}
|
||||
@@ -1337,21 +1350,15 @@ void named_thread_t::start()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(GENERAL, "Thread started");
|
||||
}
|
||||
LOG_TRACE(GENERAL, "Thread started");
|
||||
|
||||
thread->on_task();
|
||||
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(GENERAL, "Thread ended");
|
||||
}
|
||||
LOG_TRACE(GENERAL, "Thread ended");
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "Exception: %s\nPlease report this to the developers.", e.what());
|
||||
LOG_FATAL(GENERAL, "Exception: %s\nPlease report this to the developers.", e.what());
|
||||
Emu.Pause();
|
||||
}
|
||||
catch (EmulationStopped)
|
||||
|
||||
+3
-3
@@ -30,14 +30,14 @@ namespace convert
|
||||
{
|
||||
static bool func(const std::string& value)
|
||||
{
|
||||
return value == "true" ? true : false;
|
||||
return value == "true" ? true : value == "false" ? false : throw std::invalid_argument(__FUNCTION__);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, char>
|
||||
struct to_impl_t<std::string, signed char>
|
||||
{
|
||||
static std::string func(char value)
|
||||
static std::string func(signed char value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "rPlatform.h"
|
||||
|
||||
+5
-3
@@ -14,10 +14,11 @@ branches:
|
||||
|
||||
before_build:
|
||||
# until git for win 2.5 release with commit checkout
|
||||
- git submodule update --init ffmpeg asmjit minidx9 rsx_program_decompiler
|
||||
- git submodule update --init ffmpeg asmjit minidx9 rsx_program_decompiler GSL libpng
|
||||
- 7z x wxWidgets.7z -aos -oC:\rpcs3\wxWidgets > null
|
||||
- if %configuration%==Release (cmake -G "Visual Studio 14 Win64")
|
||||
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 14 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/share/llvm/cmake)
|
||||
- 7z x zlib.7z -aos -oC:\rpcs3\ > null
|
||||
- if %configuration%==Release (cmake -G "Visual Studio 14 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/)
|
||||
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 14 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/share/llvm/cmake -DZLIB_ROOT=C:/rpcs3/zlib/)
|
||||
|
||||
build_script:
|
||||
- cmake --build . --config Release -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
@@ -25,6 +26,7 @@ build_script:
|
||||
install:
|
||||
- ps: Start-FileDownload 'https://402331b94f8e4b87ae2ef4677347f7956cf3861f.googledrive.com/host/0B6v_qtb9hkicfmt0NG0wTTRtUmF4X3VTQk5Oc2JidEVKVnUteDA1dXdrYlNsVW9kREpsSHc/wxWidgets.7z'
|
||||
- ps: Start-FileDownload 'https://402331b94f8e4b87ae2ef4677347f7956cf3861f.googledrive.com/host/0B6v_qtb9hkicfmt0NG0wTTRtUmF4X3VTQk5Oc2JidEVKVnUteDA1dXdrYlNsVW9kREpsSHc/llvmlibs.7z'
|
||||
- ps: Start-FileDownload 'https://402331b94f8e4b87ae2ef4677347f7956cf3861f.googledrive.com/host/0B6v_qtb9hkicfmt0NG0wTTRtUmF4X3VTQk5Oc2JidEVKVnUteDA1dXdrYlNsVW9kREpsSHc/zlib.7z'
|
||||
- set WXWIN=C:\rpcs3\wxWidgets
|
||||
- set OPENALDIR=C:\rpcs3\OpenAL
|
||||
- set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;C:\wxWidgets;%PATH%
|
||||
|
||||
+35
-45
@@ -1,10 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug - LLVM|x64">
|
||||
<Configuration>Debug - LLVM</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug - MemLeak|x64">
|
||||
<Configuration>Debug - MemLeak</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release - LLVM|x64">
|
||||
<Configuration>Release - LLVM</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
@@ -71,64 +83,42 @@
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\rpcs3_default.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="..\rpcs3_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - MemLeak|x64'" Label="PropertySheets">
|
||||
<Import Project="..\rpcs3_debug.props" />
|
||||
<Import Project="..\rpcs3_memleak.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'" Label="PropertySheets">
|
||||
<Import Project="..\rpcs3_debug.props" />
|
||||
<Import Project="..\rpcs3_llvm.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="..\rpcs3_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'" Label="PropertySheets">
|
||||
<Import Project="..\rpcs3_release.props" />
|
||||
<Import Project="..\rpcs3_llvm.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
|
||||
<IntDir>
|
||||
</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
|
||||
<IntDir>
|
||||
</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<PreprocessorDefinitions>ASMJIT_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>ASMJIT_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<PreprocessorDefinitions>ASMJIT_STATIC;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
Submodule
+1
Submodule libpng added at ea77a6fd49
@@ -44,50 +44,32 @@
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<IncludePath>.\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath);..\minidx9\Include;..\minidx12\Include</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<IncludePath>.\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath);..\minidx9\Include;..\minidx12\Include</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\rpcs3_default.props" />
|
||||
</ImportGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\;..\rpcs3;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;..\OpenAL\libs\Win64;..\ffmpeg\Windows\x86_64\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\;..\rpcs3;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;..\OpenAL\libs\Win64;..\ffmpeg\Windows\x86_64\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -17,6 +17,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxpro
|
||||
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63} = {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}
|
||||
{A1A8355B-0988-528E-9CC2-B971D6266669} = {A1A8355B-0988-528E-9CC2-B971D6266669}
|
||||
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D} = {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {D6973076-9317-4EF2-A0B8-B7A18AC0713E}
|
||||
{8B867186-A0B5-5479-B824-E176EDD27C40} = {8B867186-A0B5-5479-B824-E176EDD27C40}
|
||||
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D} = {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}
|
||||
{8BC303AB-25BE-4276-8E57-73F171B2D672} = {8BC303AB-25BE-4276-8E57-73F171B2D672}
|
||||
@@ -139,12 +140,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xrc", "wxWidgets\build\msw\
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79} = {24C45343-FD20-5C92-81C1-35A2AE841E79}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "stblib", "stblib", "{9D839DFB-76E6-4F10-8EED-BA2AC7CC3FB6}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
stblib\stb_image.c = stblib\stb_image.c
|
||||
stblib\stb_image.h = stblib\stb_image.h
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ribbon", "wxWidgets\build\msw\wx_ribbon.vcxproj", "{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{24C45343-FD20-5C92-81C1-35A2AE841E79} = {24C45343-FD20-5C92-81C1-35A2AE841E79}
|
||||
@@ -181,8 +176,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_custom_build", "wxWidgets\
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "copy_setup_h", "rpcs3\copy_setup_h.vcxproj", "{00D36322-6188-4A66-B514-3B3F183E998D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GSRender", "GSRender", "{1A43FD7A-C7DD-4D04-A4D6-FAA194AAD9D2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D12GSRender", "rpcs3\D3D12GSRender.vcxproj", "{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3-tests", "rpcs3-tests\rpcs3-tests.vcxproj", "{AB222E8A-00CA-4ACF-A87E-5251C16C0587}"
|
||||
@@ -205,6 +198,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XAudio", "rpcs3\XAudio.vcxp
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenAL", "rpcs3\OpenAL.vcxproj", "{30A05C4D-F5FD-421C-A864-17A64BDEAA75}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpng", "libpng", "{A17D34F1-7E3E-4841-818D-3B7C6F5AF829}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "libpng\projects\vstudio\libpng\libpng.vcxproj", "{D6973076-9317-4EF2-A0B8-B7A18AC0713E}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF} = {60F89955-91C6-3A36-8000-13C592FEC2DF}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "zlib", "zlib", "{F0C19EFA-EDD0-43F2-97C1-18E865E96B4E}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "libpng\projects\vstudio\zlib\zlib.vcxproj", "{60F89955-91C6-3A36-8000-13C592FEC2DF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug - LLVM|x64 = Debug - LLVM|x64
|
||||
@@ -539,18 +543,18 @@ Global
|
||||
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.Build.0 = Release|x64
|
||||
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release|x64.ActiveCfg = Release|x64
|
||||
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release|x64.Build.0 = Release|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM|x64.Build.0 = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.Build.0 = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Debug|x64.ActiveCfg = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Debug|x64.Build.0 = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Release|x64.ActiveCfg = Release|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Release|x64.Build.0 = Release|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.Build.0 = Release|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.ActiveCfg = Release|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.Build.0 = Release|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
@@ -623,9 +627,7 @@ Global
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - LLVM|x64.ActiveCfg = Debug|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - LLVM|x64.Build.0 = Debug|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug|x64.Build.0 = Debug|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Debug|x64.ActiveCfg = Debug|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Debug|x64.Build.0 = Debug|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Release|x64.ActiveCfg = Release|x64
|
||||
@@ -633,7 +635,6 @@ Global
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release - LLVM|x64.ActiveCfg = Release|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release - LLVM|x64.Build.0 = Release|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release|x64.ActiveCfg = Release|x64
|
||||
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release|x64.Build.0 = Release|x64
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
|
||||
{3384223A-6D97-4799-9862-359F85312892}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
|
||||
@@ -704,6 +705,34 @@ Global
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.ActiveCfg = Release|x64
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.Build.0 = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - LLVM|x64.ActiveCfg = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - LLVM|x64.Build.0 = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.ActiveCfg = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.Build.0 = Debug Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Debug|x64.ActiveCfg = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Debug|x64.Build.0 = Debug|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Release|x64.ActiveCfg = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Release|x64.Build.0 = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.ActiveCfg = Release Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.Build.0 = Release Library|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release|x64
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - LLVM|x64.ActiveCfg = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - LLVM|x64.Build.0 = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.ActiveCfg = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.Build.0 = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.ActiveCfg = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.Build.0 = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Debug|x64.ActiveCfg = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Debug|x64.Build.0 = Debug Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Release|x64.ActiveCfg = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Release|x64.Build.0 = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.ActiveCfg = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.Build.0 = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.ActiveCfg = Release Library|x64
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.Build.0 = Release Library|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -741,5 +770,7 @@ Global
|
||||
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{78CB2F39-B809-4A06-8329-8C0A19119D3D} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{30A05C4D-F5FD-421C-A864-17A64BDEAA75} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {A17D34F1-7E3E-4841-818D-3B7C6F5AF829}
|
||||
{60F89955-91C6-3A36-8000-13C592FEC2DF} = {F0C19EFA-EDD0-43F2-97C1-18E865E96B4E}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
+12
-6
@@ -112,6 +112,8 @@ ${LLVM_INCLUDE_DIRS}
|
||||
"${RPCS3_SRC_DIR}/.."
|
||||
"${RPCS3_SRC_DIR}/../asmjit/src/asmjit"
|
||||
"${RPCS3_SRC_DIR}/../glm"
|
||||
"${RPCS3_SRC_DIR}/../libpng"
|
||||
"${RPCS3_SRC_DIR}/../GSL/include"
|
||||
"${RPCS3_SRC_DIR}/../rsx_program_decompiler/rsx_decompiler"
|
||||
"${RPCS3_SRC_DIR}/../rsx_program_decompiler/shader_code"
|
||||
)
|
||||
@@ -139,7 +141,10 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
link_directories("${RPCS3_SRC_DIR}/../asmjit/" "${RPCS3_SRC_DIR}/../minidx12/")
|
||||
link_directories(
|
||||
"${RPCS3_SRC_DIR}/../asmjit/"
|
||||
"${RPCS3_SRC_DIR}/../minidx12/"
|
||||
)
|
||||
|
||||
if(MSVC OR NOT WIN32)
|
||||
link_directories("${RPCS3_SRC_DIR}/../ffmpeg/${PLATFORM_ARCH}/lib")
|
||||
@@ -155,6 +160,7 @@ GLOB_RECURSE
|
||||
RPCS3_SRC
|
||||
"${RPCS3_SRC_DIR}/rpcs3.cpp"
|
||||
"${RPCS3_SRC_DIR}/config.cpp"
|
||||
"${RPCS3_SRC_DIR}/stb_image.cpp"
|
||||
"${RPCS3_SRC_DIR}/../Utilities/GNU.cpp"
|
||||
"${RPCS3_SRC_DIR}/Emu/*"
|
||||
"${RPCS3_SRC_DIR}/Gui/*"
|
||||
@@ -183,14 +189,14 @@ if(WIN32) # I'm not sure we need all of these libs, but we link them in vs
|
||||
else()
|
||||
target_link_libraries(rpcs3 dxgi.lib d2d1.lib dwrite.lib)
|
||||
endif()
|
||||
target_link_libraries(rpcs3 asmjit.lib avformat.lib avcodec.lib avutil.lib swresample.lib swscale.lib ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${ADDITIONAL_LIBS})
|
||||
target_link_libraries(rpcs3 asmjit.lib avformat.lib avcodec.lib avutil.lib swresample.lib swscale.lib png16_static ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${ADDITIONAL_LIBS})
|
||||
else()
|
||||
if(LLVM_FOUND)
|
||||
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(rpcs3 libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a ${ZLIB_LIBRARIES} ${LLVM_LIBS} ${ADDITIONAL_LIBS})
|
||||
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(rpcs3 libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a png16_static ${ZLIB_LIBRARIES} ${LLVM_LIBS} ${ADDITIONAL_LIBS})
|
||||
else()
|
||||
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(rpcs3 libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a ${ZLIB_LIBRARIES} ${ADDITIONAL_LIBS})
|
||||
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(rpcs3 libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a png16_static ${ZLIB_LIBRARIES} ${ADDITIONAL_LIBS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -820,7 +820,6 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi
|
||||
// Prepare the files.
|
||||
fs::file input(input_file_name);
|
||||
fs::file output(output_file_name, fom::rewrite);
|
||||
fs::file rap(rap_file_name);
|
||||
|
||||
// Set keys (RIF and DEVKLIC).
|
||||
unsigned char rifkey[0x10];
|
||||
@@ -879,8 +878,10 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi
|
||||
}
|
||||
|
||||
// Read the RAP file, if provided.
|
||||
if (rap)
|
||||
if (rap_file_name.size())
|
||||
{
|
||||
fs::file rap(rap_file_name);
|
||||
|
||||
unsigned char rapkey[0x10];
|
||||
memset(rapkey, 0, 0x10);
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, volatile f64& pr
|
||||
const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB
|
||||
|
||||
// Save current file offset (probably zero)
|
||||
const u64 start_offset = pkg_f.seek(0, fsm::cur);
|
||||
const u64 start_offset = pkg_f.seek(0, fs::seek_cur);
|
||||
|
||||
// Get basic PKG information
|
||||
PKGHeader header;
|
||||
|
||||
@@ -942,9 +942,9 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
bool SELFDecrypter::LoadMetadata()
|
||||
{
|
||||
aes_context aes;
|
||||
u32 metadata_info_size = sizeof32(meta_info);
|
||||
u32 metadata_info_size = SIZE_32(meta_info);
|
||||
u8 *metadata_info = (u8 *)malloc(metadata_info_size);
|
||||
u32 metadata_headers_size = sce_hdr.se_hsize - (sizeof32(sce_hdr) + sce_hdr.se_meta + sizeof32(meta_info));
|
||||
u32 metadata_headers_size = sce_hdr.se_hsize - (SIZE_32(sce_hdr) + sce_hdr.se_meta + SIZE_32(meta_info));
|
||||
u8 *metadata_headers = (u8 *)malloc(metadata_headers_size);
|
||||
|
||||
// Locate and read the encrypted metadata info.
|
||||
@@ -1330,6 +1330,8 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf)
|
||||
|
||||
bool DecryptSelf(const std::string& elf, const std::string& self)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Decrypting %s", self);
|
||||
|
||||
// Check for a debug SELF first.
|
||||
if (!CheckDebugSelf(self, elf))
|
||||
{
|
||||
|
||||
@@ -61,66 +61,7 @@
|
||||
<Import Project="..\rpcs3_llvm.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - MemLeak|x64'">
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug - MemLeak|x64'">
|
||||
<Lib>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
</Lib>
|
||||
<ClCompile>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">
|
||||
<Lib>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies />
|
||||
<AdditionalLibraryDirectories />
|
||||
</Lib>
|
||||
<ClCompile>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Lib>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
</Lib>
|
||||
<ClCompile>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Lib>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
</Lib>
|
||||
<ClCompile>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">
|
||||
<Lib>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies />
|
||||
<AdditionalLibraryDirectories />
|
||||
</Lib>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
|
||||
@@ -1125,7 +1125,7 @@ struct ARMv7_op2_table_t
|
||||
{
|
||||
if (opcode.code & ~opcode.mask)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "%s: wrong opcode mask (mask=0x%04x, code=0x%04x)", opcode.name, opcode.mask >> 16, opcode.code >> 16);
|
||||
LOG_ERROR(ARMv7, "%s: wrong opcode mask (mask=0x%04x, code=0x%04x)", opcode.name, opcode.mask >> 16, opcode.code >> 16);
|
||||
}
|
||||
|
||||
t2.push_back(&opcode);
|
||||
@@ -1164,7 +1164,7 @@ struct ARMv7_op4t_table_t
|
||||
{
|
||||
if (opcode.code & ~opcode.mask)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "%s: wrong opcode mask (mask=0x%04x 0x%04x, code=0x%04x 0x%04x)", opcode.name, opcode.mask >> 16, (u16)opcode.mask, opcode.code >> 16, (u16)opcode.code);
|
||||
LOG_ERROR(ARMv7, "%s: wrong opcode mask (mask=0x%04x 0x%04x, code=0x%04x 0x%04x)", opcode.name, opcode.mask >> 16, (u16)opcode.mask, opcode.code >> 16, (u16)opcode.code);
|
||||
}
|
||||
|
||||
table.push_back(&opcode);
|
||||
@@ -1199,7 +1199,7 @@ struct ARMv7_op4arm_table_t
|
||||
{
|
||||
if (opcode.code & ~opcode.mask)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "%s: wrong opcode mask (mask=0x%08x, code=0x%08x)", opcode.name, opcode.mask, opcode.code);
|
||||
LOG_ERROR(ARMv7, "%s: wrong opcode mask (mask=0x%08x, code=0x%08x)", opcode.name, opcode.mask, opcode.code);
|
||||
}
|
||||
|
||||
table.push_back(&opcode);
|
||||
@@ -1365,7 +1365,7 @@ u32 ARMv7Decoder::DecodeMemory(const u32 address)
|
||||
// "group" decoding algorithm (temporarily disabled)
|
||||
|
||||
//execute_main_group(&m_thr);
|
||||
//// LOG_NOTICE(GENERAL, "%s, %d \n\n", m_thr.m_last_instr_name, m_thr.m_last_instr_size);
|
||||
//// LOG_NOTICE(ARMv7, "%s, %d \n\n", m_thr.m_last_instr_name, m_thr.m_last_instr_size);
|
||||
//m_thr.m_last_instr_name = "Unknown";
|
||||
//return m_thr.m_last_instr_size;
|
||||
}
|
||||
|
||||
@@ -2005,7 +2005,7 @@ static void execute_main_group(ARMv7Thread* thr)
|
||||
case 0xe: (*g_table_0xe).func(thr, (*g_table_0xe).type); break;
|
||||
case 0xf: (*g_table_0xf).func(thr, (*g_table_0xf).type); break;
|
||||
|
||||
default: LOG_ERROR(GENERAL, "ARMv7Decoder: unknown group 0x%x", (thr->code.code0 & 0xf000) >> 12); Emu.Pause(); break;
|
||||
default: LOG_ERROR(ARMv7, "ARMv7Decoder: unknown group 0x%x", (thr->code.code0 & 0xf000) >> 12); Emu.Pause(); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
using SceFiosOpCallback = s32(vm::ptr<void> pContext, s32 op, u8 event, s32 err);
|
||||
using SceFiosVprintfCallback = s32(vm::cptr<char> fmt, va_list ap);
|
||||
using SceFiosVprintfCallback = s32(vm::cptr<char> fmt, armv7_va_args_t ap /* va_list */);
|
||||
using SceFiosMemcpyCallback = vm::ptr<void>(vm::ptr<void> dst, vm::cptr<void> src, u32 len);
|
||||
|
||||
enum SceFiosWhence : s32
|
||||
|
||||
@@ -33,7 +33,7 @@ s32 sceKernelGetMemBlockInfoByAddr(vm::ptr<void> vbase, vm::ptr<SceKernelMemBloc
|
||||
|
||||
s32 sceKernelCreateThread(vm::cptr<char> pName, vm::ptr<SceKernelThreadEntry> entry, s32 initPriority, u32 stackSize, u32 attr, s32 cpuAffinityMask, vm::cptr<SceKernelThreadOptParam> pOptParam)
|
||||
{
|
||||
sceLibKernel.Warning("sceKernelCreateThread(pName=*0x%x, entry=*0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam=*0x%x)",
|
||||
sceLibKernel.warning("sceKernelCreateThread(pName=*0x%x, entry=*0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam=*0x%x)",
|
||||
pName, entry, initPriority, stackSize, attr, cpuAffinityMask, pOptParam);
|
||||
|
||||
auto armv7 = idm::make_ptr<ARMv7Thread>(pName.get_ptr());
|
||||
@@ -48,7 +48,7 @@ s32 sceKernelCreateThread(vm::cptr<char> pName, vm::ptr<SceKernelThreadEntry> en
|
||||
|
||||
s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::cptr<void> pArgBlock)
|
||||
{
|
||||
sceLibKernel.Warning("sceKernelStartThread(threadId=0x%x, argSize=0x%x, pArgBlock=*0x%x)", threadId, argSize, pArgBlock);
|
||||
sceLibKernel.warning("sceKernelStartThread(threadId=0x%x, argSize=0x%x, pArgBlock=*0x%x)", threadId, argSize, pArgBlock);
|
||||
|
||||
const auto thread = idm::get<ARMv7Thread>(threadId);
|
||||
|
||||
@@ -78,7 +78,7 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::cptr<void> pArgBlock)
|
||||
|
||||
s32 sceKernelExitThread(ARMv7Thread& context, s32 exitStatus)
|
||||
{
|
||||
sceLibKernel.Warning("sceKernelExitThread(exitStatus=0x%x)", exitStatus);
|
||||
sceLibKernel.warning("sceKernelExitThread(exitStatus=0x%x)", exitStatus);
|
||||
|
||||
// exit status is stored in r0
|
||||
context.exit();
|
||||
@@ -88,7 +88,7 @@ s32 sceKernelExitThread(ARMv7Thread& context, s32 exitStatus)
|
||||
|
||||
s32 sceKernelDeleteThread(s32 threadId)
|
||||
{
|
||||
sceLibKernel.Warning("sceKernelDeleteThread(threadId=0x%x)", threadId);
|
||||
sceLibKernel.warning("sceKernelDeleteThread(threadId=0x%x)", threadId);
|
||||
|
||||
const auto thread = idm::get<ARMv7Thread>(threadId);
|
||||
|
||||
@@ -110,7 +110,7 @@ s32 sceKernelDeleteThread(s32 threadId)
|
||||
|
||||
s32 sceKernelExitDeleteThread(ARMv7Thread& context, s32 exitStatus)
|
||||
{
|
||||
sceLibKernel.Warning("sceKernelExitDeleteThread(exitStatus=0x%x)", exitStatus);
|
||||
sceLibKernel.warning("sceKernelExitDeleteThread(exitStatus=0x%x)", exitStatus);
|
||||
|
||||
// exit status is stored in r0
|
||||
context.stop();
|
||||
@@ -123,91 +123,91 @@ s32 sceKernelExitDeleteThread(ARMv7Thread& context, s32 exitStatus)
|
||||
|
||||
s32 sceKernelChangeThreadCpuAffinityMask(s32 threadId, s32 cpuAffinityMask)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelChangeThreadCpuAffinityMask(threadId=0x%x, cpuAffinityMask=0x%x)", threadId, cpuAffinityMask);
|
||||
sceLibKernel.todo("sceKernelChangeThreadCpuAffinityMask(threadId=0x%x, cpuAffinityMask=0x%x)", threadId, cpuAffinityMask);
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelGetThreadCpuAffinityMask(s32 threadId)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelGetThreadCpuAffinityMask(threadId=0x%x)", threadId);
|
||||
sceLibKernel.todo("sceKernelGetThreadCpuAffinityMask(threadId=0x%x)", threadId);
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelChangeThreadPriority(s32 threadId, s32 priority)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelChangeThreadPriority(threadId=0x%x, priority=%d)", threadId, priority);
|
||||
sceLibKernel.todo("sceKernelChangeThreadPriority(threadId=0x%x, priority=%d)", threadId, priority);
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelGetThreadCurrentPriority()
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelGetThreadCurrentPriority()");
|
||||
sceLibKernel.todo("sceKernelGetThreadCurrentPriority()");
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
u32 sceKernelGetThreadId(ARMv7Thread& context)
|
||||
{
|
||||
sceLibKernel.Log("sceKernelGetThreadId()");
|
||||
sceLibKernel.trace("sceKernelGetThreadId()");
|
||||
|
||||
return context.get_id();
|
||||
}
|
||||
|
||||
s32 sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelChangeCurrentThreadAttr()");
|
||||
sceLibKernel.todo("sceKernelChangeCurrentThreadAttr()");
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelGetThreadExitStatus(s32 threadId, vm::ptr<s32> pExitStatus)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=0x%x, pExitStatus=*0x%x)", threadId, pExitStatus);
|
||||
sceLibKernel.todo("sceKernelGetThreadExitStatus(threadId=0x%x, pExitStatus=*0x%x)", threadId, pExitStatus);
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelGetProcessId()
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelGetProcessId()");
|
||||
sceLibKernel.todo("sceKernelGetProcessId()");
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelCheckWaitableStatus()
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelCheckWaitableStatus()");
|
||||
sceLibKernel.todo("sceKernelCheckWaitableStatus()");
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelGetThreadInfo(s32 threadId, vm::ptr<SceKernelThreadInfo> pInfo)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=0x%x, pInfo=*0x%x)", threadId, pInfo);
|
||||
sceLibKernel.todo("sceKernelGetThreadInfo(threadId=0x%x, pInfo=*0x%x)", threadId, pInfo);
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelGetThreadRunStatus(vm::ptr<SceKernelThreadRunStatus> pStatus)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelGetThreadRunStatus(pStatus=*0x%x)", pStatus);
|
||||
sceLibKernel.todo("sceKernelGetThreadRunStatus(pStatus=*0x%x)", pStatus);
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelGetSystemInfo(vm::ptr<SceKernelSystemInfo> pInfo)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelGetSystemInfo(pInfo=*0x%x)", pInfo);
|
||||
sceLibKernel.todo("sceKernelGetSystemInfo(pInfo=*0x%x)", pInfo);
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelGetThreadmgrUIDClass(s32 uid)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelGetThreadmgrUIDClass(uid=0x%x)", uid);
|
||||
sceLibKernel.error("sceKernelGetThreadmgrUIDClass(uid=0x%x)", uid);
|
||||
|
||||
const auto type = idm::get_type(uid);
|
||||
|
||||
@@ -227,35 +227,35 @@ s32 sceKernelGetThreadmgrUIDClass(s32 uid)
|
||||
|
||||
s32 sceKernelChangeThreadVfpException(s32 clearMask, s32 setMask)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelChangeThreadVfpException(clearMask=0x%x, setMask=0x%x)", clearMask, setMask);
|
||||
sceLibKernel.todo("sceKernelChangeThreadVfpException(clearMask=0x%x, setMask=0x%x)", clearMask, setMask);
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelGetCurrentThreadVfpException()
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelGetCurrentThreadVfpException()");
|
||||
sceLibKernel.todo("sceKernelGetCurrentThreadVfpException()");
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelDelayThread(u32 usec)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelDelayThread()");
|
||||
sceLibKernel.todo("sceKernelDelayThread()");
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelDelayThreadCB(u32 usec)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelDelayThreadCB()");
|
||||
sceLibKernel.todo("sceKernelDelayThreadCB()");
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 sceKernelWaitThreadEnd(s32 threadId, vm::ptr<s32> pExitStatus, vm::ptr<u32> pTimeout)
|
||||
{
|
||||
sceLibKernel.Warning("sceKernelWaitThreadEnd(threadId=0x%x, pExitStatus=*0x%x, pTimeout=*0x%x)", threadId, pExitStatus, pTimeout);
|
||||
sceLibKernel.warning("sceKernelWaitThreadEnd(threadId=0x%x, pExitStatus=*0x%x, pTimeout=*0x%x)", threadId, pExitStatus, pTimeout);
|
||||
|
||||
const auto thread = idm::get<ARMv7Thread>(threadId);
|
||||
|
||||
@@ -285,7 +285,7 @@ s32 sceKernelWaitThreadEnd(s32 threadId, vm::ptr<s32> pExitStatus, vm::ptr<u32>
|
||||
|
||||
s32 sceKernelWaitThreadEndCB(s32 threadId, vm::ptr<s32> pExitStatus, vm::ptr<u32> pTimeout)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=0x%x, pExitStatus=*0x%x, pTimeout=*0x%x)", threadId, pExitStatus, pTimeout);
|
||||
sceLibKernel.todo("sceKernelWaitThreadEndCB(threadId=0x%x, pExitStatus=*0x%x, pTimeout=*0x%x)", threadId, pExitStatus, pTimeout);
|
||||
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
@@ -383,14 +383,14 @@ s32 sceKernelWaitMultipleEventsCB(vm::ptr<SceKernelWaitEvent> pWaitEventList, s3
|
||||
|
||||
s32 sceKernelCreateEventFlag(vm::cptr<char> pName, u32 attr, u32 initPattern, vm::cptr<SceKernelEventFlagOptParam> pOptParam)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelCreateEventFlag(pName=*0x%x, attr=0x%x, initPattern=0x%x, pOptParam=*0x%x)", pName, attr, initPattern, pOptParam);
|
||||
sceLibKernel.error("sceKernelCreateEventFlag(pName=*0x%x, attr=0x%x, initPattern=0x%x, pOptParam=*0x%x)", pName, attr, initPattern, pOptParam);
|
||||
|
||||
return idm::make<psv_event_flag_t>(pName.get_ptr(), attr, initPattern);
|
||||
}
|
||||
|
||||
s32 sceKernelDeleteEventFlag(s32 evfId)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelDeleteEventFlag(evfId=0x%x)", evfId);
|
||||
sceLibKernel.error("sceKernelDeleteEventFlag(evfId=0x%x)", evfId);
|
||||
|
||||
const auto evf = idm::withdraw<psv_event_flag_t>(evfId);
|
||||
|
||||
@@ -410,7 +410,7 @@ s32 sceKernelDeleteEventFlag(s32 evfId)
|
||||
|
||||
s32 sceKernelOpenEventFlag(vm::cptr<char> pName)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelOpenEventFlag(pName=*0x%x)", pName);
|
||||
sceLibKernel.error("sceKernelOpenEventFlag(pName=*0x%x)", pName);
|
||||
|
||||
// For now, go through all objects to find the name
|
||||
for (const auto& data : idm::get_map<psv_event_flag_t>())
|
||||
@@ -428,7 +428,7 @@ s32 sceKernelOpenEventFlag(vm::cptr<char> pName)
|
||||
|
||||
s32 sceKernelCloseEventFlag(s32 evfId)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelCloseEventFlag(evfId=0x%x)", evfId);
|
||||
sceLibKernel.error("sceKernelCloseEventFlag(evfId=0x%x)", evfId);
|
||||
|
||||
const auto evf = idm::withdraw<psv_event_flag_t>(evfId);
|
||||
|
||||
@@ -448,7 +448,7 @@ s32 sceKernelCloseEventFlag(s32 evfId)
|
||||
|
||||
s32 sceKernelWaitEventFlag(ARMv7Thread& context, s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr<u32> pResultPat, vm::ptr<u32> pTimeout)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelWaitEventFlag(evfId=0x%x, bitPattern=0x%x, waitMode=0x%x, pResultPat=*0x%x, pTimeout=*0x%x)", evfId, bitPattern, waitMode, pResultPat, pTimeout);
|
||||
sceLibKernel.error("sceKernelWaitEventFlag(evfId=0x%x, bitPattern=0x%x, waitMode=0x%x, pResultPat=*0x%x, pTimeout=*0x%x)", evfId, bitPattern, waitMode, pResultPat, pTimeout);
|
||||
|
||||
const u64 start_time = pTimeout ? get_system_time() : 0;
|
||||
const u32 timeout = pTimeout ? pTimeout->value() : 0;
|
||||
@@ -509,14 +509,14 @@ s32 sceKernelWaitEventFlag(ARMv7Thread& context, s32 evfId, u32 bitPattern, u32
|
||||
|
||||
s32 sceKernelWaitEventFlagCB(ARMv7Thread& context, s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr<u32> pResultPat, vm::ptr<u32> pTimeout)
|
||||
{
|
||||
sceLibKernel.Todo("sceKernelWaitEventFlagCB(evfId=0x%x, bitPattern=0x%x, waitMode=0x%x, pResultPat=*0x%x, pTimeout=*0x%x)", evfId, bitPattern, waitMode, pResultPat, pTimeout);
|
||||
sceLibKernel.todo("sceKernelWaitEventFlagCB(evfId=0x%x, bitPattern=0x%x, waitMode=0x%x, pResultPat=*0x%x, pTimeout=*0x%x)", evfId, bitPattern, waitMode, pResultPat, pTimeout);
|
||||
|
||||
return sceKernelWaitEventFlag(context, evfId, bitPattern, waitMode, pResultPat, pTimeout);
|
||||
}
|
||||
|
||||
s32 sceKernelPollEventFlag(s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr<u32> pResultPat)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelPollEventFlag(evfId=0x%x, bitPattern=0x%x, waitMode=0x%x, pResultPat=*0x%x)", evfId, bitPattern, waitMode, pResultPat);
|
||||
sceLibKernel.error("sceKernelPollEventFlag(evfId=0x%x, bitPattern=0x%x, waitMode=0x%x, pResultPat=*0x%x)", evfId, bitPattern, waitMode, pResultPat);
|
||||
|
||||
const auto evf = idm::get<psv_event_flag_t>(evfId);
|
||||
|
||||
@@ -541,7 +541,7 @@ s32 sceKernelPollEventFlag(s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr<u32>
|
||||
|
||||
s32 sceKernelSetEventFlag(s32 evfId, u32 bitPattern)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelSetEventFlag(evfId=0x%x, bitPattern=0x%x)", evfId, bitPattern);
|
||||
sceLibKernel.error("sceKernelSetEventFlag(evfId=0x%x, bitPattern=0x%x)", evfId, bitPattern);
|
||||
|
||||
const auto evf = idm::get<psv_event_flag_t>(evfId);
|
||||
|
||||
@@ -586,7 +586,7 @@ s32 sceKernelSetEventFlag(s32 evfId, u32 bitPattern)
|
||||
|
||||
s32 sceKernelClearEventFlag(s32 evfId, u32 bitPattern)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelClearEventFlag(evfId=0x%x, bitPattern=0x%x)", evfId, bitPattern);
|
||||
sceLibKernel.error("sceKernelClearEventFlag(evfId=0x%x, bitPattern=0x%x)", evfId, bitPattern);
|
||||
|
||||
const auto evf = idm::get<psv_event_flag_t>(evfId);
|
||||
|
||||
@@ -604,7 +604,7 @@ s32 sceKernelClearEventFlag(s32 evfId, u32 bitPattern)
|
||||
|
||||
s32 sceKernelCancelEventFlag(s32 evfId, u32 setPattern, vm::ptr<s32> pNumWaitThreads)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelCancelEventFlag(evfId=0x%x, setPattern=0x%x, pNumWaitThreads=*0x%x)", evfId, setPattern, pNumWaitThreads);
|
||||
sceLibKernel.error("sceKernelCancelEventFlag(evfId=0x%x, setPattern=0x%x, pNumWaitThreads=*0x%x)", evfId, setPattern, pNumWaitThreads);
|
||||
|
||||
const auto evf = idm::get<psv_event_flag_t>(evfId);
|
||||
|
||||
@@ -632,7 +632,7 @@ s32 sceKernelCancelEventFlag(s32 evfId, u32 setPattern, vm::ptr<s32> pNumWaitThr
|
||||
|
||||
s32 sceKernelGetEventFlagInfo(s32 evfId, vm::ptr<SceKernelEventFlagInfo> pInfo)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelGetEventFlagInfo(evfId=0x%x, pInfo=*0x%x)", evfId, pInfo);
|
||||
sceLibKernel.error("sceKernelGetEventFlagInfo(evfId=0x%x, pInfo=*0x%x)", evfId, pInfo);
|
||||
|
||||
const auto evf = idm::get<psv_event_flag_t>(evfId);
|
||||
|
||||
@@ -643,7 +643,7 @@ s32 sceKernelGetEventFlagInfo(s32 evfId, vm::ptr<SceKernelEventFlagInfo> pInfo)
|
||||
|
||||
std::lock_guard<std::mutex> lock(evf->mutex);
|
||||
|
||||
pInfo->size = sizeof32(SceKernelEventFlagInfo);
|
||||
pInfo->size = SIZE_32(SceKernelEventFlagInfo);
|
||||
pInfo->evfId = evfId;
|
||||
|
||||
strcpy_trunc(pInfo->name, evf->name);
|
||||
@@ -660,14 +660,14 @@ s32 sceKernelGetEventFlagInfo(s32 evfId, vm::ptr<SceKernelEventFlagInfo> pInfo)
|
||||
|
||||
s32 sceKernelCreateSema(vm::cptr<char> pName, u32 attr, s32 initCount, s32 maxCount, vm::cptr<SceKernelSemaOptParam> pOptParam)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelCreateSema(pName=*0x%x, attr=0x%x, initCount=%d, maxCount=%d, pOptParam=*0x%x)", pName, attr, initCount, maxCount, pOptParam);
|
||||
sceLibKernel.error("sceKernelCreateSema(pName=*0x%x, attr=0x%x, initCount=%d, maxCount=%d, pOptParam=*0x%x)", pName, attr, initCount, maxCount, pOptParam);
|
||||
|
||||
return idm::make<psv_semaphore_t>(pName.get_ptr(), attr, initCount, maxCount);
|
||||
}
|
||||
|
||||
s32 sceKernelDeleteSema(s32 semaId)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelDeleteSema(semaId=0x%x)", semaId);
|
||||
sceLibKernel.error("sceKernelDeleteSema(semaId=0x%x)", semaId);
|
||||
|
||||
const auto sema = idm::withdraw<psv_semaphore_t>(semaId);
|
||||
|
||||
@@ -693,7 +693,7 @@ s32 sceKernelCloseSema(s32 semaId)
|
||||
|
||||
s32 sceKernelWaitSema(s32 semaId, s32 needCount, vm::ptr<u32> pTimeout)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelWaitSema(semaId=0x%x, needCount=%d, pTimeout=*0x%x)", semaId, needCount, pTimeout);
|
||||
sceLibKernel.error("sceKernelWaitSema(semaId=0x%x, needCount=%d, pTimeout=*0x%x)", semaId, needCount, pTimeout);
|
||||
|
||||
const auto sema = idm::get<psv_semaphore_t>(semaId);
|
||||
|
||||
@@ -702,7 +702,7 @@ s32 sceKernelWaitSema(s32 semaId, s32 needCount, vm::ptr<u32> pTimeout)
|
||||
return SCE_KERNEL_ERROR_INVALID_UID;
|
||||
}
|
||||
|
||||
sceLibKernel.Error("*** name = %s", sema->name);
|
||||
sceLibKernel.error("*** name = %s", sema->name);
|
||||
Emu.Pause();
|
||||
return SCE_OK;
|
||||
}
|
||||
@@ -736,14 +736,14 @@ s32 sceKernelGetSemaInfo(s32 semaId, vm::ptr<SceKernelSemaInfo> pInfo)
|
||||
|
||||
s32 sceKernelCreateMutex(vm::cptr<char> pName, u32 attr, s32 initCount, vm::cptr<SceKernelMutexOptParam> pOptParam)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelCreateMutex(pName=*0x%x, attr=0x%x, initCount=%d, pOptParam=*0x%x)", pName, attr, initCount, pOptParam);
|
||||
sceLibKernel.error("sceKernelCreateMutex(pName=*0x%x, attr=0x%x, initCount=%d, pOptParam=*0x%x)", pName, attr, initCount, pOptParam);
|
||||
|
||||
return idm::make<psv_mutex_t>(pName.get_ptr(), attr, initCount);
|
||||
}
|
||||
|
||||
s32 sceKernelDeleteMutex(s32 mutexId)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelDeleteMutex(mutexId=0x%x)", mutexId);
|
||||
sceLibKernel.error("sceKernelDeleteMutex(mutexId=0x%x)", mutexId);
|
||||
|
||||
const auto mutex = idm::withdraw<psv_mutex_t>(mutexId);
|
||||
|
||||
@@ -843,7 +843,7 @@ s32 sceKernelGetLwMutexInfoById(s32 lwMutexId, vm::ptr<SceKernelLwMutexInfo> pIn
|
||||
|
||||
s32 sceKernelCreateCond(vm::cptr<char> pName, u32 attr, s32 mutexId, vm::cptr<SceKernelCondOptParam> pOptParam)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelCreateCond(pName=*0x%x, attr=0x%x, mutexId=0x%x, pOptParam=*0x%x)", pName, attr, mutexId, pOptParam);
|
||||
sceLibKernel.error("sceKernelCreateCond(pName=*0x%x, attr=0x%x, mutexId=0x%x, pOptParam=*0x%x)", pName, attr, mutexId, pOptParam);
|
||||
|
||||
const auto mutex = idm::get<psv_mutex_t>(mutexId);
|
||||
|
||||
@@ -857,7 +857,7 @@ s32 sceKernelCreateCond(vm::cptr<char> pName, u32 attr, s32 mutexId, vm::cptr<Sc
|
||||
|
||||
s32 sceKernelDeleteCond(s32 condId)
|
||||
{
|
||||
sceLibKernel.Error("sceKernelDeleteCond(condId=0x%x)", condId);
|
||||
sceLibKernel.error("sceKernelDeleteCond(condId=0x%x)", condId);
|
||||
|
||||
const auto cond = idm::withdraw<psv_cond_t>(condId);
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace sce_libc_func
|
||||
{
|
||||
void __cxa_atexit(vm::ptr<atexit_func_t> func, vm::ptr<void> arg, vm::ptr<void> dso)
|
||||
{
|
||||
sceLibc.Warning("__cxa_atexit(func=*0x%x, arg=*0x%x, dso=*0x%x)", func, arg, dso);
|
||||
sceLibc.warning("__cxa_atexit(func=*0x%x, arg=*0x%x, dso=*0x%x)", func, arg, dso);
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_atexit_mutex);
|
||||
|
||||
@@ -162,7 +162,7 @@ namespace sce_libc_func
|
||||
|
||||
void __aeabi_atexit(vm::ptr<void> arg, vm::ptr<atexit_func_t> func, vm::ptr<void> dso)
|
||||
{
|
||||
sceLibc.Warning("__aeabi_atexit(arg=*0x%x, func=*0x%x, dso=*0x%x)", arg, func, dso);
|
||||
sceLibc.warning("__aeabi_atexit(arg=*0x%x, func=*0x%x, dso=*0x%x)", arg, func, dso);
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_atexit_mutex);
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace sce_libc_func
|
||||
|
||||
void exit(ARMv7Thread& context)
|
||||
{
|
||||
sceLibc.Warning("exit()");
|
||||
sceLibc.warning("exit()");
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_atexit_mutex);
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace sce_libc_func
|
||||
func(context);
|
||||
}
|
||||
|
||||
sceLibc.Success("Process finished");
|
||||
sceLibc.success("Process finished");
|
||||
|
||||
Emu.CallAfter([]()
|
||||
{
|
||||
@@ -202,52 +202,52 @@ namespace sce_libc_func
|
||||
|
||||
void printf(ARMv7Thread& context, vm::cptr<char> fmt, armv7_va_args_t va_args)
|
||||
{
|
||||
sceLibc.Warning("printf(fmt=*0x%x)", fmt);
|
||||
sceLibc.Log("*** *fmt = '%s'", fmt.get_ptr());
|
||||
sceLibc.warning("printf(fmt=*0x%x)", fmt);
|
||||
sceLibc.trace("*** *fmt = '%s'", fmt.get_ptr());
|
||||
|
||||
const std::string& result = armv7_fmt(context, fmt, va_args.g_count, va_args.f_count, va_args.v_count);
|
||||
sceLibc.Log("*** -> '%s'", result);
|
||||
sceLibc.trace("*** -> '%s'", result);
|
||||
|
||||
LOG_NOTICE(TTY, result);
|
||||
_log::g_tty_file.log(result);
|
||||
}
|
||||
|
||||
void sprintf(ARMv7Thread& context, vm::ptr<char> str, vm::cptr<char> fmt, armv7_va_args_t va_args)
|
||||
{
|
||||
sceLibc.Warning("sprintf(str=*0x%x, fmt=*0x%x)", str, fmt);
|
||||
sceLibc.Log("*** *fmt = '%s'", fmt.get_ptr());
|
||||
sceLibc.warning("sprintf(str=*0x%x, fmt=*0x%x)", str, fmt);
|
||||
sceLibc.trace("*** *fmt = '%s'", fmt.get_ptr());
|
||||
|
||||
const std::string& result = armv7_fmt(context, fmt, va_args.g_count, va_args.f_count, va_args.v_count);
|
||||
sceLibc.Log("*** -> '%s'", result);
|
||||
sceLibc.trace("*** -> '%s'", result);
|
||||
|
||||
::memcpy(str.get_ptr(), result.c_str(), result.size() + 1);
|
||||
}
|
||||
|
||||
void __cxa_set_dso_handle_main(vm::ptr<void> dso)
|
||||
{
|
||||
sceLibc.Warning("__cxa_set_dso_handle_main(dso=*0x%x)", dso);
|
||||
sceLibc.warning("__cxa_set_dso_handle_main(dso=*0x%x)", dso);
|
||||
|
||||
g_dso = dso;
|
||||
}
|
||||
|
||||
void memcpy(vm::ptr<void> dst, vm::cptr<void> src, u32 size)
|
||||
{
|
||||
sceLibc.Warning("memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size);
|
||||
sceLibc.warning("memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size);
|
||||
|
||||
::memcpy(dst.get_ptr(), src.get_ptr(), size);
|
||||
}
|
||||
|
||||
void memset(vm::ptr<void> dst, s32 value, u32 size)
|
||||
{
|
||||
sceLibc.Warning("memset(dst=*0x%x, value=%d, size=0x%x)", dst, value, size);
|
||||
sceLibc.warning("memset(dst=*0x%x, value=%d, size=0x%x)", dst, value, size);
|
||||
|
||||
::memset(dst.get_ptr(), value, size);
|
||||
}
|
||||
|
||||
void _Assert(vm::cptr<char> text, vm::cptr<char> func)
|
||||
{
|
||||
sceLibc.Error("_Assert(text=*0x%x, func=*0x%x)", text, func);
|
||||
sceLibc.error("_Assert(text=*0x%x, func=*0x%x)", text, func);
|
||||
|
||||
LOG_ERROR(TTY, "%s : %s\n", func.get_ptr(), text.get_ptr());
|
||||
LOG_FATAL(HLE, "%s : %s\n", func.get_ptr(), text.get_ptr());
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ extern u64 get_system_time();
|
||||
|
||||
s32 scePerfArmPmonReset(ARMv7Thread& context, s32 threadId)
|
||||
{
|
||||
scePerf.Warning("scePerfArmPmonReset(threadId=0x%x)", threadId);
|
||||
scePerf.warning("scePerfArmPmonReset(threadId=0x%x)", threadId);
|
||||
|
||||
if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF)
|
||||
{
|
||||
@@ -22,7 +22,7 @@ s32 scePerfArmPmonReset(ARMv7Thread& context, s32 threadId)
|
||||
|
||||
s32 scePerfArmPmonSelectEvent(ARMv7Thread& context, s32 threadId, u32 counter, u8 eventCode)
|
||||
{
|
||||
scePerf.Warning("scePerfArmPmonSelectEvent(threadId=0x%x, counter=0x%x, eventCode=0x%x)", threadId, counter, eventCode);
|
||||
scePerf.warning("scePerfArmPmonSelectEvent(threadId=0x%x, counter=0x%x, eventCode=0x%x)", threadId, counter, eventCode);
|
||||
|
||||
if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF)
|
||||
{
|
||||
@@ -74,7 +74,7 @@ s32 scePerfArmPmonSelectEvent(ARMv7Thread& context, s32 threadId, u32 counter, u
|
||||
|
||||
s32 scePerfArmPmonStart(ARMv7Thread& context, s32 threadId)
|
||||
{
|
||||
scePerf.Warning("scePerfArmPmonStart(threadId=0x%x)", threadId);
|
||||
scePerf.warning("scePerfArmPmonStart(threadId=0x%x)", threadId);
|
||||
|
||||
if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF)
|
||||
{
|
||||
@@ -86,7 +86,7 @@ s32 scePerfArmPmonStart(ARMv7Thread& context, s32 threadId)
|
||||
|
||||
s32 scePerfArmPmonStop(ARMv7Thread& context, s32 threadId)
|
||||
{
|
||||
scePerf.Warning("scePerfArmPmonStop(threadId=0x%x)");
|
||||
scePerf.warning("scePerfArmPmonStop(threadId=0x%x)");
|
||||
|
||||
if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF)
|
||||
{
|
||||
@@ -98,7 +98,7 @@ s32 scePerfArmPmonStop(ARMv7Thread& context, s32 threadId)
|
||||
|
||||
s32 scePerfArmPmonGetCounterValue(ARMv7Thread& context, s32 threadId, u32 counter, vm::ptr<u32> pValue)
|
||||
{
|
||||
scePerf.Warning("scePerfArmPmonGetCounterValue(threadId=0x%x, counter=%d, pValue=*0x%x)", threadId, counter, pValue);
|
||||
scePerf.warning("scePerfArmPmonGetCounterValue(threadId=0x%x, counter=%d, pValue=*0x%x)", threadId, counter, pValue);
|
||||
|
||||
if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF)
|
||||
{
|
||||
@@ -124,7 +124,7 @@ s32 scePerfArmPmonGetCounterValue(ARMv7Thread& context, s32 threadId, u32 counte
|
||||
|
||||
s32 scePerfArmPmonSoftwareIncrement(ARMv7Thread& context, u32 mask)
|
||||
{
|
||||
scePerf.Warning("scePerfArmPmonSoftwareIncrement(mask=0x%x)", mask);
|
||||
scePerf.warning("scePerfArmPmonSoftwareIncrement(mask=0x%x)", mask);
|
||||
|
||||
if (mask > SCE_PERF_ARM_PMON_COUNTER_MASK_ALL)
|
||||
{
|
||||
@@ -144,14 +144,14 @@ s32 scePerfArmPmonSoftwareIncrement(ARMv7Thread& context, u32 mask)
|
||||
|
||||
u64 scePerfGetTimebaseValue()
|
||||
{
|
||||
scePerf.Warning("scePerfGetTimebaseValue()");
|
||||
scePerf.warning("scePerfGetTimebaseValue()");
|
||||
|
||||
return get_system_time();
|
||||
}
|
||||
|
||||
u32 scePerfGetTimebaseFrequency()
|
||||
{
|
||||
scePerf.Warning("scePerfGetTimebaseFrequency()");
|
||||
scePerf.warning("scePerfGetTimebaseFrequency()");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -198,4 +198,4 @@ psv_log_base scePerf("ScePerf", []()
|
||||
REG_FUNC(0xC3DE4C0A, sceRazorCpuPushMarker);
|
||||
REG_FUNC(0xDC3224C3, sceRazorCpuPopMarker);
|
||||
REG_FUNC(0x4F1385E3, sceRazorCpuSync);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
|
||||
s32 sceSysmoduleLoadModule(u16 id)
|
||||
{
|
||||
sceSysmodule.Warning("sceSysmoduleLoadModule(id=0x%04x) -> SCE_OK", id);
|
||||
sceSysmodule.warning("sceSysmoduleLoadModule(id=0x%04x) -> SCE_OK", id);
|
||||
|
||||
return SCE_OK; // loading succeeded
|
||||
}
|
||||
|
||||
s32 sceSysmoduleUnloadModule(u16 id)
|
||||
{
|
||||
sceSysmodule.Warning("sceSysmoduleUnloadModule(id=0x%04x) -> SCE_OK", id);
|
||||
sceSysmodule.warning("sceSysmoduleUnloadModule(id=0x%04x) -> SCE_OK", id);
|
||||
|
||||
return SCE_OK; // unloading succeeded
|
||||
}
|
||||
|
||||
s32 sceSysmoduleIsLoaded(u16 id)
|
||||
{
|
||||
sceSysmodule.Warning("sceSysmoduleIsLoaded(id=0x%04x) -> SCE_OK", id);
|
||||
sceSysmodule.warning("sceSysmoduleIsLoaded(id=0x%04x) -> SCE_OK", id);
|
||||
|
||||
return SCE_OK; // module is loaded
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
#include "PSVFuncList.h"
|
||||
|
||||
psv_log_base::psv_log_base(const std::string& name, init_func_t init)
|
||||
: m_name(name)
|
||||
: _log::channel(name)
|
||||
, m_init(init)
|
||||
{
|
||||
on_error = [this](s32 code, psv_func* func)
|
||||
{
|
||||
if (code < 0)
|
||||
{
|
||||
Error("%s() failed: 0x%08X", func->name, code);
|
||||
error("%s() failed: 0x%08X", func->name, code);
|
||||
Emu.Pause();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,16 +2,14 @@
|
||||
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "ARMv7Thread.h"
|
||||
#include "Emu/SysCalls/LogBase.h"
|
||||
|
||||
namespace vm { using namespace psv; }
|
||||
|
||||
// PSV module class
|
||||
class psv_log_base : public LogBase
|
||||
class psv_log_base : public _log::channel
|
||||
{
|
||||
using init_func_t = void(*)();
|
||||
|
||||
std::string m_name;
|
||||
init_func_t m_init;
|
||||
|
||||
public:
|
||||
@@ -32,12 +30,6 @@ public:
|
||||
|
||||
m_init();
|
||||
}
|
||||
|
||||
virtual const std::string& GetName() const override
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using armv7_func_caller = void(*)(ARMv7Thread&);
|
||||
@@ -321,7 +313,7 @@ namespace psv_func_detail
|
||||
static const bool is_variadic = std::is_same<std::remove_cv_t<T>, armv7_va_args_t>::value;
|
||||
static const bool is_general = !is_float && !is_vector && !is_context && !is_variadic;
|
||||
|
||||
static const u32 g_align = alignof32(T) > 4 ? alignof32(T) >> 2 : 1;
|
||||
static const u32 g_align = ALIGN_32(T) > 4 ? ALIGN_32(T) >> 2 : 1;
|
||||
static const u32 g_value = is_general ? ((g_count + (g_align - 1)) & ~(g_align - 1)) + (g_align) : g_count;
|
||||
static const u32 f_value = f_count + is_float;
|
||||
static const u32 v_value = v_count + is_vector;
|
||||
|
||||
@@ -1,24 +1,10 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "AudioManager.h"
|
||||
#include "Emu/state.h"
|
||||
|
||||
AudioManager::AudioManager() : m_audio_out(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
AudioManager::~AudioManager()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void AudioManager::Init()
|
||||
{
|
||||
if (m_audio_out) return;
|
||||
|
||||
m_audio_info.Init();
|
||||
|
||||
m_audio_out = Emu.GetCallbacks().get_audio();
|
||||
if (!m_audio_out) m_audio_out = Emu.GetCallbacks().get_audio();
|
||||
}
|
||||
|
||||
void AudioManager::Close()
|
||||
|
||||
@@ -2,29 +2,13 @@
|
||||
|
||||
#include "AudioThread.h"
|
||||
|
||||
// it cannot be configured currently, and it must NOT use cellSysutil definitions
|
||||
struct AudioInfo
|
||||
{
|
||||
AudioInfo()
|
||||
{
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class AudioManager
|
||||
{
|
||||
AudioInfo m_audio_info;
|
||||
std::shared_ptr<AudioThread> m_audio_out;
|
||||
public:
|
||||
AudioManager();
|
||||
~AudioManager();
|
||||
|
||||
public:
|
||||
void Init();
|
||||
void Close();
|
||||
|
||||
AudioThread& GetAudioOut() { assert(m_audio_out); return *m_audio_out; }
|
||||
AudioInfo& GetInfo() { return m_audio_info; }
|
||||
AudioThread& GetAudioOut() { return *m_audio_out; }
|
||||
};
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
|
||||
#include "Emu/Audio/AudioThread.h"
|
||||
|
||||
#pragma push_macro("_WIN32_WINNT")
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0601 // This is to be sure that correct (2.7) header is included
|
||||
#include "minidx9/Include/XAudio2.h" // XAudio2 2.8 available only on Win8+, used XAudio2 2.7 from dxsdk
|
||||
#undef _WIN32_WINNT
|
||||
#pragma pop_macro("_WIN32_WINNT")
|
||||
|
||||
class XAudio2Thread : public AudioThread
|
||||
{
|
||||
|
||||
@@ -89,7 +89,7 @@ void CPUThread::dump_info() const
|
||||
{
|
||||
if (!Emu.IsStopped())
|
||||
{
|
||||
LOG_NOTICE(GENERAL, RegsToString());
|
||||
LOG_NOTICE(GENERAL, "%s", RegsToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1778,7 +1778,7 @@ void ppu_interpreter::LWARX(PPUThread& CPU, ppu_opcode_t op)
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
|
||||
be_t<u32> value;
|
||||
vm::reservation_acquire(&value, VM_CAST(addr), sizeof32(value));
|
||||
vm::reservation_acquire(&value, VM_CAST(addr), SIZE_32(value));
|
||||
|
||||
CPU.GPR[op.rd] = value;
|
||||
}
|
||||
@@ -1949,7 +1949,7 @@ void ppu_interpreter::LDARX(PPUThread& CPU, ppu_opcode_t op)
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
|
||||
be_t<u64> value;
|
||||
vm::reservation_acquire(&value, VM_CAST(addr), sizeof32(value));
|
||||
vm::reservation_acquire(&value, VM_CAST(addr), SIZE_32(value));
|
||||
|
||||
CPU.GPR[op.rd] = value;
|
||||
}
|
||||
@@ -2079,7 +2079,7 @@ void ppu_interpreter::STWCX_(PPUThread& CPU, ppu_opcode_t op)
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
|
||||
const be_t<u32> value = (u32)CPU.GPR[op.rs];
|
||||
CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, sizeof32(value)));
|
||||
CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, SIZE_32(value)));
|
||||
}
|
||||
|
||||
void ppu_interpreter::STWX(PPUThread& CPU, ppu_opcode_t op)
|
||||
@@ -2139,7 +2139,7 @@ void ppu_interpreter::STDCX_(PPUThread& CPU, ppu_opcode_t op)
|
||||
const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb];
|
||||
|
||||
const be_t<u64> value = CPU.GPR[op.rs];
|
||||
CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, sizeof32(value)));
|
||||
CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, SIZE_32(value)));
|
||||
}
|
||||
|
||||
void ppu_interpreter::STBX(PPUThread& CPU, ppu_opcode_t op)
|
||||
|
||||
+369
-369
File diff suppressed because it is too large
Load Diff
@@ -188,7 +188,7 @@ void ppu_recompiler_llvm::Compiler::translate_to_llvm_ir(llvm::Module *module, c
|
||||
std::string verify;
|
||||
raw_string_ostream verify_ostream(verify);
|
||||
if (verifyFunction(*m_state.function, &verify_ostream)) {
|
||||
// m_recompilation_engine.Log() << "Verification failed: " << verify_ostream.str() << "\n";
|
||||
// m_recompilation_engine.trace() << "Verification failed: " << verify_ostream.str() << "\n";
|
||||
}
|
||||
|
||||
m_module = nullptr;
|
||||
@@ -421,13 +421,13 @@ std::pair<Executable, llvm::ExecutionEngine *> RecompilationEngine::compile(cons
|
||||
Function *llvm_function = module_ptr->getFunction(name);
|
||||
void *function = execution_engine->getPointerToFunction(llvm_function);
|
||||
|
||||
/* m_recompilation_engine.Log() << "\nDisassembly:\n";
|
||||
/* m_recompilation_engine.trace() << "\nDisassembly:\n";
|
||||
auto disassembler = LLVMCreateDisasm(sys::getProcessTriple().c_str(), nullptr, 0, nullptr, nullptr);
|
||||
for (size_t pc = 0; pc < mci.size();) {
|
||||
char str[1024];
|
||||
|
||||
auto size = LLVMDisasmInstruction(disassembler, ((u8 *)mci.address()) + pc, mci.size() - pc, (uint64_t)(((u8 *)mci.address()) + pc), str, sizeof(str));
|
||||
m_recompilation_engine.Log() << fmt::format("0x%08X: ", (u64)(((u8 *)mci.address()) + pc)) << str << '\n';
|
||||
m_recompilation_engine.trace() << fmt::format("0x%08X: ", (u64)(((u8 *)mci.address()) + pc)) << str << '\n';
|
||||
pc += size;
|
||||
}
|
||||
|
||||
|
||||
@@ -5097,33 +5097,33 @@ Value * Compiler::SetNibble(Value * val, u32 n, Value * b0, Value * b1, Value *
|
||||
}
|
||||
|
||||
Value * Compiler::GetPc() {
|
||||
auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, PC));
|
||||
auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, PC));
|
||||
auto pc_i32_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(pc_i32_ptr, 4);
|
||||
}
|
||||
|
||||
void Compiler::SetPc(Value * val_ix) {
|
||||
auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, PC));
|
||||
auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, PC));
|
||||
auto pc_i32_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||
auto val_i32 = m_ir_builder->CreateZExtOrTrunc(val_ix, m_ir_builder->getInt32Ty());
|
||||
m_ir_builder->CreateAlignedStore(val_i32, pc_i32_ptr, 4);
|
||||
}
|
||||
|
||||
Value * Compiler::GetGpr(u32 r, u32 num_bits) {
|
||||
auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, GPR[r]));
|
||||
auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, GPR[r]));
|
||||
auto r_ix_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getIntNTy(num_bits)->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(r_ix_ptr, 8);
|
||||
}
|
||||
|
||||
void Compiler::SetGpr(u32 r, Value * val_x64) {
|
||||
auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, GPR[r]));
|
||||
auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, GPR[r]));
|
||||
auto r_i64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||
auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty());
|
||||
m_ir_builder->CreateAlignedStore(val_i64, r_i64_ptr, 8);
|
||||
}
|
||||
|
||||
Value * Compiler::GetCr() {
|
||||
auto cr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, CR));
|
||||
auto cr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CR));
|
||||
auto cr_i32_ptr = m_ir_builder->CreateBitCast(cr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(cr_i32_ptr, 4);
|
||||
}
|
||||
@@ -5134,7 +5134,7 @@ Value * Compiler::GetCrField(u32 n) {
|
||||
|
||||
void Compiler::SetCr(Value * val_x32) {
|
||||
auto val_i32 = m_ir_builder->CreateBitCast(val_x32, m_ir_builder->getInt32Ty());
|
||||
auto cr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, CR));
|
||||
auto cr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CR));
|
||||
auto cr_i32_ptr = m_ir_builder->CreateBitCast(cr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||
m_ir_builder->CreateAlignedStore(val_i32, cr_i32_ptr, 4);
|
||||
}
|
||||
@@ -5176,33 +5176,33 @@ void Compiler::SetCr6AfterVectorCompare(u32 vr) {
|
||||
}
|
||||
|
||||
Value * Compiler::GetLr() {
|
||||
auto lr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, LR));
|
||||
auto lr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, LR));
|
||||
auto lr_i64_ptr = m_ir_builder->CreateBitCast(lr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(lr_i64_ptr, 8);
|
||||
}
|
||||
|
||||
void Compiler::SetLr(Value * val_x64) {
|
||||
auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty());
|
||||
auto lr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, LR));
|
||||
auto lr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, LR));
|
||||
auto lr_i64_ptr = m_ir_builder->CreateBitCast(lr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||
m_ir_builder->CreateAlignedStore(val_i64, lr_i64_ptr, 8);
|
||||
}
|
||||
|
||||
Value * Compiler::GetCtr() {
|
||||
auto ctr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, CTR));
|
||||
auto ctr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CTR));
|
||||
auto ctr_i64_ptr = m_ir_builder->CreateBitCast(ctr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(ctr_i64_ptr, 8);
|
||||
}
|
||||
|
||||
void Compiler::SetCtr(Value * val_x64) {
|
||||
auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty());
|
||||
auto ctr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, CTR));
|
||||
auto ctr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CTR));
|
||||
auto ctr_i64_ptr = m_ir_builder->CreateBitCast(ctr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||
m_ir_builder->CreateAlignedStore(val_i64, ctr_i64_ptr, 8);
|
||||
}
|
||||
|
||||
Value * Compiler::GetXer() {
|
||||
auto xer_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, XER));
|
||||
auto xer_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, XER));
|
||||
auto xer_i64_ptr = m_ir_builder->CreateBitCast(xer_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(xer_i64_ptr, 8);
|
||||
}
|
||||
@@ -5217,7 +5217,7 @@ Value * Compiler::GetXerSo() {
|
||||
|
||||
void Compiler::SetXer(Value * val_x64) {
|
||||
auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty());
|
||||
auto xer_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, XER));
|
||||
auto xer_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, XER));
|
||||
auto xer_i64_ptr = m_ir_builder->CreateBitCast(xer_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||
m_ir_builder->CreateAlignedStore(val_i64, xer_i64_ptr, 8);
|
||||
}
|
||||
@@ -5235,7 +5235,7 @@ void Compiler::SetXerSo(Value * so) {
|
||||
}
|
||||
|
||||
Value * Compiler::GetVrsave() {
|
||||
auto vrsave_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VRSAVE));
|
||||
auto vrsave_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VRSAVE));
|
||||
auto vrsave_i32_ptr = m_ir_builder->CreateBitCast(vrsave_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||
auto val_i32 = m_ir_builder->CreateAlignedLoad(vrsave_i32_ptr, 4);
|
||||
return m_ir_builder->CreateZExtOrTrunc(val_i32, m_ir_builder->getInt64Ty());
|
||||
@@ -5244,26 +5244,26 @@ Value * Compiler::GetVrsave() {
|
||||
void Compiler::SetVrsave(Value * val_x64) {
|
||||
auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty());
|
||||
auto val_i32 = m_ir_builder->CreateZExtOrTrunc(val_i64, m_ir_builder->getInt32Ty());
|
||||
auto vrsave_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VRSAVE));
|
||||
auto vrsave_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VRSAVE));
|
||||
auto vrsave_i32_ptr = m_ir_builder->CreateBitCast(vrsave_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||
m_ir_builder->CreateAlignedStore(val_i32, vrsave_i32_ptr, 8);
|
||||
}
|
||||
|
||||
Value * Compiler::GetFpscr() {
|
||||
auto fpscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, FPSCR));
|
||||
auto fpscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPSCR));
|
||||
auto fpscr_i32_ptr = m_ir_builder->CreateBitCast(fpscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(fpscr_i32_ptr, 4);
|
||||
}
|
||||
|
||||
void Compiler::SetFpscr(Value * val_x32) {
|
||||
auto val_i32 = m_ir_builder->CreateBitCast(val_x32, m_ir_builder->getInt32Ty());
|
||||
auto fpscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, FPSCR));
|
||||
auto fpscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPSCR));
|
||||
auto fpscr_i32_ptr = m_ir_builder->CreateBitCast(fpscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||
m_ir_builder->CreateAlignedStore(val_i32, fpscr_i32_ptr, 4);
|
||||
}
|
||||
|
||||
Value * Compiler::GetFpr(u32 r, u32 bits, bool as_int) {
|
||||
auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, FPR[r]));
|
||||
auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPR[r]));
|
||||
if (!as_int) {
|
||||
auto r_f64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getDoubleTy()->getPointerTo());
|
||||
auto r_f64 = m_ir_builder->CreateAlignedLoad(r_f64_ptr, 8);
|
||||
@@ -5287,7 +5287,7 @@ Value * Compiler::GetFpr(u32 r, u32 bits, bool as_int) {
|
||||
}
|
||||
|
||||
void Compiler::SetFpr(u32 r, Value * val) {
|
||||
auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, FPR[r]));
|
||||
auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPR[r]));
|
||||
auto r_f64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getDoubleTy()->getPointerTo());
|
||||
|
||||
Value* val_f64;
|
||||
@@ -5306,47 +5306,47 @@ void Compiler::SetFpr(u32 r, Value * val) {
|
||||
}
|
||||
|
||||
Value * Compiler::GetVscr() {
|
||||
auto vscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VSCR));
|
||||
auto vscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VSCR));
|
||||
auto vscr_i32_ptr = m_ir_builder->CreateBitCast(vscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(vscr_i32_ptr, 4);
|
||||
}
|
||||
|
||||
void Compiler::SetVscr(Value * val_x32) {
|
||||
auto val_i32 = m_ir_builder->CreateBitCast(val_x32, m_ir_builder->getInt32Ty());
|
||||
auto vscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VSCR));
|
||||
auto vscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VSCR));
|
||||
auto vscr_i32_ptr = m_ir_builder->CreateBitCast(vscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||
m_ir_builder->CreateAlignedStore(val_i32, vscr_i32_ptr, 4);
|
||||
}
|
||||
|
||||
Value * Compiler::GetVr(u32 vr) {
|
||||
auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VPR[vr]));
|
||||
auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr]));
|
||||
auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(vr_i128_ptr, 16);
|
||||
}
|
||||
|
||||
Value * Compiler::GetVrAsIntVec(u32 vr, u32 vec_elt_num_bits) {
|
||||
auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VPR[vr]));
|
||||
auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr]));
|
||||
auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo());
|
||||
auto vr_vec_ptr = m_ir_builder->CreateBitCast(vr_i128_ptr, VectorType::get(m_ir_builder->getIntNTy(vec_elt_num_bits), 128 / vec_elt_num_bits)->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(vr_vec_ptr, 16);
|
||||
}
|
||||
|
||||
Value * Compiler::GetVrAsFloatVec(u32 vr) {
|
||||
auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VPR[vr]));
|
||||
auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr]));
|
||||
auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo());
|
||||
auto vr_v4f32_ptr = m_ir_builder->CreateBitCast(vr_i128_ptr, VectorType::get(m_ir_builder->getFloatTy(), 4)->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(vr_v4f32_ptr, 16);
|
||||
}
|
||||
|
||||
Value * Compiler::GetVrAsDoubleVec(u32 vr) {
|
||||
auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VPR[vr]));
|
||||
auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr]));
|
||||
auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo());
|
||||
auto vr_v2f64_ptr = m_ir_builder->CreateBitCast(vr_i128_ptr, VectorType::get(m_ir_builder->getDoubleTy(), 2)->getPointerTo());
|
||||
return m_ir_builder->CreateAlignedLoad(vr_v2f64_ptr, 16);
|
||||
}
|
||||
|
||||
void Compiler::SetVr(u32 vr, Value * val_x128) {
|
||||
auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VPR[vr]));
|
||||
auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr]));
|
||||
auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo());
|
||||
auto val_i128 = m_ir_builder->CreateBitCast(val_x128, m_ir_builder->getIntNTy(128));
|
||||
m_ir_builder->CreateAlignedStore(val_i128, vr_i128_ptr, 16);
|
||||
|
||||
@@ -349,9 +349,9 @@ cpu_thread& ppu_thread::args(std::initializer_list<std::string> values)
|
||||
|
||||
assert(argc == 0);
|
||||
|
||||
envp.set(vm::alloc(align(sizeof32(*envp), stack_align), vm::main));
|
||||
envp.set(vm::alloc(align(SIZE_32(*envp), stack_align), vm::main));
|
||||
*envp = 0;
|
||||
argv.set(vm::alloc(sizeof32(*argv) * (u32)values.size(), vm::main));
|
||||
argv.set(vm::alloc(SIZE_32(*argv) * (u32)values.size(), vm::main));
|
||||
|
||||
for (auto &arg : values)
|
||||
{
|
||||
|
||||
@@ -1017,6 +1017,8 @@ enum : u32
|
||||
{
|
||||
MFF_FORCED_HLE = (1 << 0), // always call HLE function
|
||||
MFF_NO_RETURN = (1 << 1), // uses EIF_USE_BRANCH flag with LLE, ignored with MFF_FORCED_HLE
|
||||
|
||||
MFF_PERFECT = /* 0 */ MFF_FORCED_HLE, // can be set for fully implemented functions with LLE compatibility
|
||||
};
|
||||
|
||||
// flags passed with index
|
||||
@@ -1026,5 +1028,5 @@ enum : u32
|
||||
EIF_PERFORM_BLR = (1 << 24), // do BLR after calling HLE/LLE function
|
||||
EIF_USE_BRANCH = (1 << 23), // do only branch, LLE must be set, last_syscall must be zero
|
||||
|
||||
EIF_FLAGS = 0x3800000, // all flags
|
||||
EIF_FLAGS = 0x3800000, // all flags
|
||||
};
|
||||
|
||||
@@ -60,7 +60,7 @@ bool RawSPUThread::read_reg(const u32 addr, u32& value)
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(0x%x): unknown/illegal offset (0x%x)", index, addr, offset);
|
||||
LOG_ERROR(SPU, "RawSPUThread[%d]: Read32(0x%x): unknown/illegal offset (0x%x)", index, addr, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
|
||||
#include "asmjit.h"
|
||||
|
||||
#define OFFSET_OF(type, x) static_cast<s32>(reinterpret_cast<uintptr_t>(&(((type*)0)->x)))
|
||||
|
||||
#define SPU_OFF_128(x) asmjit::host::oword_ptr(*cpu, OFFSET_OF(SPUThread, x))
|
||||
#define SPU_OFF_64(x) asmjit::host::qword_ptr(*cpu, OFFSET_OF(SPUThread, x))
|
||||
#define SPU_OFF_32(x) asmjit::host::dword_ptr(*cpu, OFFSET_OF(SPUThread, x))
|
||||
#define SPU_OFF_16(x) asmjit::host::word_ptr(*cpu, OFFSET_OF(SPUThread, x))
|
||||
#define SPU_OFF_8(x) asmjit::host::byte_ptr(*cpu, OFFSET_OF(SPUThread, x))
|
||||
#define SPU_OFF_128(x) asmjit::host::oword_ptr(*cpu, OFFSET_32(SPUThread, x))
|
||||
#define SPU_OFF_64(x) asmjit::host::qword_ptr(*cpu, OFFSET_32(SPUThread, x))
|
||||
#define SPU_OFF_32(x) asmjit::host::dword_ptr(*cpu, OFFSET_32(SPUThread, x))
|
||||
#define SPU_OFF_16(x) asmjit::host::word_ptr(*cpu, OFFSET_32(SPUThread, x))
|
||||
#define SPU_OFF_8(x) asmjit::host::byte_ptr(*cpu, OFFSET_32(SPUThread, x))
|
||||
|
||||
spu_recompiler::spu_recompiler()
|
||||
: m_jit(std::make_shared<asmjit::JitRuntime>())
|
||||
@@ -31,7 +29,7 @@ spu_recompiler::spu_recompiler()
|
||||
|
||||
LOG_SUCCESS(SPU, "SPU Recompiler (ASMJIT) created...");
|
||||
|
||||
fs::file(fs::get_config_dir() + "SPUJIT.log", fom::rewrite) << fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str());
|
||||
fs::file(fs::get_config_dir() + "SPUJIT.log", fom::rewrite).write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str()));
|
||||
}
|
||||
|
||||
void spu_recompiler::compile(spu_function_t& f)
|
||||
@@ -216,7 +214,7 @@ void spu_recompiler::compile(spu_function_t& f)
|
||||
log += "\n\n\n";
|
||||
|
||||
// Append log file
|
||||
fs::file(fs::get_config_dir() + "SPUJIT.log", fom::write | fom::append) << log;
|
||||
fs::file(fs::get_config_dir() + "SPUJIT.log", fom::write | fom::append).write(log);
|
||||
}
|
||||
|
||||
spu_recompiler::XmmLink spu_recompiler::XmmAlloc() // get empty xmm register
|
||||
@@ -1083,7 +1081,7 @@ void spu_recompiler::CBX(spu_opcode_t op)
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->mov(asmjit::host::byte_ptr(*cpu, *addr, 0, OFFSET_OF(SPUThread, gpr[op.rt])), 0x03);
|
||||
c->mov(asmjit::host::byte_ptr(*cpu, *addr, 0, OFFSET_32(SPUThread, gpr[op.rt])), 0x03);
|
||||
c->unuse(*addr);
|
||||
}
|
||||
|
||||
@@ -1097,7 +1095,7 @@ void spu_recompiler::CHX(spu_opcode_t op)
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->mov(asmjit::host::word_ptr(*cpu, *addr, 0, OFFSET_OF(SPUThread, gpr[op.rt])), 0x0203);
|
||||
c->mov(asmjit::host::word_ptr(*cpu, *addr, 0, OFFSET_32(SPUThread, gpr[op.rt])), 0x0203);
|
||||
c->unuse(*addr);
|
||||
}
|
||||
|
||||
@@ -1111,7 +1109,7 @@ void spu_recompiler::CWX(spu_opcode_t op)
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->mov(asmjit::host::dword_ptr(*cpu, *addr, 0, OFFSET_OF(SPUThread, gpr[op.rt])), 0x00010203);
|
||||
c->mov(asmjit::host::dword_ptr(*cpu, *addr, 0, OFFSET_32(SPUThread, gpr[op.rt])), 0x00010203);
|
||||
c->unuse(*addr);
|
||||
}
|
||||
|
||||
@@ -1126,7 +1124,7 @@ void spu_recompiler::CDX(spu_opcode_t op)
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->mov(*qw0, asmjit::imm_u(0x0001020304050607));
|
||||
c->mov(asmjit::host::qword_ptr(*cpu, *addr, 0, OFFSET_OF(SPUThread, gpr[op.rt])), *qw0);
|
||||
c->mov(asmjit::host::qword_ptr(*cpu, *addr, 0, OFFSET_32(SPUThread, gpr[op.rt])), *qw0);
|
||||
c->unuse(*addr);
|
||||
c->unuse(*qw0);
|
||||
}
|
||||
@@ -1254,7 +1252,7 @@ void spu_recompiler::CBD(spu_opcode_t op)
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->mov(asmjit::host::byte_ptr(*cpu, *addr, 0, OFFSET_OF(SPUThread, gpr[op.rt])), 0x03);
|
||||
c->mov(asmjit::host::byte_ptr(*cpu, *addr, 0, OFFSET_32(SPUThread, gpr[op.rt])), 0x03);
|
||||
c->unuse(*addr);
|
||||
}
|
||||
|
||||
@@ -1279,7 +1277,7 @@ void spu_recompiler::CHD(spu_opcode_t op)
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->mov(asmjit::host::word_ptr(*cpu, *addr, 0, OFFSET_OF(SPUThread, gpr[op.rt])), 0x0203);
|
||||
c->mov(asmjit::host::word_ptr(*cpu, *addr, 0, OFFSET_32(SPUThread, gpr[op.rt])), 0x0203);
|
||||
c->unuse(*addr);
|
||||
}
|
||||
|
||||
@@ -1304,7 +1302,7 @@ void spu_recompiler::CWD(spu_opcode_t op)
|
||||
const XmmLink& vr = XmmAlloc();
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->mov(asmjit::host::dword_ptr(*cpu, *addr, 0, OFFSET_OF(SPUThread, gpr[op.rt])), 0x00010203);
|
||||
c->mov(asmjit::host::dword_ptr(*cpu, *addr, 0, OFFSET_32(SPUThread, gpr[op.rt])), 0x00010203);
|
||||
c->unuse(*addr);
|
||||
}
|
||||
|
||||
@@ -1330,7 +1328,7 @@ void spu_recompiler::CDD(spu_opcode_t op)
|
||||
c->movdqa(vr, XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
c->movdqa(SPU_OFF_128(gpr[op.rt]), vr);
|
||||
c->mov(*qw0, asmjit::imm_u(0x0001020304050607));
|
||||
c->mov(asmjit::host::qword_ptr(*cpu, *addr, 0, OFFSET_OF(SPUThread, gpr[op.rt])), *qw0);
|
||||
c->mov(asmjit::host::qword_ptr(*cpu, *addr, 0, OFFSET_32(SPUThread, gpr[op.rt])), *qw0);
|
||||
c->unuse(*addr);
|
||||
c->unuse(*qw0);
|
||||
}
|
||||
|
||||
@@ -376,10 +376,7 @@ void SPUThread::do_dma_list_cmd(u32 cmd, spu_mfc_arg_t args)
|
||||
|
||||
void SPUThread::process_mfc_cmd(u32 cmd)
|
||||
{
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(SPU, "DMA %s: cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x", get_mfc_cmd_name(cmd), cmd, ch_mfc_args.lsa, ch_mfc_args.ea, ch_mfc_args.tag, ch_mfc_args.size);
|
||||
}
|
||||
LOG_TRACE(SPU, "DMA %s: cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x", get_mfc_cmd_name(cmd), cmd, ch_mfc_args.lsa, ch_mfc_args.ea, ch_mfc_args.tag, ch_mfc_args.size);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
@@ -576,10 +573,7 @@ void SPUThread::set_interrupt_status(bool enable)
|
||||
|
||||
u32 SPUThread::get_ch_count(u32 ch)
|
||||
{
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(SPU, "get_ch_count(ch=%d [%s])", ch, ch < 128 ? spu_ch_name[ch] : "???");
|
||||
}
|
||||
LOG_TRACE(SPU, "get_ch_count(ch=%d [%s])", ch, ch < 128 ? spu_ch_name[ch] : "???");
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
@@ -603,10 +597,7 @@ u32 SPUThread::get_ch_count(u32 ch)
|
||||
|
||||
u32 SPUThread::get_ch_value(u32 ch)
|
||||
{
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(SPU, "get_ch_value(ch=%d [%s])", ch, ch < 128 ? spu_ch_name[ch] : "???");
|
||||
}
|
||||
LOG_TRACE(SPU, "get_ch_value(ch=%d [%s])", ch, ch < 128 ? spu_ch_name[ch] : "???");
|
||||
|
||||
auto read_channel = [this](spu_channel_t& channel) -> u32
|
||||
{
|
||||
@@ -767,10 +758,7 @@ u32 SPUThread::get_ch_value(u32 ch)
|
||||
|
||||
void SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
{
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(SPU, "set_ch_value(ch=%d [%s], value=0x%x)", ch, ch < 128 ? spu_ch_name[ch] : "???", value);
|
||||
}
|
||||
LOG_TRACE(SPU, "set_ch_value(ch=%d [%s], value=0x%x)", ch, ch < 128 ? spu_ch_name[ch] : "???", value);
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
@@ -826,10 +814,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
|
||||
ch_out_mbox.set_value(data, 0);
|
||||
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data);
|
||||
}
|
||||
LOG_TRACE(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data);
|
||||
|
||||
const auto queue = this->spup[spup].lock();
|
||||
|
||||
@@ -865,10 +850,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
|
||||
ch_out_mbox.set_value(data, 0);
|
||||
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data);
|
||||
}
|
||||
LOG_TRACE(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data);
|
||||
|
||||
const auto queue = this->spup[spup].lock();
|
||||
|
||||
@@ -915,10 +897,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
throw EXCEPTION("sys_event_flag_set_bit(id=%d, value=0x%x (flag=%d)): Invalid flag", data, value, flag);
|
||||
}
|
||||
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_WARNING(SPU, "sys_event_flag_set_bit(id=%d, value=0x%x (flag=%d))", data, value, flag);
|
||||
}
|
||||
LOG_TRACE(SPU, "sys_event_flag_set_bit(id=%d, value=0x%x (flag=%d))", data, value, flag);
|
||||
|
||||
const auto eflag = idm::get<lv2_event_flag_t>(data);
|
||||
|
||||
@@ -959,10 +938,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
throw EXCEPTION("sys_event_flag_set_bit_impatient(id=%d, value=0x%x (flag=%d)): Invalid flag", data, value, flag);
|
||||
}
|
||||
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_WARNING(SPU, "sys_event_flag_set_bit_impatient(id=%d, value=0x%x (flag=%d))", data, value, flag);
|
||||
}
|
||||
LOG_TRACE(SPU, "sys_event_flag_set_bit_impatient(id=%d, value=0x%x (flag=%d))", data, value, flag);
|
||||
|
||||
const auto eflag = idm::get<lv2_event_flag_t>(data);
|
||||
|
||||
@@ -1158,10 +1134,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
|
||||
void SPUThread::stop_and_signal(u32 code)
|
||||
{
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(SPU, "stop_and_signal(code=0x%x)", code);
|
||||
}
|
||||
LOG_TRACE(SPU, "stop_and_signal(code=0x%x)", code);
|
||||
|
||||
if (m_type == CPU_THREAD_RAW_SPU)
|
||||
{
|
||||
@@ -1229,10 +1202,7 @@ void SPUThread::stop_and_signal(u32 code)
|
||||
|
||||
ch_out_mbox.set_value(spuq, 0);
|
||||
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq);
|
||||
}
|
||||
LOG_TRACE(SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq);
|
||||
|
||||
const auto group = tg.lock();
|
||||
|
||||
@@ -1355,10 +1325,7 @@ void SPUThread::stop_and_signal(u32 code)
|
||||
|
||||
ch_out_mbox.set_value(value, 0);
|
||||
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(SPU, "sys_spu_thread_group_exit(status=0x%x)", value);
|
||||
}
|
||||
LOG_TRACE(SPU, "sys_spu_thread_group_exit(status=0x%x)", value);
|
||||
|
||||
const auto group = tg.lock();
|
||||
|
||||
@@ -1394,10 +1361,7 @@ void SPUThread::stop_and_signal(u32 code)
|
||||
throw EXCEPTION("sys_spu_thread_exit(): Out_MBox is empty");
|
||||
}
|
||||
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(SPU, "sys_spu_thread_exit(status=0x%x)", ch_out_mbox.get_value());
|
||||
}
|
||||
LOG_TRACE(SPU, "sys_spu_thread_exit(status=0x%x)", ch_out_mbox.get_value());
|
||||
|
||||
const auto group = tg.lock();
|
||||
|
||||
@@ -1425,10 +1389,7 @@ void SPUThread::stop_and_signal(u32 code)
|
||||
|
||||
void SPUThread::halt()
|
||||
{
|
||||
if (rpcs3::config.misc.log.hle_logging.value())
|
||||
{
|
||||
LOG_NOTICE(SPU, "halt()");
|
||||
}
|
||||
LOG_TRACE(SPU, "halt()");
|
||||
|
||||
if (m_type == CPU_THREAD_RAW_SPU)
|
||||
{
|
||||
|
||||
@@ -26,11 +26,9 @@ bool vfsFile::Open(const std::string& path, u32 mode)
|
||||
return m_stream && m_stream->IsOpened();
|
||||
}
|
||||
|
||||
bool vfsFile::Close()
|
||||
void vfsFile::Close()
|
||||
{
|
||||
m_stream.reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 vfsFile::GetSize() const
|
||||
@@ -48,9 +46,9 @@ u64 vfsFile::Read(void* dst, u64 size)
|
||||
return m_stream->Read(dst, size);
|
||||
}
|
||||
|
||||
u64 vfsFile::Seek(s64 offset, fsm mode)
|
||||
u64 vfsFile::Seek(s64 offset, fs::seek_mode whence)
|
||||
{
|
||||
return m_stream->Seek(offset, mode);
|
||||
return m_stream->Seek(offset, whence);
|
||||
}
|
||||
|
||||
u64 vfsFile::Tell() const
|
||||
|
||||
@@ -12,14 +12,14 @@ public:
|
||||
vfsFile(const std::string& path, u32 mode = fom::read);
|
||||
|
||||
virtual bool Open(const std::string& path, u32 mode = fom::read) override;
|
||||
virtual bool Close() override;
|
||||
virtual void Close() override;
|
||||
|
||||
virtual u64 GetSize() const override;
|
||||
|
||||
virtual u64 Write(const void* src, u64 size) override;
|
||||
virtual u64 Read(void* dst, u64 size) override;
|
||||
|
||||
virtual u64 Seek(s64 offset, fsm seek_mode = fsm::begin) override;
|
||||
virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override;
|
||||
virtual u64 Tell() const override;
|
||||
|
||||
virtual bool IsOpened() const override;
|
||||
|
||||
@@ -20,11 +20,10 @@ bool vfsFileBase::Open(const std::string& path, u32 mode)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vfsFileBase::Close()
|
||||
void vfsFileBase::Close()
|
||||
{
|
||||
m_path = "";
|
||||
|
||||
return vfsStream::Close();
|
||||
vfsStream::Close();
|
||||
}
|
||||
|
||||
std::string vfsFileBase::GetPath() const
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
virtual ~vfsFileBase() override;
|
||||
|
||||
virtual bool Open(const std::string& path, u32 mode);
|
||||
virtual bool Close() override;
|
||||
virtual void Close() override;
|
||||
virtual bool IsOpened() const override { return !m_path.empty(); }
|
||||
|
||||
std::string GetPath() const;
|
||||
|
||||
@@ -20,7 +20,7 @@ bool vfsLocalDir::Open(const std::string& path)
|
||||
std::string name;
|
||||
fs::stat_t file_info;
|
||||
|
||||
while (m_dir.read(name, file_info))
|
||||
while (m_dir.read(name, file_info) && name.size())
|
||||
{
|
||||
m_entries.emplace_back();
|
||||
|
||||
|
||||
@@ -12,9 +12,10 @@ bool vfsLocalFile::Open(const std::string& path, u32 mode)
|
||||
return m_file.open(path, mode) && vfsFileBase::Open(path, mode);
|
||||
}
|
||||
|
||||
bool vfsLocalFile::Close()
|
||||
void vfsLocalFile::Close()
|
||||
{
|
||||
return m_file.close() && vfsFileBase::Close();
|
||||
m_file.close();
|
||||
vfsFileBase::Close();
|
||||
}
|
||||
|
||||
u64 vfsLocalFile::GetSize() const
|
||||
@@ -32,14 +33,14 @@ u64 vfsLocalFile::Read(void* dst, u64 size)
|
||||
return m_file.read(dst, size);
|
||||
}
|
||||
|
||||
u64 vfsLocalFile::Seek(s64 offset, fsm mode)
|
||||
u64 vfsLocalFile::Seek(s64 offset, fs::seek_mode whence)
|
||||
{
|
||||
return m_file.seek(offset, mode);
|
||||
return m_file.seek(offset, whence);
|
||||
}
|
||||
|
||||
u64 vfsLocalFile::Tell() const
|
||||
{
|
||||
return m_file.seek(0, fsm::cur);
|
||||
return m_file.seek(0, fs::seek_cur);
|
||||
}
|
||||
|
||||
bool vfsLocalFile::IsOpened() const
|
||||
|
||||
@@ -11,14 +11,14 @@ public:
|
||||
vfsLocalFile(vfsDevice* device);
|
||||
|
||||
virtual bool Open(const std::string& path, u32 mode = fom::read) override;
|
||||
virtual bool Close() override;
|
||||
virtual void Close() override;
|
||||
|
||||
virtual u64 GetSize() const override;
|
||||
|
||||
virtual u64 Write(const void* src, u64 size) override;
|
||||
virtual u64 Read(void* dst, u64 size) override;
|
||||
|
||||
virtual u64 Seek(s64 offset, fsm seek_mode = fsm::begin) override;
|
||||
virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override;
|
||||
virtual u64 Tell() const override;
|
||||
|
||||
virtual bool IsOpened() const override;
|
||||
|
||||
@@ -9,28 +9,54 @@ struct vfsStream
|
||||
Close();
|
||||
}
|
||||
|
||||
virtual bool Close()
|
||||
virtual void Close()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual u64 GetSize() const = 0;
|
||||
|
||||
virtual u64 Write(const void* src, u64 count) = 0;
|
||||
|
||||
template<typename T> force_inline bool SWrite(const T& data, u64 count = sizeof(T))
|
||||
template<typename T>
|
||||
force_inline bool SWrite(const T& data, u64 count = sizeof(T))
|
||||
{
|
||||
return Write(&data, count) == count;
|
||||
}
|
||||
|
||||
virtual u64 Read(void* dst, u64 count) = 0;
|
||||
|
||||
template<typename T> force_inline bool SRead(T& data, u64 count = sizeof(T))
|
||||
template<typename T>
|
||||
force_inline bool SRead(T& data, u64 count = sizeof(T))
|
||||
{
|
||||
return Read(&data, count) == count;
|
||||
}
|
||||
|
||||
virtual u64 Seek(s64 offset, fsm seek_mode = fsm::begin) = 0;
|
||||
template<typename T>
|
||||
bool VWrite(const std::vector<T>& vec)
|
||||
{
|
||||
return IsOpened() && Write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> VRead()
|
||||
{
|
||||
std::vector<T> result;
|
||||
if (IsOpened() == false)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result.resize(GetSize() / sizeof(T));
|
||||
|
||||
if (Seek(0) == -1 || Read(result.data(), result.size() * sizeof(T)) != result.size() * sizeof(T))
|
||||
{
|
||||
result.clear();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) = 0;
|
||||
|
||||
virtual u64 Tell() const = 0;
|
||||
|
||||
|
||||
@@ -31,16 +31,16 @@ public:
|
||||
|
||||
virtual u64 Read(void* dst, u64 count) override;
|
||||
|
||||
virtual u64 Seek(s64 offset, fsm seek_mode = fsm::begin) override
|
||||
virtual u64 Seek(s64 offset, fs::seek_mode whence) override
|
||||
{
|
||||
switch (seek_mode)
|
||||
switch (whence)
|
||||
{
|
||||
case fsm::begin: return m_pos = offset;
|
||||
case fsm::cur: return m_pos += offset;
|
||||
case fsm::end: return m_pos = m_size + offset;
|
||||
case fs::seek_set: return m_pos = offset;
|
||||
case fs::seek_cur: return m_pos += offset;
|
||||
case fs::seek_end: return m_pos = m_size + offset;
|
||||
}
|
||||
|
||||
throw EXCEPTION("Unknown seek_mode (0x%x)", seek_mode);
|
||||
throw EXCEPTION("Unknown seek_mode (0x%x)", whence);
|
||||
}
|
||||
|
||||
virtual u64 Tell() const override
|
||||
|
||||
@@ -787,16 +787,16 @@ u64 vfsHDD::Read(void* dst, u64 size)
|
||||
return m_file.Read(dst, size); // ???
|
||||
}
|
||||
|
||||
u64 vfsHDD::Seek(s64 offset, fsm seek_mode)
|
||||
u64 vfsHDD::Seek(s64 offset, fs::seek_mode whence)
|
||||
{
|
||||
switch (seek_mode)
|
||||
switch (whence)
|
||||
{
|
||||
case fsm::begin: return m_file.Seek(offset);
|
||||
case fsm::cur: return m_file.Seek(Tell() + offset);
|
||||
case fsm::end: return m_file.Seek(m_file.GetSize() + offset);
|
||||
case fs::seek_set: return m_file.Seek(offset);
|
||||
case fs::seek_cur: return m_file.Seek(Tell() + offset);
|
||||
case fs::seek_end: return m_file.Seek(m_file.GetSize() + offset);
|
||||
}
|
||||
|
||||
throw EXCEPTION("Unknown seek_mode(0x%x)", seek_mode);
|
||||
throw EXCEPTION("Unknown whence (0x%x)", whence);
|
||||
}
|
||||
|
||||
u64 vfsHDD::Tell() const
|
||||
@@ -817,4 +817,4 @@ bool vfsHDD::IsOpened() const
|
||||
u64 vfsHDD::GetSize() const
|
||||
{
|
||||
return m_file.GetSize();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -196,7 +196,7 @@ public:
|
||||
|
||||
virtual u64 Read(void* dst, u64 count) override;
|
||||
|
||||
virtual u64 Seek(s64 offset, fsm seek_mode = fsm::begin) override;
|
||||
virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override;
|
||||
|
||||
virtual u64 Tell() const override;
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */
|
||||
#ifndef MAP_ANONYMOUS
|
||||
@@ -239,13 +238,10 @@ namespace vm
|
||||
catch (...)
|
||||
{
|
||||
// capture any exception possibly thrown by predicate
|
||||
pred = [exception = std::current_exception()]
|
||||
pred = [exception = std::current_exception()]() -> bool
|
||||
{
|
||||
// new predicate will throw the captured exception from the original thread
|
||||
std::rethrow_exception(exception);
|
||||
|
||||
// dummy return value, remove when std::rethrow_exception gains [[noreturn]] attribute in MSVC
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ namespace vm
|
||||
// Convert pointer-to-member to a vm address compatible offset
|
||||
template<typename MT, typename T> inline u32 get_offset(MT T::*const member_ptr)
|
||||
{
|
||||
return static_cast<u32>(reinterpret_cast<std::uintptr_t>(&(reinterpret_cast<T*>(0ull)->*member_ptr)));
|
||||
return static_cast<u32>(reinterpret_cast<std::uintptr_t>(&reinterpret_cast<char const volatile&>(reinterpret_cast<T*>(0ull)->*member_ptr)));
|
||||
}
|
||||
|
||||
template<typename T> struct cast_ptr
|
||||
|
||||
+16
-16
@@ -46,7 +46,7 @@ namespace vm
|
||||
// get vm pointer to a struct member with array subscription
|
||||
template<typename MT, typename T2, typename ET = std::remove_extent_t<MT>, typename = if_comparable_t<T, T2>> _ptr_base<ET> ptr(MT T2::*const mptr, u32 index) const
|
||||
{
|
||||
return{ VM_CAST(m_addr) + get_offset(mptr) + sizeof32(ET) * index, vm::addr };
|
||||
return{ VM_CAST(m_addr) + get_offset(mptr) + SIZE_32(ET) * index, vm::addr };
|
||||
}
|
||||
|
||||
// get vm reference to a struct member
|
||||
@@ -58,7 +58,7 @@ namespace vm
|
||||
// get vm reference to a struct member with array subscription
|
||||
template<typename MT, typename T2, typename ET = std::remove_extent_t<MT>, typename = if_comparable_t<T, T2>> _ref_base<ET> ref(MT T2::*const mptr, u32 index) const
|
||||
{
|
||||
return{ VM_CAST(m_addr) + get_offset(mptr) + sizeof32(ET) * index, vm::addr };
|
||||
return{ VM_CAST(m_addr) + get_offset(mptr) + SIZE_32(ET) * index, vm::addr };
|
||||
}
|
||||
|
||||
// get vm reference
|
||||
@@ -98,7 +98,7 @@ namespace vm
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator[] is not available for void pointers");
|
||||
|
||||
return *static_cast<T*>(vm::base(VM_CAST(m_addr) + sizeof32(T) * index));
|
||||
return *static_cast<T*>(vm::base(VM_CAST(m_addr) + SIZE_32(T) * index));
|
||||
}
|
||||
|
||||
// enable only the conversions which are originally possible between pointer types
|
||||
@@ -128,7 +128,7 @@ namespace vm
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: aligned() is not available for void pointers");
|
||||
|
||||
return aligned(alignof32(T));
|
||||
return aligned(ALIGN_32(T));
|
||||
}
|
||||
|
||||
// Test address for arbitrary alignment: (addr & (align - 1)) != 0
|
||||
@@ -143,7 +143,7 @@ namespace vm
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator++ is not available for void pointers");
|
||||
|
||||
const addr_type result = m_addr;
|
||||
m_addr = VM_CAST(m_addr) + sizeof32(T);
|
||||
m_addr = VM_CAST(m_addr) + SIZE_32(T);
|
||||
return{ result, vm::addr };
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace vm
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator++ is not available for void pointers");
|
||||
|
||||
m_addr = VM_CAST(m_addr) + sizeof32(T);
|
||||
m_addr = VM_CAST(m_addr) + SIZE_32(T);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ namespace vm
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator-- is not available for void pointers");
|
||||
|
||||
const addr_type result = m_addr;
|
||||
m_addr = VM_CAST(m_addr) - sizeof32(T);
|
||||
m_addr = VM_CAST(m_addr) - SIZE_32(T);
|
||||
return{ result, vm::addr };
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace vm
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator-- is not available for void pointers");
|
||||
|
||||
m_addr = VM_CAST(m_addr) - sizeof32(T);
|
||||
m_addr = VM_CAST(m_addr) - SIZE_32(T);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace vm
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator+= is not available for void pointers");
|
||||
|
||||
m_addr = VM_CAST(m_addr) + count * sizeof32(T);
|
||||
m_addr = VM_CAST(m_addr) + count * SIZE_32(T);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace vm
|
||||
{
|
||||
static_assert(!std::is_void<T>::value, "vm::_ptr_base<> error: operator-= is not available for void pointers");
|
||||
|
||||
m_addr = VM_CAST(m_addr) - count * sizeof32(T);
|
||||
m_addr = VM_CAST(m_addr) - count * SIZE_32(T);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
@@ -350,13 +350,13 @@ namespace vm
|
||||
// Call wait_op() for specified vm pointer
|
||||
template<typename T, typename AT, typename F, typename... Args> inline auto wait_op(named_thread_t& thread, const _ptr_base<T, AT>& ptr, F pred, Args&&... args) -> decltype(static_cast<void>(pred(args...)))
|
||||
{
|
||||
return wait_op(thread, ptr.addr(), sizeof32(T), std::move(pred), std::forward<Args>(args)...);
|
||||
return wait_op(thread, ptr.addr(), SIZE_32(T), std::move(pred), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Call notify_at() for specified vm pointer
|
||||
template<typename T, typename AT> inline void notify_at(const vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
return notify_at(ptr.addr(), sizeof32(T));
|
||||
return notify_at(ptr.addr(), SIZE_32(T));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,19 +375,19 @@ template<typename T, typename AT> inline std::enable_if_t<std::is_object<T>::val
|
||||
// addition operator for vm::_ptr_base (pointer + integer)
|
||||
template<typename T, typename AT> inline std::enable_if_t<std::is_object<T>::value, vm::_ptr_base<T>> operator +(const vm::_ptr_base<T, AT>& ptr, u32 count)
|
||||
{
|
||||
return{ VM_CAST(ptr.addr()) + count * sizeof32(T), vm::addr };
|
||||
return{ VM_CAST(ptr.addr()) + count * SIZE_32(T), vm::addr };
|
||||
}
|
||||
|
||||
// addition operator for vm::_ptr_base (integer + pointer)
|
||||
template<typename T, typename AT> inline std::enable_if_t<std::is_object<T>::value, vm::_ptr_base<T>> operator +(u32 count, const vm::_ptr_base<T, AT>& ptr)
|
||||
{
|
||||
return{ VM_CAST(ptr.addr()) + count * sizeof32(T), vm::addr };
|
||||
return{ VM_CAST(ptr.addr()) + count * SIZE_32(T), vm::addr };
|
||||
}
|
||||
|
||||
// subtraction operator for vm::_ptr_base (pointer - integer)
|
||||
template<typename T, typename AT> inline std::enable_if_t<std::is_object<T>::value, vm::_ptr_base<T>> operator -(const vm::_ptr_base<T, AT>& ptr, u32 count)
|
||||
{
|
||||
return{ VM_CAST(ptr.addr()) - count * sizeof32(T), vm::addr };
|
||||
return{ VM_CAST(ptr.addr()) - count * SIZE_32(T), vm::addr };
|
||||
}
|
||||
|
||||
// pointer difference operator for vm::_ptr_base
|
||||
@@ -397,7 +397,7 @@ template<typename T1, typename AT1, typename T2, typename AT2> inline std::enabl
|
||||
std::is_same<std::remove_cv_t<T1>, std::remove_cv_t<T2>>::value,
|
||||
s32> operator -(const vm::_ptr_base<T1, AT1>& left, const vm::_ptr_base<T2, AT2>& right)
|
||||
{
|
||||
return static_cast<s32>(VM_CAST(left.addr()) - VM_CAST(right.addr())) / sizeof32(T1);
|
||||
return static_cast<s32>(VM_CAST(left.addr()) - VM_CAST(right.addr())) / SIZE_32(T1);
|
||||
}
|
||||
|
||||
// comparison operator for vm::_ptr_base (pointer1 == pointer2)
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace vm
|
||||
public:
|
||||
// Call the constructor with specified arguments
|
||||
template<typename... Args, typename = std::enable_if_t<std::is_constructible<T, Args...>::value>> _var_base(Args&&... args)
|
||||
: pointer(A::alloc(sizeof32(T), alignof32(T)), vm::addr)
|
||||
: pointer(A::alloc(SIZE_32(T), ALIGN_32(T)), vm::addr)
|
||||
{
|
||||
#include "restore_new.h"
|
||||
new(pointer::get_ptr()) T(std::forward<Args>(args)...);
|
||||
@@ -118,7 +118,7 @@ namespace vm
|
||||
pointer::get_ptr()->~T();
|
||||
|
||||
// Deallocate memory
|
||||
A::dealloc(pointer::addr(), sizeof32(T));
|
||||
A::dealloc(pointer::addr(), SIZE_32(T));
|
||||
}
|
||||
|
||||
// Remove operator []
|
||||
@@ -135,7 +135,7 @@ namespace vm
|
||||
public:
|
||||
// Call the default constructor for each element
|
||||
_var_base(u32 count)
|
||||
: pointer(A::alloc(sizeof32(T) * count, alignof32(T)), vm::addr)
|
||||
: pointer(A::alloc(SIZE_32(T) * count, ALIGN_32(T)), vm::addr)
|
||||
, m_count(count)
|
||||
{
|
||||
#include "restore_new.h"
|
||||
@@ -145,7 +145,7 @@ namespace vm
|
||||
|
||||
// Call the constructor for each element using [it, it + count)
|
||||
template<typename T2> _var_base(u32 count, T2 it)
|
||||
: pointer(A::alloc(sizeof32(T) * count, alignof32(T)), vm::addr)
|
||||
: pointer(A::alloc(SIZE_32(T) * count, ALIGN_32(T)), vm::addr)
|
||||
, m_count(count)
|
||||
{
|
||||
#include "restore_new.h"
|
||||
@@ -161,7 +161,7 @@ namespace vm
|
||||
for (u32 i = m_count - 1; ~i; i--) pointer::operator [](i).~T();
|
||||
|
||||
// Deallocate memory
|
||||
A::dealloc(pointer::addr(), sizeof32(T) * m_count);
|
||||
A::dealloc(pointer::addr(), SIZE_32(T) * m_count);
|
||||
}
|
||||
|
||||
u32 get_count() const
|
||||
@@ -188,7 +188,7 @@ namespace vm
|
||||
public:
|
||||
// Call the default constructor for each element
|
||||
_var_base()
|
||||
: pointer(A::alloc(sizeof32(T) * N, alignof32(T)), vm::addr)
|
||||
: pointer(A::alloc(SIZE_32(T) * N, ALIGN_32(T)), vm::addr)
|
||||
{
|
||||
#include "restore_new.h"
|
||||
new(pointer::get_ptr()) T[N]();
|
||||
@@ -197,7 +197,7 @@ namespace vm
|
||||
|
||||
// Call the constructor for each element using array
|
||||
template<typename T2> _var_base(const T2(&array)[N])
|
||||
: pointer(A::alloc(sizeof32(T) * N, alignof32(T)), vm::addr)
|
||||
: pointer(A::alloc(SIZE_32(T) * N, ALIGN_32(T)), vm::addr)
|
||||
{
|
||||
#include "restore_new.h"
|
||||
for (u32 i = 0; i < N; i++) new(pointer::get_ptr() + i) T(array[i]);
|
||||
@@ -212,7 +212,7 @@ namespace vm
|
||||
for (u32 i = N - 1; ~i; i--) pointer::operator [](i).~T();
|
||||
|
||||
// Deallocate memory
|
||||
A::dealloc(pointer::addr(), sizeof32(T) * N);
|
||||
A::dealloc(pointer::addr(), SIZE_32(T) * N);
|
||||
}
|
||||
|
||||
constexpr u32 get_count() const
|
||||
|
||||
@@ -309,7 +309,7 @@ public:
|
||||
|
||||
m_arb_shader += fmt::format("#%d ", i) + param_type + param_name + param_semantic + param_const + "\n";
|
||||
|
||||
offset += sizeof32(CgBinaryParameter);
|
||||
offset += SIZE_32(CgBinaryParameter);
|
||||
}
|
||||
|
||||
m_arb_shader += "\n";
|
||||
@@ -334,7 +334,9 @@ public:
|
||||
u32 size;
|
||||
u32 ctrl = (vmfprog.outputFromH0 ? 0 : 0x40) | (vmfprog.depthReplace ? 0xe : 0);
|
||||
std::vector<texture_dimension> td;
|
||||
GLFragmentDecompilerThread(m_glsl_shader, param_array, ptr + vmprog.ucode, size, ctrl, td).Task();
|
||||
RSXFragmentProgram prog;
|
||||
prog.size = 0, prog.addr = vm::base(ptr + vmprog.ucode), prog.offset = 0, prog.ctrl = ctrl;
|
||||
GLFragmentDecompilerThread(m_glsl_shader, param_array, prog, size).Task();
|
||||
vm::close();
|
||||
}
|
||||
}
|
||||
@@ -364,7 +366,7 @@ public:
|
||||
|
||||
m_arb_shader += fmt::format("#%d ", i) + param_type + param_name + param_semantic + param_const + "\n";
|
||||
|
||||
offset += sizeof32(CgBinaryParameter);
|
||||
offset += SIZE_32(CgBinaryParameter);
|
||||
}
|
||||
|
||||
m_arb_shader += "\n";
|
||||
@@ -383,7 +385,9 @@ public:
|
||||
}
|
||||
|
||||
TaskVP();
|
||||
GLVertexDecompilerThread(m_data, m_glsl_shader, param_array).Task();
|
||||
RSXVertexProgram prog;
|
||||
prog.data = m_data;
|
||||
GLVertexDecompilerThread(prog, m_glsl_shader, param_array).Task();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ std::string CgBinaryDisasm::GetDSTDisasm(bool isSca)
|
||||
|
||||
default:
|
||||
if (d3.dst > 15)
|
||||
LOG_ERROR(RSX, fmt::format("dst index out of range: %u", d3.dst));
|
||||
LOG_ERROR(RSX, "dst index out of range: %u", d3.dst);
|
||||
|
||||
ret += fmt::format("o[%d]", d3.dst) + GetVecMaskDisasm();
|
||||
break;
|
||||
@@ -94,7 +94,7 @@ std::string CgBinaryDisasm::GetSRCDisasm(const u32 n)
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERROR(RSX, fmt::format("Bad src%u reg type: %d", n, u32{ src[n].reg_type }));
|
||||
LOG_ERROR(RSX, "Bad src%u reg type: %d", n, u32{ src[n].reg_type });
|
||||
Emu.Pause();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5,34 +5,54 @@
|
||||
#define MIN2(x, y) ((x) < (y)) ? (x) : (y)
|
||||
#define MAX2(x, y) ((x) > (y)) ? (x) : (y)
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* Convert CMP vector to RGBA16.
|
||||
* A vector in CMP (compressed) format is stored as X11Y11Z10 and has a W component of 1.
|
||||
* X11 and Y11 channels are int between -1024 and 1023 interpreted as -1.f, 1.f
|
||||
* Z10 is int between -512 and 511 interpreted as -1.f, 1.f
|
||||
*/
|
||||
std::array<u16, 4> decode_cmp_vector(u32 encoded_vector)
|
||||
{
|
||||
u16 Z = encoded_vector >> 22;
|
||||
Z = Z << 6;
|
||||
u16 Y = (encoded_vector >> 11) & 0x7FF;
|
||||
Y = Y << 5;
|
||||
u16 X = encoded_vector & 0x7FF;
|
||||
X = X << 5;
|
||||
return{ X, Y, Z, 1 };
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: these functions shouldn't access rsx::method_registers (global)
|
||||
|
||||
void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_t index, const rsx::data_array_format_info &vertex_array_desc)
|
||||
{
|
||||
assert(vertex_array_desc.size > 0);
|
||||
|
||||
if (vertex_array_desc.frequency > 1)
|
||||
LOG_ERROR(RSX, "%s: frequency is not null (%d, index=%d)", __FUNCTION__, vertex_array_desc.frequency, index);
|
||||
|
||||
u32 offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + index];
|
||||
u32 address = rsx::get_address(offset & 0x7fffffff, offset >> 31);
|
||||
|
||||
u32 type_size = rsx::get_vertex_type_size(vertex_array_desc.type);
|
||||
u32 element_size = type_size * vertex_array_desc.size;
|
||||
Expects(vertex_array_desc.size > 0);
|
||||
|
||||
u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET];
|
||||
u32 offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + index];
|
||||
u32 address = base_offset + rsx::get_address(offset & 0x7fffffff, offset >> 31);
|
||||
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(vertex_array_desc.type, vertex_array_desc.size);
|
||||
|
||||
u32 base_index = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX];
|
||||
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
{
|
||||
auto src = vm::ps3::_ptr<const u8>(address + base_offset + vertex_array_desc.stride * (first + i + base_index));
|
||||
auto src = vm::ps3::_ptr<const u8>(address + vertex_array_desc.stride * (first + i + base_index));
|
||||
u8* dst = (u8*)buffer + i * element_size;
|
||||
|
||||
switch (type_size)
|
||||
switch (vertex_array_desc.type)
|
||||
{
|
||||
case 1:
|
||||
case rsx::vertex_base_type::ub:
|
||||
memcpy(dst, src, vertex_array_desc.size);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case rsx::vertex_base_type::s1:
|
||||
case rsx::vertex_base_type::sf:
|
||||
{
|
||||
auto* c_src = (const be_t<u16>*)src;
|
||||
u16* c_dst = (u16*)dst;
|
||||
@@ -41,10 +61,14 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_
|
||||
{
|
||||
*c_dst++ = *c_src++;
|
||||
}
|
||||
if (vertex_array_desc.size * sizeof(u16) < element_size)
|
||||
*c_dst++ = 0x3c00;
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
case rsx::vertex_base_type::f:
|
||||
case rsx::vertex_base_type::s32k:
|
||||
case rsx::vertex_base_type::ub256:
|
||||
{
|
||||
auto* c_src = (const be_t<u32>*)src;
|
||||
u32* c_dst = (u32*)dst;
|
||||
@@ -55,137 +79,186 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rsx::vertex_base_type::cmp:
|
||||
{
|
||||
auto* c_src = (const be_t<u32>*)src;
|
||||
const auto& decoded_vector = decode_cmp_vector(*c_src);
|
||||
u16* c_dst = (u16*)dst;
|
||||
c_dst[0] = decoded_vector[0];
|
||||
c_dst[1] = decoded_vector[1];
|
||||
c_dst[2] = decoded_vector[2];
|
||||
c_dst[3] = decoded_vector[3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename IndexType>
|
||||
void uploadAsIt(char *dst, u32 address, size_t indexCount, bool is_primitive_restart_enabled, u32 primitive_restart_index, u32 &min_index, u32 &max_index)
|
||||
template<typename T>
|
||||
std::tuple<T, T> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
|
||||
{
|
||||
for (u32 i = 0; i < indexCount; ++i)
|
||||
T min_index = -1;
|
||||
T max_index = 0;
|
||||
|
||||
Expects(dst.size_bytes() >= src.size_bytes());
|
||||
|
||||
size_t dst_idx = 0;
|
||||
for (T index : src)
|
||||
{
|
||||
IndexType index = vm::ps3::_ref<IndexType>(address + i * sizeof(IndexType));
|
||||
if (is_primitive_restart_enabled && index == (IndexType)primitive_restart_index)
|
||||
index = (IndexType)-1;
|
||||
(IndexType&)dst[i * sizeof(IndexType)] = index;
|
||||
if (is_primitive_restart_enabled && index == (IndexType)-1) // Cut
|
||||
continue;
|
||||
max_index = MAX2(max_index, index);
|
||||
min_index = MIN2(min_index, index);
|
||||
if (is_primitive_restart_enabled && index == primitive_restart_index)
|
||||
{
|
||||
index = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
max_index = MAX2(max_index, index);
|
||||
min_index = MIN2(min_index, index);
|
||||
}
|
||||
dst[dst_idx++] = index;
|
||||
}
|
||||
return std::make_tuple(min_index, max_index);
|
||||
}
|
||||
|
||||
// FIXME: expanded primitive type may not support primitive restart correctly
|
||||
|
||||
template<typename IndexType>
|
||||
void expandIndexedTriangleFan(char *dst, u32 address, size_t indexCount, bool is_primitive_restart_enabled, u32 primitive_restart_index, u32 &min_index, u32 &max_index)
|
||||
template<typename T>
|
||||
std::tuple<T, T> expand_indexed_triangle_fan(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
|
||||
{
|
||||
for (unsigned i = 0; i < indexCount - 2; i++)
|
||||
T min_index = -1;
|
||||
T max_index = 0;
|
||||
|
||||
Expects(dst.size() >= 3 * (src.size() - 2));
|
||||
|
||||
const T index0 = src[0];
|
||||
if (!is_primitive_restart_enabled || index0 != -1) // Cut
|
||||
{
|
||||
IndexType index0 = vm::ps3::_ref<IndexType>(address);
|
||||
if (index0 == (IndexType)primitive_restart_index)
|
||||
index0 = (IndexType)-1;
|
||||
IndexType index1 = vm::ps3::_ref<IndexType>(address + (i + 2 - 1) * sizeof(IndexType));
|
||||
if (index1 == (IndexType)primitive_restart_index)
|
||||
index1 = (IndexType)-1;
|
||||
IndexType index2 = vm::ps3::_ref<IndexType>(address + (i + 2) * sizeof(IndexType));
|
||||
if (index2 == (IndexType)primitive_restart_index)
|
||||
index2 = (IndexType)-1;
|
||||
min_index = MIN2(min_index, index0);
|
||||
max_index = MAX2(max_index, index0);
|
||||
}
|
||||
|
||||
(IndexType&)dst[(3 * i) * sizeof(IndexType)] = index0;
|
||||
(IndexType&)dst[(3 * i + 1) * sizeof(IndexType)] = index1;
|
||||
(IndexType&)dst[(3 * i + 2) * sizeof(IndexType)] = index2;
|
||||
|
||||
if (!is_primitive_restart_enabled || index0 != (IndexType)-1) // Cut
|
||||
size_t dst_idx = 0;
|
||||
while (src.size() > 2)
|
||||
{
|
||||
gsl::span<to_be_t<const T>> tri_indexes = src.subspan(0, 2);
|
||||
T index1 = tri_indexes[0];
|
||||
if (is_primitive_restart_enabled && index1 == primitive_restart_index)
|
||||
{
|
||||
min_index = MIN2(min_index, index0);
|
||||
max_index = MAX2(max_index, index0);
|
||||
index1 = -1;
|
||||
}
|
||||
if (!is_primitive_restart_enabled || index1 != (IndexType)-1) // Cut
|
||||
else
|
||||
{
|
||||
min_index = MIN2(min_index, index1);
|
||||
max_index = MAX2(max_index, index1);
|
||||
}
|
||||
if (!is_primitive_restart_enabled || index2 != (IndexType)-1) // Cut
|
||||
T index2 = tri_indexes[1];
|
||||
if (is_primitive_restart_enabled && index2 == primitive_restart_index)
|
||||
{
|
||||
index2 = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_index = MIN2(min_index, index2);
|
||||
max_index = MAX2(max_index, index2);
|
||||
}
|
||||
|
||||
dst[dst_idx++] = index0;
|
||||
dst[dst_idx++] = index1;
|
||||
dst[dst_idx++] = index2;
|
||||
|
||||
src = src.subspan(2);
|
||||
}
|
||||
return std::make_tuple(min_index, max_index);
|
||||
}
|
||||
|
||||
template<typename IndexType>
|
||||
void expandIndexedQuads(char *dst, u32 address, size_t indexCount, bool is_primitive_restart_enabled, u32 primitive_restart_index, u32 &min_index, u32 &max_index)
|
||||
// FIXME: expanded primitive type may not support primitive restart correctly
|
||||
template<typename T>
|
||||
std::tuple<T, T> expand_indexed_quads(gsl::span<to_be_t<const T>> src, gsl::span<T> dst, bool is_primitive_restart_enabled, T primitive_restart_index)
|
||||
{
|
||||
for (unsigned i = 0; i < indexCount / 4; i++)
|
||||
T min_index = -1;
|
||||
T max_index = 0;
|
||||
|
||||
Expects(4 * dst.size_bytes() >= 6 * src.size_bytes());
|
||||
|
||||
size_t dst_idx = 0;
|
||||
while (!src.empty())
|
||||
{
|
||||
IndexType index0 = vm::ps3::_ref<IndexType>(address + 4 * i * sizeof(IndexType));
|
||||
if (is_primitive_restart_enabled && index0 == (IndexType)primitive_restart_index)
|
||||
index0 = (IndexType)-1;
|
||||
IndexType index1 = vm::ps3::_ref<IndexType>(address + (4 * i + 1) * sizeof(IndexType));
|
||||
if (is_primitive_restart_enabled && index1 == (IndexType)primitive_restart_index)
|
||||
index1 = (IndexType)-1;
|
||||
IndexType index2 = vm::ps3::_ref<IndexType>(address + (4 * i + 2) * sizeof(IndexType));
|
||||
if (is_primitive_restart_enabled && index2 == (IndexType)primitive_restart_index)
|
||||
index2 = (IndexType)-1;
|
||||
IndexType index3 = vm::ps3::_ref<IndexType>(address + (4 * i + 3) * sizeof(IndexType));
|
||||
if (is_primitive_restart_enabled &&index3 == (IndexType)primitive_restart_index)
|
||||
index3 = (IndexType)-1;
|
||||
|
||||
// First triangle
|
||||
(IndexType&)dst[(6 * i) * sizeof(IndexType)] = index0;
|
||||
(IndexType&)dst[(6 * i + 1) * sizeof(IndexType)] = index1;
|
||||
(IndexType&)dst[(6 * i + 2) * sizeof(IndexType)] = index2;
|
||||
// Second triangle
|
||||
(IndexType&)dst[(6 * i + 3) * sizeof(IndexType)] = index2;
|
||||
(IndexType&)dst[(6 * i + 4) * sizeof(IndexType)] = index3;
|
||||
(IndexType&)dst[(6 * i + 5) * sizeof(IndexType)] = index0;
|
||||
|
||||
if (!is_primitive_restart_enabled || index0 != (IndexType)-1) // Cut
|
||||
gsl::span<to_be_t<const T>> quad_indexes = src.subspan(0, 4);
|
||||
T index0 = quad_indexes[0];
|
||||
if (is_primitive_restart_enabled && index0 == primitive_restart_index)
|
||||
{
|
||||
index0 = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_index = MIN2(min_index, index0);
|
||||
max_index = MAX2(max_index, index0);
|
||||
}
|
||||
if (!is_primitive_restart_enabled || index1 != (IndexType)-1) // Cut
|
||||
T index1 = quad_indexes[1];
|
||||
if (is_primitive_restart_enabled && index1 == primitive_restart_index)
|
||||
{
|
||||
index1 = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_index = MIN2(min_index, index1);
|
||||
max_index = MAX2(max_index, index1);
|
||||
}
|
||||
if (!is_primitive_restart_enabled || index2 != (IndexType)-1) // Cut
|
||||
T index2 = quad_indexes[2];
|
||||
if (is_primitive_restart_enabled && index2 == primitive_restart_index)
|
||||
{
|
||||
index2 = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_index = MIN2(min_index, index2);
|
||||
max_index = MAX2(max_index, index2);
|
||||
}
|
||||
if (!is_primitive_restart_enabled || index3 != (IndexType)-1) // Cut
|
||||
T index3 = quad_indexes[3];
|
||||
if (is_primitive_restart_enabled &&index3 == primitive_restart_index)
|
||||
{
|
||||
index3 = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_index = MIN2(min_index, index3);
|
||||
max_index = MAX2(max_index, index3);
|
||||
}
|
||||
|
||||
// First triangle
|
||||
dst[dst_idx++] = index0;
|
||||
dst[dst_idx++] = index1;
|
||||
dst[dst_idx++] = index2;
|
||||
// Second triangle
|
||||
dst[dst_idx++] = index2;
|
||||
dst[dst_idx++] = index3;
|
||||
dst[dst_idx++] = index0;
|
||||
|
||||
src = src.subspan(4);
|
||||
}
|
||||
return std::make_tuple(min_index, max_index);
|
||||
}
|
||||
}
|
||||
|
||||
// Only handle quads and triangle fan now
|
||||
bool is_primitive_native(unsigned m_draw_mode)
|
||||
bool is_primitive_native(rsx::primitive_type draw_mode)
|
||||
{
|
||||
switch (m_draw_mode)
|
||||
switch (draw_mode)
|
||||
{
|
||||
default:
|
||||
case CELL_GCM_PRIMITIVE_POINTS:
|
||||
case CELL_GCM_PRIMITIVE_LINES:
|
||||
case CELL_GCM_PRIMITIVE_LINE_LOOP:
|
||||
case CELL_GCM_PRIMITIVE_LINE_STRIP:
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLES:
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP:
|
||||
case CELL_GCM_PRIMITIVE_QUAD_STRIP:
|
||||
case rsx::primitive_type::points:
|
||||
case rsx::primitive_type::lines:
|
||||
case rsx::primitive_type::line_loop:
|
||||
case rsx::primitive_type::line_strip:
|
||||
case rsx::primitive_type::triangles:
|
||||
case rsx::primitive_type::triangle_strip:
|
||||
case rsx::primitive_type::quad_strip:
|
||||
return true;
|
||||
case CELL_GCM_PRIMITIVE_POLYGON:
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_FAN:
|
||||
case CELL_GCM_PRIMITIVE_QUADS:
|
||||
case rsx::primitive_type::polygon:
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
case rsx::primitive_type::quads:
|
||||
return false;
|
||||
}
|
||||
throw new EXCEPTION("Wrong primitive type");
|
||||
}
|
||||
|
||||
/** We assume that polygon is convex in polygon mode (constraints in OpenGL)
|
||||
@@ -193,41 +266,41 @@ bool is_primitive_native(unsigned m_draw_mode)
|
||||
* see http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/polygon-triangulation-r3334
|
||||
*/
|
||||
|
||||
size_t get_index_count(unsigned m_draw_mode, unsigned initial_index_count)
|
||||
size_t get_index_count(rsx::primitive_type draw_mode, unsigned initial_index_count)
|
||||
{
|
||||
// Index count
|
||||
if (is_primitive_native(m_draw_mode))
|
||||
if (is_primitive_native(draw_mode))
|
||||
return initial_index_count;
|
||||
|
||||
switch (m_draw_mode)
|
||||
switch (draw_mode)
|
||||
{
|
||||
case CELL_GCM_PRIMITIVE_POLYGON:
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_FAN:
|
||||
case rsx::primitive_type::polygon:
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
return (initial_index_count - 2) * 3;
|
||||
case CELL_GCM_PRIMITIVE_QUADS:
|
||||
case rsx::primitive_type::quads:
|
||||
return (6 * initial_index_count) / 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_index_type_size(u32 type)
|
||||
size_t get_index_type_size(rsx::index_array_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: return 2;
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: return 4;
|
||||
default: return 0;
|
||||
case rsx::index_array_type::u16: return sizeof(u16);
|
||||
case rsx::index_array_type::u32: return sizeof(u32);
|
||||
}
|
||||
throw new EXCEPTION("Wrong index type");
|
||||
}
|
||||
|
||||
void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, unsigned draw_mode, unsigned first, unsigned count)
|
||||
void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, rsx::primitive_type draw_mode, unsigned first, unsigned count)
|
||||
{
|
||||
unsigned short *typedDst = (unsigned short *)(dst);
|
||||
switch (draw_mode)
|
||||
{
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_FAN:
|
||||
case CELL_GCM_PRIMITIVE_POLYGON:
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
case rsx::primitive_type::polygon:
|
||||
for (unsigned i = 0; i < (count - 2); i++)
|
||||
{
|
||||
typedDst[3 * i] = first;
|
||||
@@ -235,7 +308,7 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst,
|
||||
typedDst[3 * i + 2] = i + 2;
|
||||
}
|
||||
return;
|
||||
case CELL_GCM_PRIMITIVE_QUADS:
|
||||
case rsx::primitive_type::quads:
|
||||
for (unsigned i = 0; i < count / 4; i++)
|
||||
{
|
||||
// First triangle
|
||||
@@ -248,62 +321,118 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst,
|
||||
typedDst[6 * i + 5] = 4 * i + first;
|
||||
}
|
||||
return;
|
||||
case rsx::primitive_type::points:
|
||||
case rsx::primitive_type::lines:
|
||||
case rsx::primitive_type::line_loop:
|
||||
case rsx::primitive_type::line_strip:
|
||||
case rsx::primitive_type::triangles:
|
||||
case rsx::primitive_type::triangle_strip:
|
||||
case rsx::primitive_type::quad_strip:
|
||||
throw new EXCEPTION("Native primitive type doesn't require expansion");
|
||||
}
|
||||
}
|
||||
|
||||
void write_index_array_data_to_buffer(char* dst, unsigned m_draw_mode, unsigned first, unsigned count, unsigned &min_index, unsigned &max_index)
|
||||
// TODO: Unify indexed and non indexed primitive expansion ?
|
||||
|
||||
template<typename T>
|
||||
std::tuple<T, T> write_index_array_data_to_buffer_impl(gsl::span<T, gsl::dynamic_range> dst, rsx::primitive_type draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf);
|
||||
u32 type = rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4;
|
||||
rsx::index_array_type type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
|
||||
u32 type_size = type == CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32 ? sizeof(u32) : sizeof(u16);
|
||||
u32 type_size = gsl::narrow<u32>(get_index_type_size(type));
|
||||
|
||||
|
||||
Expects(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX] == 0);
|
||||
|
||||
u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET];
|
||||
u32 base_index = 0;//rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX];
|
||||
bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE];
|
||||
u32 primitive_restart_index = rsx::method_registers[NV4097_SET_RESTART_INDEX];
|
||||
|
||||
switch (m_draw_mode)
|
||||
// Disjoint first_counts ranges not supported atm
|
||||
for (int i = 0; i < first_count_arguments.size() - 1; i++)
|
||||
{
|
||||
case CELL_GCM_PRIMITIVE_POINTS:
|
||||
case CELL_GCM_PRIMITIVE_LINES:
|
||||
case CELL_GCM_PRIMITIVE_LINE_LOOP:
|
||||
case CELL_GCM_PRIMITIVE_LINE_STRIP:
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLES:
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP:
|
||||
case CELL_GCM_PRIMITIVE_QUAD_STRIP:
|
||||
case CELL_GCM_PRIMITIVE_POLYGON:
|
||||
switch (type)
|
||||
{
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32:
|
||||
uploadAsIt<u32>(dst, address + (first + base_index) * sizeof(u32), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index);
|
||||
return;
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16:
|
||||
uploadAsIt<u16>(dst, address + (first + base_index) * sizeof(u16), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_FAN:
|
||||
switch (type)
|
||||
{
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32:
|
||||
expandIndexedTriangleFan<u32>(dst, address + (first + base_index) * sizeof(u32), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index);
|
||||
return;
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16:
|
||||
expandIndexedTriangleFan<u16>(dst, address + (first + base_index) * sizeof(u16), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index);
|
||||
return;
|
||||
}
|
||||
case CELL_GCM_PRIMITIVE_QUADS:
|
||||
switch (type)
|
||||
{
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32:
|
||||
expandIndexedQuads<u32>(dst, address + (first + base_index) * sizeof(u32), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index);
|
||||
return;
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16:
|
||||
expandIndexedQuads<u16>(dst, address + (first + base_index) * sizeof(u16), count, is_primitive_restart_enabled, primitive_restart_index, min_index, max_index);
|
||||
return;
|
||||
}
|
||||
const std::tuple<u32, u32> &range = first_count_arguments[i];
|
||||
const std::tuple<u32, u32> &next_range = first_count_arguments[i + 1];
|
||||
Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range));
|
||||
}
|
||||
u32 first = std::get<0>(first_count_arguments.front());
|
||||
u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first;
|
||||
auto ptr = vm::ps3::_ptr<const T>(address + first * type_size);
|
||||
|
||||
switch (draw_mode)
|
||||
{
|
||||
case rsx::primitive_type::points:
|
||||
case rsx::primitive_type::lines:
|
||||
case rsx::primitive_type::line_loop:
|
||||
case rsx::primitive_type::line_strip:
|
||||
case rsx::primitive_type::triangles:
|
||||
case rsx::primitive_type::triangle_strip:
|
||||
case rsx::primitive_type::quad_strip:
|
||||
return upload_untouched<T>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
|
||||
case rsx::primitive_type::polygon:
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
return expand_indexed_triangle_fan<T>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
|
||||
case rsx::primitive_type::quads:
|
||||
return expand_indexed_quads<T>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
|
||||
}
|
||||
|
||||
throw new EXCEPTION("Unknow draw mode");
|
||||
}
|
||||
|
||||
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<u32, gsl::dynamic_range> dst, rsx::primitive_type draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
{
|
||||
return write_index_array_data_to_buffer_impl(dst, draw_mode, first_count_arguments);
|
||||
}
|
||||
|
||||
std::tuple<u16, u16> write_index_array_data_to_buffer(gsl::span<u16, gsl::dynamic_range> dst, rsx::primitive_type draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
{
|
||||
return write_index_array_data_to_buffer_impl(dst, draw_mode, first_count_arguments);
|
||||
}
|
||||
|
||||
std::tuple<u32, u32> write_index_array_data_to_buffer_untouched(gsl::span<u32, gsl::dynamic_range> dst, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf);
|
||||
rsx::index_array_type type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
|
||||
u32 type_size = gsl::narrow<u32>(get_index_type_size(type));
|
||||
bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE];
|
||||
u32 primitive_restart_index = rsx::method_registers[NV4097_SET_RESTART_INDEX];
|
||||
|
||||
// Disjoint first_counts ranges not supported atm
|
||||
for (int i = 0; i < first_count_arguments.size() - 1; i++)
|
||||
{
|
||||
const std::tuple<u32, u32> &range = first_count_arguments[i];
|
||||
const std::tuple<u32, u32> &next_range = first_count_arguments[i + 1];
|
||||
Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range));
|
||||
}
|
||||
u32 first = std::get<0>(first_count_arguments.front());
|
||||
u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first;
|
||||
auto ptr = vm::ps3::_ptr<const u32>(address + first * type_size);
|
||||
|
||||
return upload_untouched<u32>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
|
||||
}
|
||||
|
||||
std::tuple<u16, u16> write_index_array_data_to_buffer_untouched(gsl::span<u16, gsl::dynamic_range> dst, const std::vector<std::pair<u32, u32> > &first_count_arguments)
|
||||
{
|
||||
u32 address = rsx::get_address(rsx::method_registers[NV4097_SET_INDEX_ARRAY_ADDRESS], rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] & 0xf);
|
||||
rsx::index_array_type type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
|
||||
u32 type_size = gsl::narrow<u32>(get_index_type_size(type));
|
||||
bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE];
|
||||
u16 primitive_restart_index = rsx::method_registers[NV4097_SET_RESTART_INDEX];
|
||||
|
||||
// Disjoint first_counts ranges not supported atm
|
||||
for (int i = 0; i < first_count_arguments.size() - 1; i++)
|
||||
{
|
||||
const std::tuple<u32, u32> &range = first_count_arguments[i];
|
||||
const std::tuple<u32, u32> &next_range = first_count_arguments[i + 1];
|
||||
Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range));
|
||||
}
|
||||
u32 first = std::get<0>(first_count_arguments.front());
|
||||
u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first;
|
||||
auto ptr = vm::ps3::_ptr<const u16>(address + first * type_size);
|
||||
|
||||
return upload_untouched<u16>({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index);
|
||||
}
|
||||
|
||||
void stream_vector(void *dst, u32 x, u32 y, u32 z, u32 w)
|
||||
|
||||
@@ -3,15 +3,6 @@
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "../RSXThread.h"
|
||||
|
||||
|
||||
struct VertexBufferFormat
|
||||
{
|
||||
std::pair<size_t, size_t> range;
|
||||
std::vector<size_t> attributeId;
|
||||
size_t elementCount;
|
||||
size_t stride;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write count vertex attributes from index array buffer starting at first, using vertex_array_desc
|
||||
*/
|
||||
@@ -20,29 +11,36 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_
|
||||
/*
|
||||
* If primitive mode is not supported and need to be emulated (using an index buffer) returns false.
|
||||
*/
|
||||
bool is_primitive_native(unsigned m_draw_mode);
|
||||
bool is_primitive_native(rsx::primitive_type m_draw_mode);
|
||||
|
||||
/**
|
||||
* Returns a fixed index count for emulated primitive, otherwise returns initial_index_count
|
||||
*/
|
||||
size_t get_index_count(unsigned m_draw_mode, unsigned initial_index_count);
|
||||
size_t get_index_count(rsx::primitive_type m_draw_mode, unsigned initial_index_count);
|
||||
|
||||
/**
|
||||
* Returns index type size in byte
|
||||
*/
|
||||
size_t get_index_type_size(u32 type);
|
||||
size_t get_index_type_size(rsx::index_array_type type);
|
||||
|
||||
/**
|
||||
* Write count indexes starting at first to dst buffer.
|
||||
* Write count indexes using (first, first + count) ranges.
|
||||
* Returns min/max index found during the process.
|
||||
* The function expands index buffer for non native primitive type.
|
||||
*/
|
||||
void write_index_array_data_to_buffer(char* dst, unsigned m_draw_mode, unsigned first, unsigned count, unsigned &min_index, unsigned &max_index);
|
||||
std::tuple<u32, u32> write_index_array_data_to_buffer(gsl::span<u32, gsl::dynamic_range> dst, rsx::primitive_type draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments);
|
||||
std::tuple<u16, u16> write_index_array_data_to_buffer(gsl::span<u16, gsl::dynamic_range> dst, rsx::primitive_type draw_mode, const std::vector<std::pair<u32, u32> > &first_count_arguments);
|
||||
|
||||
/**
|
||||
* Doesn't expand index
|
||||
*/
|
||||
std::tuple<u32, u32> write_index_array_data_to_buffer_untouched(gsl::span<u32, gsl::dynamic_range> dst, const std::vector<std::pair<u32, u32> > &first_count_arguments);
|
||||
std::tuple<u16, u16> write_index_array_data_to_buffer_untouched(gsl::span<u16, gsl::dynamic_range> dst, const std::vector<std::pair<u32, u32> > &first_count_arguments);
|
||||
|
||||
/**
|
||||
* Write index data needed to emulate non indexed non native primitive mode.
|
||||
*/
|
||||
void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, unsigned m_draw_mode, unsigned first, unsigned count);
|
||||
void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, rsx::primitive_type draw_mode, unsigned first, unsigned count);
|
||||
|
||||
/**
|
||||
* Stream a 128 bits vector to dst.
|
||||
|
||||
@@ -4,13 +4,12 @@
|
||||
|
||||
#include "FragmentProgramDecompiler.h"
|
||||
|
||||
FragmentProgramDecompiler::FragmentProgramDecompiler(u32 addr, u32& size, u32 ctrl, const std::vector<texture_dimension> &texture_dimensions) :
|
||||
m_addr(addr),
|
||||
FragmentProgramDecompiler::FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size) :
|
||||
m_prog(prog),
|
||||
m_size(size),
|
||||
m_const_index(0),
|
||||
m_location(0),
|
||||
m_ctrl(ctrl),
|
||||
m_texture_dimensions(texture_dimensions)
|
||||
m_ctrl(prog.ctrl)
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
@@ -114,7 +113,7 @@ std::string FragmentProgramDecompiler::AddConst()
|
||||
return name;
|
||||
}
|
||||
|
||||
auto data = vm::ps3::ptr<u32>::make(m_addr + m_size + 4 * sizeof32(u32));
|
||||
auto data = (be_t<u32>*) ((char*)m_prog.addr + m_size + 4 * SIZE_32(u32));
|
||||
|
||||
m_offset = 2 * 4 * sizeof(u32);
|
||||
u32 x = GetData(data[0]);
|
||||
@@ -128,7 +127,23 @@ std::string FragmentProgramDecompiler::AddConst()
|
||||
|
||||
std::string FragmentProgramDecompiler::AddTex()
|
||||
{
|
||||
return m_parr.AddParam(PF_PARAM_UNIFORM, (m_texture_dimensions[dst.tex_num] == texture_dimension::texture_dimension_cubemap) ? "samplerCube" : "sampler2D", std::string("tex") + std::to_string(dst.tex_num));
|
||||
std::string sampler;
|
||||
switch (m_prog.get_texture_dimension(dst.tex_num))
|
||||
{
|
||||
case texture_dimension::texture_dimension_1d:
|
||||
sampler = "sampler1D";
|
||||
break;
|
||||
case texture_dimension::texture_dimension_cubemap:
|
||||
sampler = "samplerCube";
|
||||
break;
|
||||
case texture_dimension::texture_dimension_2d:
|
||||
sampler = "sampler2D";
|
||||
break;
|
||||
case texture_dimension::texture_dimension_3d:
|
||||
sampler = "sampler3D";
|
||||
break;
|
||||
}
|
||||
return m_parr.AddParam(PF_PARAM_UNIFORM, sampler, std::string("tex") + std::to_string(dst.tex_num));
|
||||
}
|
||||
|
||||
std::string FragmentProgramDecompiler::Format(const std::string& code)
|
||||
@@ -259,7 +274,7 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
{
|
||||
static const std::string reg_table[] =
|
||||
{
|
||||
"gl_Position",
|
||||
"gl_FragCoord",
|
||||
"diff_color", "spec_color",
|
||||
"fogc",
|
||||
"tc0", "tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7", "tc8", "tc9",
|
||||
@@ -340,8 +355,10 @@ bool FragmentProgramDecompiler::handle_sct(u32 opcode)
|
||||
switch (opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); return true;
|
||||
case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1).xxxx)"); return true;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1.xxxx)"); return true;
|
||||
// Note: DIVSQ is not IEEE compliant. divsq(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix).
|
||||
// sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven.
|
||||
case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, $1)"); return true;
|
||||
case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2)); return true;
|
||||
case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3)); return true;
|
||||
case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4)); return true;
|
||||
@@ -351,8 +368,11 @@ bool FragmentProgramDecompiler::handle_sct(u32 opcode)
|
||||
case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); return true;
|
||||
case RSX_FP_OPCODE_MOV: SetDst("$0"); return true;
|
||||
case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); return true;
|
||||
case RSX_FP_OPCODE_RCP: SetDst("1.0 / $0"); return true;
|
||||
case RSX_FP_OPCODE_RSQ: SetDst("1.f / sqrt($0)"); return true;
|
||||
// Note: It's higly likely that RCP is not IEEE compliant but a game that uses rcp(0) has to be found
|
||||
case RSX_FP_OPCODE_RCP: SetDst("rcp_legacy($0)"); return true;
|
||||
// Note: RSQ is not IEEE compliant. rsq(0) is some big number (Silent Hill 3 HD)
|
||||
// It is not know what happens if 0 is negative.
|
||||
case RSX_FP_OPCODE_RSQ: SetDst("rsq_legacy($0)"); return true;
|
||||
case RSX_FP_OPCODE_SEQ: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SEQ, "$0", "$1") + ")"); return true;
|
||||
case RSX_FP_OPCODE_SFL: SetDst(getFunction(FUNCTION::FUNCTION_SFL)); return true;
|
||||
case RSX_FP_OPCODE_SGE: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SGE, "$0", "$1") + ")"); return true;
|
||||
@@ -371,8 +391,10 @@ bool FragmentProgramDecompiler::handle_scb(u32 opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true;
|
||||
case RSX_FP_OPCODE_COS: SetDst("cos($0.xxxx)"); return true;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); return true;
|
||||
case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1).xxxx)"); return true;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1.xxxx)"); return true;
|
||||
// Note: DIVSQ is not IEEE compliant. sqrt(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix).
|
||||
// sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven.
|
||||
case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, sqrt($1).xxxx)"); return true;
|
||||
case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2)); return true;
|
||||
case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3)); return true;
|
||||
case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4)); return true;
|
||||
@@ -382,7 +404,7 @@ bool FragmentProgramDecompiler::handle_scb(u32 opcode)
|
||||
case RSX_FP_OPCODE_EX2: SetDst("exp2($0.xxxx)"); return true;
|
||||
case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); return true;
|
||||
case RSX_FP_OPCODE_FRC: SetDst(getFunction(FUNCTION::FUNCTION_FRACT)); return true;
|
||||
case RSX_FP_OPCODE_LIT: SetDst(getFloatTypeName(4) + "(1.0, $0.x, ($0.x > 0.0 ? exp($0.w * log2($0.y)) : 0.0), 1.0)"); return true;
|
||||
case RSX_FP_OPCODE_LIT: SetDst("lit_legacy($0)"); return true;
|
||||
case RSX_FP_OPCODE_LIF: SetDst(getFloatTypeName(4) + "(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); return true;
|
||||
case RSX_FP_OPCODE_LRP: LOG_ERROR(RSX, "Unimplemented SCB instruction: LRP"); return true; // TODO: Is this in the right category?
|
||||
case RSX_FP_OPCODE_LG2: SetDst("log2($0.xxxx)"); return true;
|
||||
@@ -418,42 +440,60 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
|
||||
case RSX_FP_OPCODE_NRM: SetDst("normalize($0)"); return true;
|
||||
case RSX_FP_OPCODE_BEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: BEM"); return true;
|
||||
case RSX_FP_OPCODE_TEX:
|
||||
if (dst.tex_num >= m_texture_dimensions.size())
|
||||
switch (m_prog.get_texture_dimension(dst.tex_num))
|
||||
{
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE));
|
||||
case texture_dimension::texture_dimension_1d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D));
|
||||
return true;
|
||||
}
|
||||
switch (m_texture_dimensions[dst.tex_num])
|
||||
{
|
||||
case texture_dimension::texture_dimension_2d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE));
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_cubemap:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE));
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_3d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case RSX_FP_OPCODE_TEXBEM: SetDst("texture($t, $0.xy, $1.x)"); return true;
|
||||
case RSX_FP_OPCODE_TXP:
|
||||
if (dst.tex_num >= m_texture_dimensions.size())
|
||||
switch (m_prog.get_texture_dimension(dst.tex_num))
|
||||
{
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ));
|
||||
case texture_dimension::texture_dimension_1d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ));
|
||||
return true;
|
||||
}
|
||||
switch (m_texture_dimensions[dst.tex_num])
|
||||
{
|
||||
case texture_dimension::texture_dimension_2d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ));
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_cubemap:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ));
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_3d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case RSX_FP_OPCODE_TXPBEM: SetDst("textureProj($t, $0.xyz, $1.x)"); return true;
|
||||
case RSX_FP_OPCODE_TXD: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXD"); return true;
|
||||
case RSX_FP_OPCODE_TXB: SetDst("texture($t, $0.xy, $1.x)"); return true;
|
||||
case RSX_FP_OPCODE_TXL: SetDst("textureLod($t, $0.xy, $1.x)"); return true;
|
||||
case RSX_FP_OPCODE_TXL:
|
||||
switch (m_prog.get_texture_dimension(dst.tex_num))
|
||||
{
|
||||
case texture_dimension::texture_dimension_1d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_2d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_cubemap:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD));
|
||||
return true;
|
||||
case texture_dimension::texture_dimension_3d:
|
||||
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case RSX_FP_OPCODE_UP2: SetDst("unpackSnorm2x16($0)"); return true; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478))
|
||||
case RSX_FP_OPCODE_UP4: SetDst("unpackSnorm4x8($0)"); return true; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478))
|
||||
case RSX_FP_OPCODE_UP16: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UP16"); return true;
|
||||
@@ -465,7 +505,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
|
||||
|
||||
std::string FragmentProgramDecompiler::Decompile()
|
||||
{
|
||||
auto data = vm::ps3::ptr<u32>::make(m_addr);
|
||||
auto data = (be_t<u32>*) m_prog.addr;
|
||||
m_size = 0;
|
||||
m_location = 0;
|
||||
m_loop_count = 0;
|
||||
|
||||
@@ -25,9 +25,7 @@ class FragmentProgramDecompiler
|
||||
SRC2 src2;
|
||||
|
||||
std::string main;
|
||||
u32 m_addr;
|
||||
u32& m_size;
|
||||
const std::vector<texture_dimension> m_texture_dimensions;
|
||||
u32 m_const_index;
|
||||
u32 m_offset;
|
||||
u32 m_location;
|
||||
@@ -76,6 +74,7 @@ class FragmentProgramDecompiler
|
||||
*/
|
||||
bool handle_tex_srb(u32 opcode);
|
||||
protected:
|
||||
const RSXFragmentProgram &m_prog;
|
||||
u32 m_ctrl;
|
||||
/** returns the type name of float vectors.
|
||||
*/
|
||||
@@ -113,6 +112,8 @@ protected:
|
||||
virtual void insertMainEnd(std::stringstream &OS) = 0;
|
||||
public:
|
||||
ParamArray m_parr;
|
||||
FragmentProgramDecompiler(u32 addr, u32& size, u32 ctrl, const std::vector<texture_dimension> &texture_dimensions);
|
||||
FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size);
|
||||
FragmentProgramDecompiler(const FragmentProgramDecompiler&) = delete;
|
||||
FragmentProgramDecompiler(FragmentProgramDecompiler&&) = delete;
|
||||
std::string Decompile();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
#include "stdafx.h"
|
||||
#include "ProgramStateCache.h"
|
||||
|
||||
using namespace program_hash_util;
|
||||
|
||||
size_t vertex_program_hash::operator()(const RSXVertexProgram &program) const
|
||||
{
|
||||
// 64-bit Fowler/Noll/Vo FNV-1a hash code
|
||||
size_t hash = 0xCBF29CE484222325ULL;
|
||||
const qword *instbuffer = (const qword*)program.data.data();
|
||||
size_t instIndex = 0;
|
||||
bool end = false;
|
||||
for (unsigned i = 0; i < program.data.size() / 4; i++)
|
||||
{
|
||||
const qword inst = instbuffer[instIndex];
|
||||
hash ^= inst.dword[0];
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
hash ^= inst.dword[1];
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
instIndex++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool vertex_program_compare::operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const
|
||||
{
|
||||
if (binary1.output_mask != binary2.output_mask)
|
||||
return false;
|
||||
if (binary1.rsx_vertex_inputs != binary2.rsx_vertex_inputs)
|
||||
return false;
|
||||
if (binary1.data.size() != binary2.data.size()) return false;
|
||||
const qword *instBuffer1 = (const qword*)binary1.data.data();
|
||||
const qword *instBuffer2 = (const qword*)binary2.data.data();
|
||||
size_t instIndex = 0;
|
||||
for (unsigned i = 0; i < binary1.data.size() / 4; i++)
|
||||
{
|
||||
const qword& inst1 = instBuffer1[instIndex];
|
||||
const qword& inst2 = instBuffer2[instIndex];
|
||||
if (inst1.dword[0] != inst2.dword[0] || inst1.dword[1] != inst2.dword[1])
|
||||
return false;
|
||||
instIndex++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool fragment_program_utils::is_constant(u32 sourceOperand)
|
||||
{
|
||||
return ((sourceOperand >> 8) & 0x3) == 2;
|
||||
}
|
||||
|
||||
size_t fragment_program_utils::get_fragment_program_ucode_size(void *ptr)
|
||||
{
|
||||
const qword *instBuffer = (const qword*)ptr;
|
||||
size_t instIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
const qword& inst = instBuffer[instIndex];
|
||||
bool isSRC0Constant = is_constant(inst.word[1]);
|
||||
bool isSRC1Constant = is_constant(inst.word[2]);
|
||||
bool isSRC2Constant = is_constant(inst.word[3]);
|
||||
bool end = (inst.word[0] >> 8) & 0x1;
|
||||
|
||||
if (isSRC0Constant || isSRC1Constant || isSRC2Constant)
|
||||
{
|
||||
instIndex += 2;
|
||||
if (end)
|
||||
return instIndex * 4 * 4;
|
||||
continue;
|
||||
}
|
||||
instIndex++;
|
||||
if (end)
|
||||
return (instIndex)* 4 * 4;
|
||||
}
|
||||
}
|
||||
|
||||
size_t fragment_program_hash::operator()(const RSXFragmentProgram& program) const
|
||||
{
|
||||
// 64-bit Fowler/Noll/Vo FNV-1a hash code
|
||||
size_t hash = 0xCBF29CE484222325ULL;
|
||||
const qword *instbuffer = (const qword*)program.addr;
|
||||
size_t instIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
const qword& inst = instbuffer[instIndex];
|
||||
hash ^= inst.dword[0];
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
hash ^= inst.dword[1];
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
instIndex++;
|
||||
// Skip constants
|
||||
if (fragment_program_utils::is_constant(inst.word[1]) ||
|
||||
fragment_program_utils::is_constant(inst.word[2]) ||
|
||||
fragment_program_utils::is_constant(inst.word[3]))
|
||||
instIndex++;
|
||||
|
||||
bool end = (inst.word[0] >> 8) & 0x1;
|
||||
if (end)
|
||||
return hash;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool fragment_program_compare::operator()(const RSXFragmentProgram& binary1, const RSXFragmentProgram& binary2) const
|
||||
{
|
||||
if (binary1.texture_dimensions != binary2.texture_dimensions || binary1.unnormalized_coords != binary2.unnormalized_coords ||
|
||||
binary1.height != binary2.height || binary1.origin_mode != binary2.origin_mode || binary1.pixel_center_mode != binary2.pixel_center_mode ||
|
||||
binary1.back_color_diffuse_output != binary2.back_color_diffuse_output || binary1.back_color_specular_output != binary2.back_color_specular_output ||
|
||||
binary1.front_back_color_enabled != binary2.front_back_color_enabled || binary1.alpha_func != binary2.alpha_func)
|
||||
return false;
|
||||
const qword *instBuffer1 = (const qword*)binary1.addr;
|
||||
const qword *instBuffer2 = (const qword*)binary2.addr;
|
||||
size_t instIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
const qword& inst1 = instBuffer1[instIndex];
|
||||
const qword& inst2 = instBuffer2[instIndex];
|
||||
|
||||
if (inst1.dword[0] != inst2.dword[0] || inst1.dword[1] != inst2.dword[1])
|
||||
return false;
|
||||
instIndex++;
|
||||
// Skip constants
|
||||
if (fragment_program_utils::is_constant(inst1.word[1]) ||
|
||||
fragment_program_utils::is_constant(inst1.word[2]) ||
|
||||
fragment_program_utils::is_constant(inst1.word[3]))
|
||||
instIndex++;
|
||||
|
||||
bool end = ((inst1.word[0] >> 8) & 0x1) && ((inst2.word[0] >> 8) & 0x1);
|
||||
if (end)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Emu/RSX/RSXFragmentProgram.h"
|
||||
#include "Emu/RSX/RSXVertexProgram.h"
|
||||
#include "Emu/Memory/vm.h"
|
||||
|
||||
|
||||
enum class SHADER_TYPE
|
||||
@@ -10,7 +11,7 @@ enum class SHADER_TYPE
|
||||
SHADER_TYPE_FRAGMENT
|
||||
};
|
||||
|
||||
namespace ProgramHashUtil
|
||||
namespace program_hash_util
|
||||
{
|
||||
// Based on
|
||||
// https://github.com/AlexAltea/nucleus/blob/master/nucleus/gpu/rsx_pgraph.cpp
|
||||
@@ -20,142 +21,34 @@ namespace ProgramHashUtil
|
||||
u32 word[4];
|
||||
};
|
||||
|
||||
struct HashVertexProgram
|
||||
struct vertex_program_hash
|
||||
{
|
||||
size_t operator()(const std::vector<u32> &program) const
|
||||
{
|
||||
// 64-bit Fowler/Noll/Vo FNV-1a hash code
|
||||
size_t hash = 0xCBF29CE484222325ULL;
|
||||
const qword *instbuffer = (const qword*)program.data();
|
||||
size_t instIndex = 0;
|
||||
bool end = false;
|
||||
for (unsigned i = 0; i < program.size() / 4; i++)
|
||||
{
|
||||
const qword inst = instbuffer[instIndex];
|
||||
hash ^= inst.dword[0];
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
hash ^= inst.dword[1];
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
instIndex++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
size_t operator()(const RSXVertexProgram &program) const;
|
||||
};
|
||||
|
||||
|
||||
struct VertexProgramCompare
|
||||
struct vertex_program_compare
|
||||
{
|
||||
bool operator()(const std::vector<u32> &binary1, const std::vector<u32> &binary2) const
|
||||
{
|
||||
if (binary1.size() != binary2.size()) return false;
|
||||
const qword *instBuffer1 = (const qword*)binary1.data();
|
||||
const qword *instBuffer2 = (const qword*)binary2.data();
|
||||
size_t instIndex = 0;
|
||||
for (unsigned i = 0; i < binary1.size() / 4; i++)
|
||||
{
|
||||
const qword& inst1 = instBuffer1[instIndex];
|
||||
const qword& inst2 = instBuffer2[instIndex];
|
||||
if (inst1.dword[0] != inst2.dword[0] || inst1.dword[1] != inst2.dword[1])
|
||||
return false;
|
||||
instIndex++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const;
|
||||
};
|
||||
|
||||
struct FragmentProgramUtil
|
||||
struct fragment_program_utils
|
||||
{
|
||||
/**
|
||||
* returns true if the given source Operand is a constant
|
||||
*/
|
||||
static bool isConstant(u32 sourceOperand)
|
||||
{
|
||||
return ((sourceOperand >> 8) & 0x3) == 2;
|
||||
}
|
||||
static bool is_constant(u32 sourceOperand);
|
||||
|
||||
static
|
||||
size_t getFPBinarySize(void *ptr)
|
||||
{
|
||||
const qword *instBuffer = (const qword*)ptr;
|
||||
size_t instIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
const qword& inst = instBuffer[instIndex];
|
||||
bool isSRC0Constant = isConstant(inst.word[1]);
|
||||
bool isSRC1Constant = isConstant(inst.word[2]);
|
||||
bool isSRC2Constant = isConstant(inst.word[3]);
|
||||
bool end = (inst.word[0] >> 8) & 0x1;
|
||||
|
||||
if (isSRC0Constant || isSRC1Constant || isSRC2Constant)
|
||||
{
|
||||
instIndex += 2;
|
||||
if (end)
|
||||
return instIndex * 4 * 4;
|
||||
continue;
|
||||
}
|
||||
instIndex++;
|
||||
if (end)
|
||||
return (instIndex)* 4 * 4;
|
||||
}
|
||||
}
|
||||
static size_t get_fragment_program_ucode_size(void *ptr);
|
||||
};
|
||||
|
||||
struct HashFragmentProgram
|
||||
struct fragment_program_hash
|
||||
{
|
||||
size_t operator()(const void *program) const
|
||||
{
|
||||
// 64-bit Fowler/Noll/Vo FNV-1a hash code
|
||||
size_t hash = 0xCBF29CE484222325ULL;
|
||||
const qword *instbuffer = (const qword*)program;
|
||||
size_t instIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
const qword& inst = instbuffer[instIndex];
|
||||
hash ^= inst.dword[0];
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
hash ^= inst.dword[1];
|
||||
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40);
|
||||
instIndex++;
|
||||
// Skip constants
|
||||
if (FragmentProgramUtil::isConstant(inst.word[1]) ||
|
||||
FragmentProgramUtil::isConstant(inst.word[2]) ||
|
||||
FragmentProgramUtil::isConstant(inst.word[3]))
|
||||
instIndex++;
|
||||
|
||||
bool end = (inst.word[0] >> 8) & 0x1;
|
||||
if (end)
|
||||
return hash;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
size_t operator()(const RSXFragmentProgram &program) const;
|
||||
};
|
||||
|
||||
struct FragmentProgramCompare
|
||||
struct fragment_program_compare
|
||||
{
|
||||
bool operator()(const void *binary1, const void *binary2) const
|
||||
{
|
||||
const qword *instBuffer1 = (const qword*)binary1;
|
||||
const qword *instBuffer2 = (const qword*)binary2;
|
||||
size_t instIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
const qword& inst1 = instBuffer1[instIndex];
|
||||
const qword& inst2 = instBuffer2[instIndex];
|
||||
|
||||
if (inst1.dword[0] != inst2.dword[0] || inst1.dword[1] != inst2.dword[1])
|
||||
return false;
|
||||
instIndex++;
|
||||
// Skip constants
|
||||
if (FragmentProgramUtil::isConstant(inst1.word[1]) ||
|
||||
FragmentProgramUtil::isConstant(inst1.word[2]) ||
|
||||
FragmentProgramUtil::isConstant(inst1.word[3]))
|
||||
instIndex++;
|
||||
|
||||
bool end = ((inst1.word[0] >> 8) & 0x1) && ((inst2.word[0] >> 8) & 0x1);
|
||||
if (end)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool operator()(const RSXFragmentProgram &binary1, const RSXFragmentProgram &binary2) const;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -170,193 +63,183 @@ namespace ProgramHashUtil
|
||||
* - a typedef PipelineProperties to a type that encapsulate various state info relevant to program compilation (alpha test, primitive type,...)
|
||||
* - a typedef ExtraData type that will be passed to the buildProgram function.
|
||||
* It should also contains the following function member :
|
||||
* - static void RecompileFragmentProgram(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID);
|
||||
* - static void RecompileVertexProgram(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID);
|
||||
* - static PipelineData *BuildProgram(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData);
|
||||
* - void DeleteProgram(PipelineData *ptr);
|
||||
* - static void recompile_fragment_program(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID);
|
||||
* - static void recompile_vertex_program(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID);
|
||||
* - static PipelineData build_program(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData);
|
||||
*/
|
||||
template<typename BackendTraits>
|
||||
class ProgramStateCache
|
||||
template<typename backend_traits>
|
||||
class program_state_cache
|
||||
{
|
||||
private:
|
||||
typedef std::unordered_map<std::vector<u32>, typename BackendTraits::VertexProgramData, ProgramHashUtil::HashVertexProgram, ProgramHashUtil::VertexProgramCompare> binary2VS;
|
||||
typedef std::unordered_map<void *, typename BackendTraits::FragmentProgramData, ProgramHashUtil::HashFragmentProgram, ProgramHashUtil::FragmentProgramCompare> binary2FS;
|
||||
binary2VS m_cacheVS;
|
||||
binary2FS m_cacheFS;
|
||||
using pipeline_storage_type = typename backend_traits::pipeline_storage_type;
|
||||
using pipeline_properties = typename backend_traits::pipeline_properties;
|
||||
using vertex_program_type = typename backend_traits::vertex_program_type;
|
||||
using fragment_program_type = typename backend_traits::fragment_program_type;
|
||||
|
||||
size_t m_currentShaderId;
|
||||
std::vector<size_t> dummyFragmentConstantCache;
|
||||
using binary_to_vertex_program = std::unordered_map<RSXVertexProgram, vertex_program_type, program_hash_util::vertex_program_hash, program_hash_util::vertex_program_compare> ;
|
||||
using binary_to_fragment_program = std::unordered_map<RSXFragmentProgram, fragment_program_type, program_hash_util::fragment_program_hash, program_hash_util::fragment_program_compare>;
|
||||
|
||||
struct PSOKey
|
||||
|
||||
struct pipeline_key
|
||||
{
|
||||
u32 vpIdx;
|
||||
u32 fpIdx;
|
||||
typename BackendTraits::PipelineProperties properties;
|
||||
u32 vertex_program_id;
|
||||
u32 fragment_program_id;
|
||||
pipeline_properties properties;
|
||||
};
|
||||
|
||||
struct PSOKeyHash
|
||||
struct pipeline_key_hash
|
||||
{
|
||||
size_t operator()(const PSOKey &key) const
|
||||
size_t operator()(const pipeline_key &key) const
|
||||
{
|
||||
size_t hashValue = 0;
|
||||
hashValue ^= std::hash<unsigned>()(key.vpIdx);
|
||||
hashValue ^= std::hash<unsigned>()(key.fpIdx);
|
||||
hashValue ^= std::hash<typename BackendTraits::PipelineProperties>()(key.properties);
|
||||
hashValue ^= std::hash<unsigned>()(key.vertex_program_id);
|
||||
hashValue ^= std::hash<unsigned>()(key.fragment_program_id);
|
||||
hashValue ^= std::hash<pipeline_properties>()(key.properties);
|
||||
return hashValue;
|
||||
}
|
||||
};
|
||||
|
||||
struct PSOKeyCompare
|
||||
struct pipeline_key_compare
|
||||
{
|
||||
size_t operator()(const PSOKey &key1, const PSOKey &key2) const
|
||||
bool operator()(const pipeline_key &key1, const pipeline_key &key2) const
|
||||
{
|
||||
return (key1.vpIdx == key2.vpIdx) && (key1.fpIdx == key2.fpIdx) && (key1.properties == key2.properties);
|
||||
return (key1.vertex_program_id == key2.vertex_program_id) && (key1.fragment_program_id == key2.fragment_program_id) && (key1.properties == key2.properties);
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<PSOKey, typename BackendTraits::PipelineData*, PSOKeyHash, PSOKeyCompare> m_cachePSO;
|
||||
private:
|
||||
size_t m_next_id = 0;
|
||||
binary_to_vertex_program m_vertex_shader_cache;
|
||||
binary_to_fragment_program m_fragment_shader_cache;
|
||||
std::unordered_map <pipeline_key, pipeline_storage_type, pipeline_key_hash, pipeline_key_compare> m_storage;
|
||||
|
||||
typename BackendTraits::FragmentProgramData& SearchFp(RSXFragmentProgram* rsx_fp, bool& found)
|
||||
/// bool here to inform that the program was preexisting.
|
||||
std::tuple<const vertex_program_type&, bool> search_vertex_program(const RSXVertexProgram& rsx_vp)
|
||||
{
|
||||
typename binary2FS::iterator It = m_cacheFS.find(vm::base(rsx_fp->addr));
|
||||
if (It != m_cacheFS.end())
|
||||
const auto& I = m_vertex_shader_cache.find(rsx_vp);
|
||||
if (I != m_vertex_shader_cache.end())
|
||||
{
|
||||
found = true;
|
||||
return It->second;
|
||||
return std::forward_as_tuple(I->second, true);
|
||||
}
|
||||
found = false;
|
||||
LOG_WARNING(RSX, "FP not found in buffer!");
|
||||
size_t actualFPSize = ProgramHashUtil::FragmentProgramUtil::getFPBinarySize(vm::base(rsx_fp->addr));
|
||||
void *fpShadowCopy = malloc(actualFPSize);
|
||||
std::memcpy(fpShadowCopy, vm::base(rsx_fp->addr), actualFPSize);
|
||||
typename BackendTraits::FragmentProgramData &newShader = m_cacheFS[fpShadowCopy];
|
||||
BackendTraits::RecompileFragmentProgram(rsx_fp, newShader, m_currentShaderId++);
|
||||
LOG_NOTICE(RSX, "VP not found in buffer!");
|
||||
vertex_program_type& new_shader = m_vertex_shader_cache[rsx_vp];
|
||||
backend_traits::recompile_vertex_program(rsx_vp, new_shader, m_next_id++);
|
||||
|
||||
return newShader;
|
||||
return std::forward_as_tuple(new_shader, false);
|
||||
}
|
||||
|
||||
typename BackendTraits::VertexProgramData& SearchVp(RSXVertexProgram* rsx_vp, bool &found)
|
||||
/// bool here to inform that the program was preexisting.
|
||||
std::tuple<const fragment_program_type&, bool> search_fragment_program(const RSXFragmentProgram& rsx_fp)
|
||||
{
|
||||
typename binary2VS::iterator It = m_cacheVS.find(rsx_vp->data);
|
||||
if (It != m_cacheVS.end())
|
||||
const auto& I = m_fragment_shader_cache.find(rsx_fp);
|
||||
if (I != m_fragment_shader_cache.end())
|
||||
{
|
||||
found = true;
|
||||
return It->second;
|
||||
return std::forward_as_tuple(I->second, true);
|
||||
}
|
||||
found = false;
|
||||
LOG_WARNING(RSX, "VP not found in buffer!");
|
||||
typename BackendTraits::VertexProgramData& newShader = m_cacheVS[rsx_vp->data];
|
||||
BackendTraits::RecompileVertexProgram(rsx_vp, newShader, m_currentShaderId++);
|
||||
LOG_NOTICE(RSX, "FP not found in buffer!");
|
||||
size_t fragment_program_size = program_hash_util::fragment_program_utils::get_fragment_program_ucode_size(rsx_fp.addr);
|
||||
gsl::not_null<void*> fragment_program_ucode_copy = malloc(fragment_program_size);
|
||||
std::memcpy(fragment_program_ucode_copy, rsx_fp.addr, fragment_program_size);
|
||||
RSXFragmentProgram new_fp_key = rsx_fp;
|
||||
new_fp_key.addr = fragment_program_ucode_copy;
|
||||
fragment_program_type &new_shader = m_fragment_shader_cache[new_fp_key];
|
||||
backend_traits::recompile_fragment_program(rsx_fp, new_shader, m_next_id++);
|
||||
|
||||
return newShader;
|
||||
}
|
||||
|
||||
typename BackendTraits::PipelineData *GetProg(const PSOKey &psoKey) const
|
||||
{
|
||||
typename std::unordered_map<PSOKey, typename BackendTraits::PipelineData *, PSOKeyHash, PSOKeyCompare>::const_iterator It = m_cachePSO.find(psoKey);
|
||||
if (It == m_cachePSO.end())
|
||||
return nullptr;
|
||||
return It->second;
|
||||
}
|
||||
|
||||
void Add(typename BackendTraits::PipelineData *prog, const PSOKey& PSOKey)
|
||||
{
|
||||
m_cachePSO.insert(std::make_pair(PSOKey, prog));
|
||||
return std::forward_as_tuple(new_shader, false);
|
||||
}
|
||||
|
||||
public:
|
||||
ProgramStateCache() : m_currentShaderId(0) {}
|
||||
~ProgramStateCache()
|
||||
program_state_cache() = default;
|
||||
~program_state_cache()
|
||||
{
|
||||
clear();
|
||||
for (auto& pair : m_fragment_shader_cache)
|
||||
{
|
||||
free(pair.first.addr);
|
||||
}
|
||||
};
|
||||
|
||||
const vertex_program_type& get_transform_program(const RSXVertexProgram& rsx_vp) const
|
||||
{
|
||||
auto I = m_vertex_shader_cache.find(rsx_vp);
|
||||
if (I != m_vertex_shader_cache.end())
|
||||
return I->second;
|
||||
throw new EXCEPTION("Trying to get unknow transform program");
|
||||
}
|
||||
|
||||
const typename BackendTraits::VertexProgramData* get_transform_program(const RSXVertexProgram& rsx_vp) const
|
||||
const fragment_program_type& get_shader_program(const RSXFragmentProgram& rsx_fp) const
|
||||
{
|
||||
typename binary2VS::const_iterator It = m_cacheVS.find(rsx_vp.data);
|
||||
if (It == m_cacheVS.end())
|
||||
return nullptr;
|
||||
return &It->second;
|
||||
auto I = m_fragment_shader_cache.find(rsx_fp);
|
||||
if (I != m_fragment_shader_cache.end())
|
||||
return I->second;
|
||||
throw new EXCEPTION("Trying to get unknow shader program");
|
||||
}
|
||||
|
||||
const typename BackendTraits::FragmentProgramData* get_shader_program(const RSXFragmentProgram& rsx_fp) const
|
||||
{
|
||||
typename binary2FS::const_iterator It = m_cacheFS.find(vm::base(rsx_fp.addr));
|
||||
if (It == m_cacheFS.end())
|
||||
return nullptr;
|
||||
return &It->second;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (auto pair : m_cachePSO)
|
||||
BackendTraits::DeleteProgram(pair.second);
|
||||
m_cachePSO.clear();
|
||||
|
||||
for (auto pair : m_cacheFS)
|
||||
free(pair.first);
|
||||
|
||||
m_cacheFS.clear();
|
||||
}
|
||||
|
||||
typename BackendTraits::PipelineData *getGraphicPipelineState(
|
||||
RSXVertexProgram *vertexShader,
|
||||
RSXFragmentProgram *fragmentShader,
|
||||
const typename BackendTraits::PipelineProperties &pipelineProperties,
|
||||
const typename BackendTraits::ExtraData& extraData
|
||||
template<typename... Args>
|
||||
pipeline_storage_type& getGraphicPipelineState(
|
||||
const RSXVertexProgram& vertexShader,
|
||||
const RSXFragmentProgram& fragmentShader,
|
||||
const pipeline_properties& pipelineProperties,
|
||||
Args&& ...args
|
||||
)
|
||||
{
|
||||
typename BackendTraits::PipelineData *result = nullptr;
|
||||
bool fpFound, vpFound;
|
||||
typename BackendTraits::VertexProgramData &vertexProg = SearchVp(vertexShader, vpFound);
|
||||
typename BackendTraits::FragmentProgramData &fragmentProg = SearchFp(fragmentShader, fpFound);
|
||||
// TODO : use tie and implicit variable declaration syntax with c++17
|
||||
const auto &vp_search = search_vertex_program(vertexShader);
|
||||
const auto &fp_search = search_fragment_program(fragmentShader);
|
||||
const vertex_program_type &vertex_program = std::get<0>(vp_search);
|
||||
const fragment_program_type &fragment_program = std::get<0>(fp_search);
|
||||
bool already_existing_fragment_program = std::get<1>(fp_search);
|
||||
bool already_existing_vertex_program = std::get<1>(vp_search);
|
||||
|
||||
if (fpFound && vpFound)
|
||||
pipeline_key key = { vertex_program.id, fragment_program.id, pipelineProperties };
|
||||
|
||||
if (already_existing_fragment_program && already_existing_vertex_program)
|
||||
{
|
||||
result = GetProg({ vertexProg.id, fragmentProg.id, pipelineProperties });
|
||||
const auto I = m_storage.find(key);
|
||||
if (I != m_storage.end())
|
||||
return I->second;
|
||||
}
|
||||
|
||||
if (result != nullptr)
|
||||
return result;
|
||||
else
|
||||
{
|
||||
LOG_WARNING(RSX, "Add program :");
|
||||
LOG_WARNING(RSX, "*** vp id = %d", vertexProg.id);
|
||||
LOG_WARNING(RSX, "*** fp id = %d", fragmentProg.id);
|
||||
LOG_NOTICE(RSX, "Add program :");
|
||||
LOG_NOTICE(RSX, "*** vp id = %d", vertex_program.id);
|
||||
LOG_NOTICE(RSX, "*** fp id = %d", fragment_program.id);
|
||||
|
||||
result = BackendTraits::BuildProgram(vertexProg, fragmentProg, pipelineProperties, extraData);
|
||||
Add(result, { vertexProg.id, fragmentProg.id, pipelineProperties });
|
||||
}
|
||||
return result;
|
||||
m_storage[key] = backend_traits::build_pipeline(vertex_program, fragment_program, pipelineProperties, std::forward<Args>(args)...);
|
||||
return m_storage[key];
|
||||
}
|
||||
|
||||
size_t get_fragment_constants_buffer_size(const RSXFragmentProgram *fragmentShader) const
|
||||
size_t get_fragment_constants_buffer_size(const RSXFragmentProgram &fragmentShader) const
|
||||
{
|
||||
typename binary2FS::const_iterator It = m_cacheFS.find(vm::base(fragmentShader->addr));
|
||||
if (It != m_cacheFS.end())
|
||||
return It->second.FragmentConstantOffsetCache.size() * 4 * sizeof(float);
|
||||
const auto I = m_fragment_shader_cache.find(fragmentShader);
|
||||
if (I != m_fragment_shader_cache.end())
|
||||
return I->second.FragmentConstantOffsetCache.size() * 4 * sizeof(float);
|
||||
LOG_ERROR(RSX, "Can't retrieve constant offset cache");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fill_fragment_constans_buffer(void *buffer, const RSXFragmentProgram *fragment_program) const
|
||||
void fill_fragment_constans_buffer(gsl::span<f32, gsl::dynamic_range> dst_buffer, const RSXFragmentProgram &fragment_program) const
|
||||
{
|
||||
typename binary2FS::const_iterator It = m_cacheFS.find(vm::base(fragment_program->addr));
|
||||
if (It == m_cacheFS.end())
|
||||
const auto I = m_fragment_shader_cache.find(fragment_program);
|
||||
if (I == m_fragment_shader_cache.end())
|
||||
return;
|
||||
__m128i mask = _mm_set_epi8(0xE, 0xF, 0xC, 0xD,
|
||||
0xA, 0xB, 0x8, 0x9,
|
||||
0x6, 0x7, 0x4, 0x5,
|
||||
0x2, 0x3, 0x0, 0x1);
|
||||
|
||||
Expects(dst_buffer.size_bytes() >= gsl::narrow<int>(I->second.FragmentConstantOffsetCache.size()) * 16);
|
||||
|
||||
size_t offset = 0;
|
||||
for (size_t offset_in_fragment_program : It->second.FragmentConstantOffsetCache)
|
||||
for (size_t offset_in_fragment_program : I->second.FragmentConstantOffsetCache)
|
||||
{
|
||||
void *data = vm::base(fragment_program->addr + (u32)offset_in_fragment_program);
|
||||
void *data = (char*)fragment_program.addr + (u32)offset_in_fragment_program;
|
||||
const __m128i &vector = _mm_loadu_si128((__m128i*)data);
|
||||
const __m128i &shuffled_vector = _mm_shuffle_epi8(vector, mask);
|
||||
_mm_stream_si128((__m128i*)((char*)buffer + offset), shuffled_vector);
|
||||
offset += 4 * sizeof(u32);
|
||||
_mm_stream_si128((__m128i*)dst_buffer.subspan(offset, 4).data(), shuffled_vector);
|
||||
offset += sizeof(f32);
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_storage.clear();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,10 +13,18 @@ enum class FUNCTION {
|
||||
FUNCTION_FRACT,
|
||||
FUNCTION_DFDX,
|
||||
FUNCTION_DFDY,
|
||||
FUNCTION_TEXTURE_SAMPLE,
|
||||
FUNCTION_TEXTURE_SAMPLE_PROJ,
|
||||
FUNCTION_TEXTURE_CUBE_SAMPLE,
|
||||
FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ,
|
||||
FUNCTION_TEXTURE_SAMPLE1D,
|
||||
FUNCTION_TEXTURE_SAMPLE1D_PROJ,
|
||||
FUNCTION_TEXTURE_SAMPLE1D_LOD,
|
||||
FUNCTION_TEXTURE_SAMPLE2D,
|
||||
FUNCTION_TEXTURE_SAMPLE2D_PROJ,
|
||||
FUNCTION_TEXTURE_SAMPLE2D_LOD,
|
||||
FUNCTION_TEXTURE_SAMPLECUBE,
|
||||
FUNCTION_TEXTURE_SAMPLECUBE_PROJ,
|
||||
FUNCTION_TEXTURE_SAMPLECUBE_LOD,
|
||||
FUNCTION_TEXTURE_SAMPLE3D,
|
||||
FUNCTION_TEXTURE_SAMPLE3D_PROJ,
|
||||
FUNCTION_TEXTURE_SAMPLE3D_LOD,
|
||||
};
|
||||
|
||||
enum class COMPARE {
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace
|
||||
struct texel_rgba
|
||||
{
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
memcpy((char*)dst + row * dst_pitch_in_block * block_size, (char*)src + row * src_pitch_in_block * block_size, width_in_block * block_size);
|
||||
}
|
||||
};
|
||||
@@ -28,13 +28,13 @@ struct texel_rgba
|
||||
struct texel_16b_swizzled
|
||||
{
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
u16 *castedSrc = static_cast<u16*>(src), *castedDst = static_cast<u16*>(dst);
|
||||
|
||||
std::unique_ptr<u16[]> temp_swizzled(new u16[row_count * width_in_block]);
|
||||
rsx::convert_linear_swizzle<u16>(castedSrc, temp_swizzled.get(), src_pitch_in_block, row_count, true);
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
for (int j = 0; j < width_in_block; j++)
|
||||
{
|
||||
u16 tmp = temp_swizzled[row * src_pitch_in_block + j];
|
||||
@@ -49,14 +49,14 @@ struct texel_16b_swizzled
|
||||
struct texel_rgba_swizzled
|
||||
{
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
u32 *castedSrc, *castedDst;
|
||||
castedSrc = (u32*)src;
|
||||
castedDst = (u32*)dst ;
|
||||
std::unique_ptr<u32[]> temp_swizzled(new u32[src_pitch_in_block * row_count]);
|
||||
rsx::convert_linear_swizzle<u32>(castedSrc, temp_swizzled.get(), src_pitch_in_block, row_count, true);
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
memcpy((char*)dst + row * dst_pitch_in_block * block_size, (char*)temp_swizzled.get() + row * src_pitch_in_block * block_size, width_in_block * block_size);
|
||||
}
|
||||
};
|
||||
@@ -67,9 +67,9 @@ struct texel_rgba_swizzled
|
||||
*/
|
||||
struct texel_bc_format {
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
memcpy((char*)dst + row * dst_pitch_in_block * block_size, (char*)src + row * src_pitch_in_block * block_size, width_in_block * block_size);
|
||||
}
|
||||
};
|
||||
@@ -79,11 +79,11 @@ struct texel_bc_format {
|
||||
*/
|
||||
struct texel_16b_format {
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
unsigned short *castedDst = (unsigned short *)dst, *castedSrc = (unsigned short *)src;
|
||||
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
for (int j = 0; j < width_in_block; j++)
|
||||
{
|
||||
u16 tmp = castedSrc[row * src_pitch_in_block + j];
|
||||
@@ -97,10 +97,10 @@ struct texel_16b_format {
|
||||
*/
|
||||
struct texel_16bX4_format {
|
||||
template<size_t block_size>
|
||||
static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block)
|
||||
{
|
||||
unsigned short *casted_dst = (unsigned short *)dst, *casted_src = (unsigned short *)src;
|
||||
for (unsigned row = 0; row < row_count; row++)
|
||||
for (unsigned row = 0; row < row_count * depth; row++)
|
||||
for (int j = 0; j < width_in_block * 4; j++)
|
||||
{
|
||||
u16 tmp = casted_src[row * src_pitch_in_block * 4 + j];
|
||||
@@ -124,13 +124,13 @@ struct texel_16bX4_format {
|
||||
* mipmap level (to allow same code for packed/non packed texels)
|
||||
*/
|
||||
template <typename T, bool padded_row, size_t block_size_in_bytes, size_t block_edge_in_texel>
|
||||
std::vector<MipmapLevelInfo> copy_texture_data(void *dst, const void *src, size_t width_in_texel, size_t height_in_texel, size_t depth, size_t mipmap_count)
|
||||
std::vector<MipmapLevelInfo> copy_texture_data(void *dst, const void *src, u16 width_in_texel, u16 height_in_texel, u16 depth, u8 layer_count, u16 mipmap_count)
|
||||
{
|
||||
std::vector<MipmapLevelInfo> Result;
|
||||
size_t offsetInDst = 0, offsetInSrc = 0;
|
||||
size_t texture_height_in_block = (height_in_texel + block_edge_in_texel - 1) / block_edge_in_texel;
|
||||
size_t texture_width_in_block = (width_in_texel + block_edge_in_texel - 1) / block_edge_in_texel;
|
||||
for (unsigned depth_level = 0; depth_level < depth; depth_level++)
|
||||
for (unsigned layer = 0; layer < layer_count; layer++)
|
||||
{
|
||||
size_t miplevel_height_in_block = texture_height_in_block, miplevel_width_in_block = texture_width_in_block;
|
||||
for (unsigned mip_level = 0; mip_level < mipmap_count; mip_level++)
|
||||
@@ -141,18 +141,19 @@ std::vector<MipmapLevelInfo> copy_texture_data(void *dst, const void *src, size_
|
||||
currentMipmapLevelInfo.offset = offsetInDst;
|
||||
currentMipmapLevelInfo.height = miplevel_height_in_block * block_edge_in_texel;
|
||||
currentMipmapLevelInfo.width = miplevel_width_in_block * block_edge_in_texel;
|
||||
currentMipmapLevelInfo.depth = depth;
|
||||
currentMipmapLevelInfo.rowPitch = dst_pitch * block_size_in_bytes;
|
||||
Result.push_back(currentMipmapLevelInfo);
|
||||
|
||||
if (!padded_row)
|
||||
{
|
||||
T::template copy_mipmap_level<block_size_in_bytes>((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, dst_pitch, miplevel_width_in_block);
|
||||
offsetInSrc += miplevel_height_in_block * miplevel_width_in_block * block_size_in_bytes;
|
||||
T::template copy_mipmap_level<block_size_in_bytes>((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, depth, dst_pitch, miplevel_width_in_block);
|
||||
offsetInSrc += miplevel_height_in_block * miplevel_width_in_block * block_size_in_bytes * depth;
|
||||
}
|
||||
else
|
||||
{
|
||||
T::template copy_mipmap_level<block_size_in_bytes>((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, dst_pitch, texture_width_in_block);
|
||||
offsetInSrc += miplevel_height_in_block * texture_width_in_block * block_size_in_bytes;
|
||||
T::template copy_mipmap_level<block_size_in_bytes>((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, depth, dst_pitch, texture_width_in_block);
|
||||
offsetInSrc += miplevel_height_in_block * texture_width_in_block * block_size_in_bytes * depth;
|
||||
}
|
||||
offsetInDst += align(miplevel_height_in_block * dst_pitch * block_size_in_bytes, 512);
|
||||
miplevel_height_in_block = MAX2(miplevel_height_in_block / 2, 1);
|
||||
@@ -265,10 +266,28 @@ size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t rowPi
|
||||
|
||||
std::vector<MipmapLevelInfo> upload_placed_texture(const rsx::texture &texture, size_t rowPitchAlignement, void* textureData)
|
||||
{
|
||||
size_t w = texture.width(), h = texture.height();
|
||||
size_t depth = texture.depth();
|
||||
if (depth == 0) depth = 1;
|
||||
if (texture.cubemap()) depth *= 6;
|
||||
u16 w = texture.width(), h = texture.height();
|
||||
u16 depth;
|
||||
u8 layer;
|
||||
|
||||
if (texture.dimension() == 1)
|
||||
{
|
||||
depth = 1;
|
||||
layer = 1;
|
||||
h = 1;
|
||||
}
|
||||
else if (texture.dimension() == 2)
|
||||
{
|
||||
depth = 1;
|
||||
layer = texture.cubemap() ? 6 : 1;
|
||||
}
|
||||
else if (texture.dimension() == 3)
|
||||
{
|
||||
depth = texture.depth();
|
||||
layer = 1;
|
||||
}
|
||||
else
|
||||
throw EXCEPTION("Unsupported texture dimension %d", texture.dimension());
|
||||
|
||||
int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
|
||||
@@ -281,37 +300,37 @@ std::vector<MipmapLevelInfo> upload_placed_texture(const rsx::texture &texture,
|
||||
{
|
||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||
if (is_swizzled)
|
||||
return copy_texture_data<texel_rgba_swizzled, false, 4, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_rgba_swizzled, false, 4, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
else
|
||||
return copy_texture_data<texel_rgba, true, 4, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_rgba, true, 4, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_A1R5G5B5:
|
||||
case CELL_GCM_TEXTURE_A4R4G4B4:
|
||||
case CELL_GCM_TEXTURE_R5G6B5:
|
||||
if (is_swizzled)
|
||||
return copy_texture_data<texel_16b_swizzled, false, 2, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_16b_swizzled, false, 2, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
else
|
||||
return copy_texture_data<texel_16b_format, true, 2, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_16b_format, true, 2, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
|
||||
return copy_texture_data<texel_16bX4_format, true, 8, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_16bX4_format, true, 8, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT1:
|
||||
if (is_swizzled)
|
||||
return copy_texture_data<texel_bc_format, false, 8, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, false, 8, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
else
|
||||
return copy_texture_data<texel_bc_format, true, 8, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, true, 8, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT23:
|
||||
if (is_swizzled)
|
||||
return copy_texture_data<texel_bc_format, false, 16, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, false, 16, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
else
|
||||
return copy_texture_data<texel_bc_format, true, 16, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, true, 16, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_COMPRESSED_DXT45:
|
||||
if (is_swizzled)
|
||||
return copy_texture_data<texel_bc_format, false, 16, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, false, 16, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
else
|
||||
return copy_texture_data<texel_bc_format, true, 16, 4>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_bc_format, true, 16, 4>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
case CELL_GCM_TEXTURE_B8:
|
||||
return copy_texture_data<texel_rgba, true, 1, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_rgba, true, 1, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
default:
|
||||
return copy_texture_data<texel_rgba, true, 4, 1>(textureData, pixels, w, h, depth, texture.mipmap());
|
||||
return copy_texture_data<texel_rgba, true, 4, 1>(textureData, pixels, w, h, depth, layer, texture.mipmap());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
struct MipmapLevelInfo
|
||||
{
|
||||
size_t offset;
|
||||
size_t width;
|
||||
size_t height;
|
||||
size_t rowPitch;
|
||||
u16 width;
|
||||
u16 height;
|
||||
u16 depth;
|
||||
u16 rowPitch;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,7 @@ std::string VertexProgramDecompiler::GetDST(bool isSca)
|
||||
|
||||
default:
|
||||
if (d3.dst > 15)
|
||||
LOG_ERROR(RSX, fmt::format("dst index out of range: %u", d3.dst));
|
||||
LOG_ERROR(RSX, "dst index out of range: %u", d3.dst);
|
||||
ret += m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? getFloatTypeName(4) + "(0.0f, 0.0f, 0.0f, 1.0f)" : getFloatTypeName(4) + "(0.0, 0.0, 0.0, 0.0)");
|
||||
break;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ std::string VertexProgramDecompiler::GetSRC(const u32 n)
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERROR(RSX, fmt::format("Bad src%u reg type: %d", n, u32{ src[n].reg_type }));
|
||||
LOG_ERROR(RSX, "Bad src%u reg type: %d", n, u32{ src[n].reg_type });
|
||||
Emu.Pause();
|
||||
break;
|
||||
}
|
||||
@@ -435,8 +435,8 @@ std::string VertexProgramDecompiler::BuildCode()
|
||||
return OS.str();
|
||||
}
|
||||
|
||||
VertexProgramDecompiler::VertexProgramDecompiler(std::vector<u32>& data) :
|
||||
m_data(data)
|
||||
VertexProgramDecompiler::VertexProgramDecompiler(const RSXVertexProgram& prog) :
|
||||
m_data(prog.data)
|
||||
{
|
||||
m_funcs.emplace_back();
|
||||
m_funcs[0].offset = 0;
|
||||
@@ -562,10 +562,10 @@ std::string VertexProgramDecompiler::Decompile()
|
||||
case RSX_SCA_OPCODE_MOV: SetDSTSca("$s"); break;
|
||||
case RSX_SCA_OPCODE_RCP: SetDSTSca("(1.0 / $s)"); break;
|
||||
case RSX_SCA_OPCODE_RCC: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break;
|
||||
case RSX_SCA_OPCODE_RSQ: SetDSTSca("(1.f / sqrt($s))"); break;
|
||||
case RSX_SCA_OPCODE_RSQ: SetDSTSca("rsq_legacy($s)"); break;
|
||||
case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break;
|
||||
case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break;
|
||||
case RSX_SCA_OPCODE_LIT: SetDSTSca(getFloatTypeName(4) + "(1.0, $s.x, ($s.x > 0.0 ? exp($s.w * log2($s.y)) : 0.0), 1.0)"); break;
|
||||
case RSX_SCA_OPCODE_LIT: SetDSTSca("lit_legacy($s)"); break;
|
||||
case RSX_SCA_OPCODE_BRA:
|
||||
{
|
||||
AddCode("$if ($cond)");
|
||||
@@ -619,7 +619,7 @@ std::string VertexProgramDecompiler::Decompile()
|
||||
// works like BRI but shorter (RET o[1].x(TR);)
|
||||
AddCode("$ifcond return;");
|
||||
break;
|
||||
case RSX_SCA_OPCODE_LG2: SetDSTSca("log2($s)"); break;
|
||||
case RSX_SCA_OPCODE_LG2: SetDSTSca("log2_legacy($s)"); break;
|
||||
case RSX_SCA_OPCODE_EX2: SetDSTSca("exp2($s)"); break;
|
||||
case RSX_SCA_OPCODE_SIN: SetDSTSca("sin($s)"); break;
|
||||
case RSX_SCA_OPCODE_COS: SetDSTSca("cos($s)"); break;
|
||||
|
||||
@@ -57,7 +57,7 @@ struct VertexProgramDecompiler
|
||||
|
||||
//wxString main;
|
||||
|
||||
std::vector<u32>& m_data;
|
||||
const std::vector<u32>& m_data;
|
||||
ParamArray m_parr;
|
||||
|
||||
std::string GetMask(bool is_sca);
|
||||
@@ -124,6 +124,6 @@ protected:
|
||||
*/
|
||||
virtual void insertMainEnd(std::stringstream &OS) = 0;
|
||||
public:
|
||||
VertexProgramDecompiler(std::vector<u32>& data);
|
||||
VertexProgramDecompiler(const RSXVertexProgram& prog);
|
||||
std::string Decompile();
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "stdafx.h"
|
||||
#include "surface_store.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
std::vector<u8> get_rtt_indexes(surface_target color_target)
|
||||
{
|
||||
switch (color_target)
|
||||
{
|
||||
case surface_target::none: return{};
|
||||
case surface_target::surface_a: return{ 0 };
|
||||
case surface_target::surface_b: return{ 1 };
|
||||
case surface_target::surfaces_a_b: return{ 0, 1 };
|
||||
case surface_target::surfaces_a_b_c: return{ 0, 1, 2 };
|
||||
case surface_target::surfaces_a_b_c_d: return{ 0, 1, 2, 3 };
|
||||
}
|
||||
throw EXCEPTION("Wrong color_target");
|
||||
}
|
||||
|
||||
size_t get_aligned_pitch(surface_color_format format, u32 width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case surface_color_format::b8: return align(width, 256);
|
||||
case surface_color_format::g8b8:
|
||||
case surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case surface_color_format::r5g6b5: return align(width * 2, 256);
|
||||
case surface_color_format::a8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case surface_color_format::x32:
|
||||
case surface_color_format::a8r8g8b8: return align(width * 4, 256);
|
||||
case surface_color_format::w16z16y16x16: return align(width * 8, 256);
|
||||
case surface_color_format::w32z32y32x32: return align(width * 16, 256);
|
||||
}
|
||||
throw EXCEPTION("Unknow color surface format");
|
||||
}
|
||||
|
||||
size_t get_packed_pitch(surface_color_format format, u32 width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case surface_color_format::b8: return width;
|
||||
case surface_color_format::g8b8:
|
||||
case surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case surface_color_format::r5g6b5: return width * 2;
|
||||
case surface_color_format::a8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case surface_color_format::x32:
|
||||
case surface_color_format::a8r8g8b8: return width * 4;
|
||||
case surface_color_format::w16z16y16x16: return width * 8;
|
||||
case surface_color_format::w32z32y32x32: return width * 16;
|
||||
}
|
||||
throw EXCEPTION("Unknow color surface format");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
#pragma once
|
||||
|
||||
#include <gsl.h>
|
||||
#include "../GCM.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
std::vector<u8> get_rtt_indexes(surface_target color_target);
|
||||
size_t get_aligned_pitch(surface_color_format format, u32 width);
|
||||
size_t get_packed_pitch(surface_color_format format, u32 width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for surface (ie color and depth stencil render target) management.
|
||||
* It handles surface creation and storage. Backend should only retrieve pointer to surface.
|
||||
* It provides 2 methods get_texture_from_*_if_applicable that should be used when an app
|
||||
* wants to sample a previous surface.
|
||||
* Please note that the backend is still responsible for creating framebuffer/descriptors
|
||||
* and need to inform surface_store everytime surface format/size/addresses change.
|
||||
*
|
||||
* Since it's a template it requires a trait with the followings:
|
||||
* - type surface_storage_type which is a structure containing texture.
|
||||
* - type surface_type which is a pointer to storage_type or a reference.
|
||||
* - type command_list_type that can be void for backend without command list
|
||||
* - type download_buffer_object used by issue_download_command and map_downloaded_buffer functions to handle sync
|
||||
*
|
||||
* - a member function static surface_type(const surface_storage_type&) that returns underlying surface pointer from a storage type.
|
||||
* - 2 member functions static surface_storage_type create_new_surface(u32 address, Surface_color_format/Surface_depth_format format, size_t width, size_t height,...)
|
||||
* used to create a new surface_storage_type holding surface from passed parameters.
|
||||
* - a member function static prepare_rtt_for_drawing(command_list, surface_type) that makes a sampleable surface a color render target one.
|
||||
* - a member function static prepare_rtt_for_drawing(command_list, surface_type) that makes a render target surface a sampleable one.
|
||||
* - a member function static prepare_ds_for_drawing that does the same for depth stencil surface.
|
||||
* - a member function static prepare_ds_for_sampling that does the same for depth stencil surface.
|
||||
* - a member function static bool rtt_has_format_width_height(const surface_storage_type&, Surface_color_format surface_color_format, size_t width, size_t height)
|
||||
* that checks if the given surface has the given format and size
|
||||
* - a member function static bool ds_has_format_width_height that does the same for ds
|
||||
* - a member function static download_buffer_object issue_download_command(surface_type, Surface_color_format color_format, size_t width, size_t height,...)
|
||||
* that generates command to download the given surface to some mappable buffer.
|
||||
* - a member function static issue_depth_download_command that does the same for depth surface
|
||||
* - a member function static issue_stencil_download_command that does the same for stencil surface
|
||||
* - a member function gsl::span<const gsl::byte> map_downloaded_buffer(download_buffer_object, ...) that maps a download_buffer_object
|
||||
* - a member function static unmap_downloaded_buffer that unmaps it.
|
||||
*/
|
||||
template<typename Traits>
|
||||
struct surface_store
|
||||
{
|
||||
template<typename T, typename U>
|
||||
void copy_pitched_src_to_dst(gsl::span<T> dest, gsl::span<const U> src, size_t src_pitch_in_bytes, size_t width, size_t height)
|
||||
{
|
||||
for (int row = 0; row < height; row++)
|
||||
{
|
||||
for (unsigned col = 0; col < width; col++)
|
||||
dest[col] = src[col];
|
||||
src = src.subspan(src_pitch_in_bytes / sizeof(U));
|
||||
dest = dest.subspan(width);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using surface_storage_type = typename Traits::surface_storage_type;
|
||||
using surface_type = typename Traits::surface_type;
|
||||
using command_list_type = typename Traits::command_list_type;
|
||||
using download_buffer_object = typename Traits::download_buffer_object;
|
||||
|
||||
std::unordered_map<u32, surface_storage_type> m_render_targets_storage = {};
|
||||
std::unordered_map<u32, surface_storage_type> m_depth_stencil_storage = {};
|
||||
|
||||
public:
|
||||
std::array<std::tuple<u32, surface_type>, 4> m_bound_render_targets = {};
|
||||
std::tuple<u32, surface_type> m_bound_depth_stencil = {};
|
||||
|
||||
std::list<surface_storage_type> invalidated_resources;
|
||||
|
||||
surface_store() = default;
|
||||
~surface_store() = default;
|
||||
surface_store(const surface_store&) = delete;
|
||||
private:
|
||||
/**
|
||||
* If render target already exists at address, issue state change operation on cmdList.
|
||||
* Otherwise create one with width, height, clearColor info.
|
||||
* returns the corresponding render target resource.
|
||||
*/
|
||||
template <typename ...Args>
|
||||
gsl::not_null<surface_type> bind_address_as_render_targets(
|
||||
command_list_type command_list,
|
||||
u32 address,
|
||||
surface_color_format color_format, size_t width, size_t height,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
auto It = m_render_targets_storage.find(address);
|
||||
// TODO: Fix corner cases
|
||||
// This doesn't take overlapping surface(s) into account.
|
||||
// Invalidated surface(s) should also copy their content to the new resources.
|
||||
if (It != m_render_targets_storage.end())
|
||||
{
|
||||
surface_storage_type &rtt = It->second;
|
||||
if (Traits::rtt_has_format_width_height(rtt, color_format, width, height))
|
||||
{
|
||||
Traits::prepare_rtt_for_drawing(command_list, Traits::get(rtt));
|
||||
return Traits::get(rtt);
|
||||
}
|
||||
invalidated_resources.push_back(std::move(rtt));
|
||||
m_render_targets_storage.erase(address);
|
||||
}
|
||||
|
||||
m_render_targets_storage[address] = Traits::create_new_surface(address, color_format, width, height, std::forward<Args>(extra_params)...);
|
||||
return Traits::get(m_render_targets_storage[address]);
|
||||
}
|
||||
|
||||
template <typename ...Args>
|
||||
gsl::not_null<surface_type> bind_address_as_depth_stencil(
|
||||
command_list_type command_list,
|
||||
u32 address,
|
||||
surface_depth_format depth_format, size_t width, size_t height,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
auto It = m_depth_stencil_storage.find(address);
|
||||
if (It != m_depth_stencil_storage.end())
|
||||
{
|
||||
surface_storage_type &ds = It->second;
|
||||
if (Traits::ds_has_format_width_height(ds, depth_format, width, height))
|
||||
{
|
||||
Traits::prepare_ds_for_drawing(command_list, Traits::get(ds));
|
||||
return Traits::get(ds);
|
||||
}
|
||||
invalidated_resources.push_back(std::move(ds));
|
||||
m_depth_stencil_storage.erase(address);
|
||||
}
|
||||
|
||||
m_depth_stencil_storage[address] = Traits::create_new_surface(address, depth_format, width, height, std::forward<Args>(extra_params)...);
|
||||
return Traits::get(m_depth_stencil_storage[address]);
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* Update bound color and depth surface.
|
||||
* Must be called everytime surface format, clip, or addresses changes.
|
||||
*/
|
||||
template <typename ...Args>
|
||||
void prepare_render_target(
|
||||
command_list_type command_list,
|
||||
u32 set_surface_format_reg,
|
||||
u32 clip_horizontal_reg, u32 clip_vertical_reg,
|
||||
surface_target set_surface_target,
|
||||
const std::array<u32, 4> &surface_addresses, u32 address_z,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
u32 clip_width = clip_horizontal_reg >> 16;
|
||||
u32 clip_height = clip_vertical_reg >> 16;
|
||||
u32 clip_x = clip_horizontal_reg;
|
||||
u32 clip_y = clip_vertical_reg;
|
||||
|
||||
surface_color_format color_format = to_surface_color_format(set_surface_format_reg & 0x1f);
|
||||
surface_depth_format depth_format = to_surface_depth_format((set_surface_format_reg >> 5) & 0x7);
|
||||
|
||||
// Make previous RTTs sampleable
|
||||
for (std::tuple<u32, surface_type> &rtt : m_bound_render_targets)
|
||||
{
|
||||
if (std::get<1>(rtt) != nullptr)
|
||||
Traits::prepare_rtt_for_sampling(command_list, std::get<1>(rtt));
|
||||
rtt = std::make_tuple(0, nullptr);
|
||||
}
|
||||
|
||||
// Create/Reuse requested rtts
|
||||
for (u8 surface_index : utility::get_rtt_indexes(set_surface_target))
|
||||
{
|
||||
if (surface_addresses[surface_index] == 0)
|
||||
continue;
|
||||
|
||||
m_bound_render_targets[surface_index] = std::make_tuple(surface_addresses[surface_index],
|
||||
bind_address_as_render_targets(command_list, surface_addresses[surface_index], color_format, clip_width, clip_height, std::forward<Args>(extra_params)...));
|
||||
}
|
||||
|
||||
// Same for depth buffer
|
||||
if (std::get<1>(m_bound_depth_stencil) != nullptr)
|
||||
Traits::prepare_ds_for_sampling(command_list, std::get<1>(m_bound_depth_stencil));
|
||||
m_bound_depth_stencil = std::make_tuple(0, nullptr);
|
||||
if (!address_z)
|
||||
return;
|
||||
m_bound_depth_stencil = std::make_tuple(address_z,
|
||||
bind_address_as_depth_stencil(command_list, address_z, depth_format, clip_width, clip_height, std::forward<Args>(extra_params)...));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for given address in stored color surface and returns it if size/format match.
|
||||
* Return an empty surface_type otherwise.
|
||||
*/
|
||||
surface_type get_texture_from_render_target_if_applicable(u32 address)
|
||||
{
|
||||
// TODO: Handle texture that overlaps one (or several) surface.
|
||||
// Handle texture conversion
|
||||
// FIXME: Disgaea 3 loading screen seems to use a subset of a surface. It's not properly handled here.
|
||||
// Note: not const because conversions/resolve/... can happen
|
||||
auto It = m_render_targets_storage.find(address);
|
||||
if (It != m_render_targets_storage.end())
|
||||
return Traits::get(It->second);
|
||||
return surface_type();
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for given address in stored depth stencil surface and returns it if size/format match.
|
||||
* Return an empty surface_type otherwise.
|
||||
*/
|
||||
surface_type get_texture_from_depth_stencil_if_applicable(u32 address)
|
||||
{
|
||||
// TODO: Same as above although there wasn't any game using corner case for DS yet.
|
||||
auto It = m_depth_stencil_storage.find(address);
|
||||
if (It != m_depth_stencil_storage.end())
|
||||
return Traits::get(It->second);
|
||||
return surface_type();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bound color surface raw data.
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::array<std::vector<gsl::byte>, 4> get_render_targets_data(
|
||||
surface_color_format color_format, size_t width, size_t height,
|
||||
Args&& ...args
|
||||
)
|
||||
{
|
||||
std::array<download_buffer_object, 4> download_data = {};
|
||||
|
||||
// Issue download commands
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (std::get<0>(m_bound_render_targets[i]) == 0)
|
||||
continue;
|
||||
|
||||
surface_type surface_resource = std::get<1>(m_bound_render_targets[i]);
|
||||
download_data[i] = std::move(
|
||||
Traits::issue_download_command(surface_resource, color_format, width, height, std::forward<Args&&>(args)...)
|
||||
);
|
||||
}
|
||||
|
||||
std::array<std::vector<gsl::byte>, 4> result = {};
|
||||
|
||||
// Sync and copy data
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (std::get<0>(m_bound_render_targets[i]) == 0)
|
||||
continue;
|
||||
|
||||
gsl::span<const gsl::byte> raw_src = Traits::map_downloaded_buffer(download_data[i], std::forward<Args&&>(args)...);
|
||||
|
||||
size_t src_pitch = utility::get_aligned_pitch(color_format, gsl::narrow<u32>(width));
|
||||
size_t dst_pitch = utility::get_packed_pitch(color_format, gsl::narrow<u32>(width));
|
||||
|
||||
result[i].resize(dst_pitch * height);
|
||||
|
||||
// Note: MSVC + GSL doesn't support span<byte> -> span<T> for non const span atm
|
||||
// thus manual conversion
|
||||
switch (color_format)
|
||||
{
|
||||
case surface_color_format::a8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case surface_color_format::a8r8g8b8:
|
||||
case surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case surface_color_format::x32:
|
||||
{
|
||||
gsl::span<be_t<u32>> dst_span{ (be_t<u32>*)result[i].data(), gsl::narrow<int>(dst_pitch * width / sizeof(be_t<u32>)) };
|
||||
copy_pitched_src_to_dst(dst_span, gsl::as_span<const u32>(raw_src), src_pitch, width, height);
|
||||
break;
|
||||
}
|
||||
case surface_color_format::b8:
|
||||
{
|
||||
gsl::span<u8> dst_span{ (u8*)result[i].data(), gsl::narrow<int>(dst_pitch * width / sizeof(u8)) };
|
||||
copy_pitched_src_to_dst(dst_span, gsl::as_span<const u8>(raw_src), src_pitch, width, height);
|
||||
break;
|
||||
}
|
||||
case surface_color_format::g8b8:
|
||||
case surface_color_format::r5g6b5:
|
||||
case surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
{
|
||||
gsl::span<be_t<u16>> dst_span{ (be_t<u16>*)result[i].data(), gsl::narrow<int>(dst_pitch * width / sizeof(be_t<u16>)) };
|
||||
copy_pitched_src_to_dst(dst_span, gsl::as_span<const u16>(raw_src), src_pitch, width, height);
|
||||
break;
|
||||
}
|
||||
// Note : may require some big endian swap
|
||||
case surface_color_format::w32z32y32x32:
|
||||
{
|
||||
gsl::span<u128> dst_span{ (u128*)result[i].data(), gsl::narrow<int>(dst_pitch * width / sizeof(u128)) };
|
||||
copy_pitched_src_to_dst(dst_span, gsl::as_span<const u128>(raw_src), src_pitch, width, height);
|
||||
break;
|
||||
}
|
||||
case surface_color_format::w16z16y16x16:
|
||||
{
|
||||
gsl::span<u64> dst_span{ (u64*)result[i].data(), gsl::narrow<int>(dst_pitch * width / sizeof(u64)) };
|
||||
copy_pitched_src_to_dst(dst_span, gsl::as_span<const u64>(raw_src), src_pitch, width, height);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
Traits::unmap_downloaded_buffer(download_data[i], std::forward<Args&&>(args)...);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bound color surface raw data.
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::array<std::vector<gsl::byte>, 2> get_depth_stencil_data(
|
||||
surface_depth_format depth_format, size_t width, size_t height,
|
||||
Args&& ...args
|
||||
)
|
||||
{
|
||||
std::array<std::vector<gsl::byte>, 2> result = {};
|
||||
if (std::get<0>(m_bound_depth_stencil) == 0)
|
||||
return result;
|
||||
size_t row_pitch = align(width * 4, 256);
|
||||
|
||||
download_buffer_object stencil_data = {};
|
||||
download_buffer_object depth_data = Traits::issue_depth_download_command(std::get<1>(m_bound_depth_stencil), depth_format, width, height, std::forward<Args&&>(args)...);
|
||||
if (depth_format == surface_depth_format::z24s8)
|
||||
stencil_data = std::move(Traits::issue_stencil_download_command(std::get<1>(m_bound_depth_stencil), width, height, std::forward<Args&&>(args)...));
|
||||
|
||||
gsl::span<const gsl::byte> depth_buffer_raw_src = Traits::map_downloaded_buffer(depth_data, std::forward<Args&&>(args)...);
|
||||
if (depth_format == surface_depth_format::z16)
|
||||
{
|
||||
result[0].resize(width * height * 2);
|
||||
gsl::span<u16> dest{ (u16*)result[0].data(), gsl::narrow<int>(width * height) };
|
||||
copy_pitched_src_to_dst(dest, gsl::as_span<const u16>(depth_buffer_raw_src), row_pitch, width, height);
|
||||
}
|
||||
if (depth_format == surface_depth_format::z24s8)
|
||||
{
|
||||
result[0].resize(width * height * 4);
|
||||
gsl::span<u32> dest{ (u32*)result[0].data(), gsl::narrow<int>(width * height) };
|
||||
copy_pitched_src_to_dst(dest, gsl::as_span<const u32>(depth_buffer_raw_src), row_pitch, width, height);
|
||||
}
|
||||
Traits::unmap_downloaded_buffer(depth_data, std::forward<Args&&>(args)...);
|
||||
|
||||
if (depth_format == surface_depth_format::z16)
|
||||
return result;
|
||||
|
||||
gsl::span<const gsl::byte> stencil_buffer_raw_src = Traits::map_downloaded_buffer(stencil_data, std::forward<Args&&>(args)...);
|
||||
result[1].resize(width * height);
|
||||
gsl::span<u8> dest{ (u8*)result[1].data(), gsl::narrow<int>(width * height) };
|
||||
copy_pitched_src_to_dst(dest, gsl::as_span<const u8>(stencil_buffer_raw_src), align(width, 256), width, height);
|
||||
Traits::unmap_downloaded_buffer(stencil_data, std::forward<Args&&>(args)...);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
+207
-222
@@ -10,43 +10,73 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
D3D12_GPU_VIRTUAL_ADDRESS createVertexBuffer(const rsx::data_array_format_info &vertex_array_desc, const std::vector<u8> &vertex_data, ID3D12Device *device, data_heap<ID3D12Resource, 65536> &vertex_index_heap)
|
||||
{
|
||||
size_t buffer_size = vertex_data.size();
|
||||
assert(vertex_index_heap.can_alloc(buffer_size));
|
||||
size_t heap_offset = vertex_index_heap.alloc(buffer_size);
|
||||
UINT get_component_mapping_from_vector_size(u8 size)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
return D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1);
|
||||
case 2:
|
||||
return D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1);
|
||||
case 3:
|
||||
return D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1);
|
||||
case 4:
|
||||
return D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
}
|
||||
throw EXCEPTION("Wrong vector size %d", size);
|
||||
}
|
||||
|
||||
void *buffer;
|
||||
CHECK_HRESULT(vertex_index_heap.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
|
||||
void *bufferMap = (char*)buffer + heap_offset;
|
||||
memcpy(bufferMap, vertex_data.data(), vertex_data.size());
|
||||
vertex_index_heap.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
return vertex_index_heap.m_heap->GetGPUVirtualAddress() + heap_offset;
|
||||
u32 get_vertex_count(const std::vector<std::pair<u32, u32> > first_count_commands)
|
||||
{
|
||||
u32 vertex_count = 0;
|
||||
for (const auto &pair : first_count_commands)
|
||||
vertex_count += pair.second;
|
||||
return vertex_count;
|
||||
}
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC get_vertex_attribute_srv(const rsx::data_array_format_info &info, UINT64 offset_in_vertex_buffers_buffer, UINT buffer_size)
|
||||
{
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC vertex_buffer_view = {
|
||||
get_vertex_attribute_format(info.type, info.size),
|
||||
D3D12_SRV_DIMENSION_BUFFER,
|
||||
get_component_mapping_from_vector_size(info.size)
|
||||
};
|
||||
vertex_buffer_view.Buffer.FirstElement = offset_in_vertex_buffers_buffer / element_size;
|
||||
vertex_buffer_view.Buffer.NumElements = buffer_size / element_size;
|
||||
return vertex_buffer_view;
|
||||
}
|
||||
|
||||
template<int N>
|
||||
UINT64 get_next_multiple_of(UINT64 val)
|
||||
{
|
||||
UINT64 divided_val = (val + N - 1) / N;
|
||||
return divided_val * N;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void D3D12GSRender::load_vertex_data(u32 first, u32 count)
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> D3D12GSRender::upload_vertex_attributes(
|
||||
const std::vector<std::pair<u32, u32> > &vertex_ranges,
|
||||
gsl::not_null<ID3D12GraphicsCommandList*> command_list)
|
||||
{
|
||||
m_first_count_pairs.emplace_back(std::make_pair(first, count));
|
||||
vertex_draw_count += count;
|
||||
}
|
||||
|
||||
std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges)
|
||||
{
|
||||
std::vector<D3D12_VERTEX_BUFFER_VIEW> vertex_buffer_views;
|
||||
|
||||
m_IASet.clear();
|
||||
size_t input_slot = 0;
|
||||
|
||||
size_t vertex_count = 0;
|
||||
|
||||
for (const auto &pair : vertex_ranges)
|
||||
vertex_count += pair.second;
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_views;
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertex_buffer_data.Get(), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, D3D12_RESOURCE_STATE_COPY_DEST));
|
||||
|
||||
u32 vertex_count = get_vertex_count(vertex_ranges);
|
||||
size_t offset_in_vertex_buffers_buffer = 0;
|
||||
u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK];
|
||||
|
||||
for (int index = 0; index < rsx::limits::vertex_count; ++index)
|
||||
@@ -60,221 +90,184 @@ std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(co
|
||||
// Active vertex array
|
||||
const rsx::data_array_format_info &info = vertex_arrays_info[index];
|
||||
|
||||
u32 type_size = rsx::get_vertex_type_size(info.type);
|
||||
u32 element_size = type_size * info.size;
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
UINT buffer_size = element_size * vertex_count;
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
size_t buffer_size = element_size * vertex_count;
|
||||
assert(m_vertex_index_data.can_alloc(buffer_size));
|
||||
size_t heap_offset = m_vertex_index_data.alloc(buffer_size);
|
||||
|
||||
void *buffer;
|
||||
CHECK_HRESULT(m_vertex_index_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
|
||||
void *mapped_buffer = (char*)buffer + heap_offset;
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
for (const auto &range : vertex_ranges)
|
||||
{
|
||||
write_vertex_array_data_to_buffer(mapped_buffer, range.first, range.second, index, info);
|
||||
mapped_buffer = (char*)mapped_buffer + range.second * element_size;
|
||||
}
|
||||
m_vertex_index_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view =
|
||||
{
|
||||
m_vertex_index_data.m_heap->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size,
|
||||
(UINT)element_size
|
||||
};
|
||||
vertex_buffer_views.push_back(vertex_buffer_view);
|
||||
command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size);
|
||||
|
||||
m_timers.m_buffer_upload_size += buffer_size;
|
||||
vertex_buffer_views.emplace_back(get_vertex_attribute_srv(info, offset_in_vertex_buffers_buffer, buffer_size));
|
||||
offset_in_vertex_buffers_buffer = get_next_multiple_of<48>(offset_in_vertex_buffers_buffer + buffer_size); // 48 is multiple of 2, 4, 6, 8, 12, 16
|
||||
|
||||
m_timers.buffer_upload_size += buffer_size;
|
||||
|
||||
D3D12_INPUT_ELEMENT_DESC IAElement = {};
|
||||
IAElement.SemanticName = "TEXCOORD";
|
||||
IAElement.SemanticIndex = (UINT)index;
|
||||
IAElement.InputSlot = (UINT)input_slot++;
|
||||
IAElement.Format = get_vertex_attribute_format(info.type, info.size);
|
||||
IAElement.AlignedByteOffset = 0;
|
||||
IAElement.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
IAElement.InstanceDataStepRate = 0;
|
||||
m_IASet.push_back(IAElement);
|
||||
}
|
||||
else if (register_vertex_info[index].size > 0)
|
||||
{
|
||||
// In register vertex attribute
|
||||
const rsx::data_array_format_info &info = register_vertex_info[index];
|
||||
|
||||
const std::vector<u8> &data = register_vertex_data[index];
|
||||
|
||||
u32 type_size = rsx::get_vertex_type_size(info.type);
|
||||
u32 element_size = type_size * info.size;
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
UINT buffer_size = gsl::narrow<UINT>(data.size());
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
size_t buffer_size = data.size();
|
||||
assert(m_vertex_index_data.can_alloc(buffer_size));
|
||||
size_t heap_offset = m_vertex_index_data.alloc(buffer_size);
|
||||
|
||||
void *buffer;
|
||||
CHECK_HRESULT(m_vertex_index_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
|
||||
void *mapped_buffer = (char*)buffer + heap_offset;
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
memcpy(mapped_buffer, data.data(), data.size());
|
||||
m_vertex_index_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view = {
|
||||
m_vertex_index_data.m_heap->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size,
|
||||
(UINT)element_size
|
||||
};
|
||||
vertex_buffer_views.push_back(vertex_buffer_view);
|
||||
command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size);
|
||||
|
||||
D3D12_INPUT_ELEMENT_DESC IAElement = {};
|
||||
IAElement.SemanticName = "TEXCOORD";
|
||||
IAElement.SemanticIndex = (UINT)index;
|
||||
IAElement.InputSlot = (UINT)input_slot++;
|
||||
IAElement.Format = get_vertex_attribute_format(info.type, info.size);
|
||||
IAElement.AlignedByteOffset = 0;
|
||||
IAElement.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
|
||||
IAElement.InstanceDataStepRate = 1;
|
||||
m_IASet.push_back(IAElement);
|
||||
vertex_buffer_views.emplace_back(get_vertex_attribute_srv(info, offset_in_vertex_buffers_buffer, buffer_size));
|
||||
offset_in_vertex_buffers_buffer = get_next_multiple_of<48>(offset_in_vertex_buffers_buffer + buffer_size); // 48 is multiple of 2, 4, 6, 8, 12, 16
|
||||
}
|
||||
}
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertex_buffer_data.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));
|
||||
return vertex_buffer_views;
|
||||
}
|
||||
|
||||
void D3D12GSRender::load_vertex_index_data(u32 first, u32 count)
|
||||
namespace
|
||||
{
|
||||
std::tuple<std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>, size_t> upload_inlined_vertex_array(
|
||||
gsl::span<const rsx::data_array_format_info, 16> vertex_attribute_infos,
|
||||
gsl::span<const gsl::byte> inlined_array_raw_data,
|
||||
data_heap& ring_buffer_data,
|
||||
ID3D12Resource* vertex_buffer_placement,
|
||||
ID3D12GraphicsCommandList* command_list
|
||||
)
|
||||
{
|
||||
// We can't rely on vertex_attribute_infos strides here so compute it
|
||||
// assuming all attributes are packed
|
||||
u32 stride = 0;
|
||||
for (const auto &info : vertex_attribute_infos)
|
||||
{
|
||||
if (!info.size) // disabled
|
||||
continue;
|
||||
|
||||
stride += rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
}
|
||||
|
||||
u32 element_count = gsl::narrow<u32>(inlined_array_raw_data.size_bytes()) / stride;
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> result;
|
||||
|
||||
UINT64 vertex_buffer_offset = 0;
|
||||
for (const auto &info : vertex_attribute_infos)
|
||||
{
|
||||
if (!info.size) // disabled
|
||||
continue;
|
||||
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
UINT buffer_size = element_size * element_count;
|
||||
size_t heap_offset = ring_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
void *mapped_buffer = ring_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
gsl::span<gsl::byte> dst = { (gsl::byte*)mapped_buffer, buffer_size };
|
||||
|
||||
for (u32 i = 0; i < element_count; i++)
|
||||
{
|
||||
auto subdst = dst.subspan(i * element_size, element_size);
|
||||
auto subsrc = inlined_array_raw_data.subspan(i * stride, element_size);
|
||||
if (info.type == rsx::vertex_base_type::ub && info.size == 4)
|
||||
{
|
||||
subdst[0] = subsrc[3];
|
||||
subdst[1] = subsrc[2];
|
||||
subdst[2] = subsrc[1];
|
||||
subdst[3] = subsrc[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(subsrc.begin(), subsrc.end(), subdst.begin());
|
||||
}
|
||||
}
|
||||
|
||||
ring_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
command_list->CopyBufferRegion(vertex_buffer_placement, vertex_buffer_offset, ring_buffer_data.get_heap(), heap_offset, buffer_size);
|
||||
|
||||
result.emplace_back(get_vertex_attribute_srv(info, vertex_buffer_offset, buffer_size));
|
||||
vertex_buffer_offset = get_next_multiple_of<48>(vertex_buffer_offset + buffer_size); // 48 is multiple of 2, 4, 6, 8, 12, 16
|
||||
}
|
||||
|
||||
return std::make_tuple(result, element_count);
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex)
|
||||
{
|
||||
assert(m_constants_data.can_alloc(256));
|
||||
size_t heap_offset = m_constants_data.alloc(256);
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(256);
|
||||
|
||||
// Scale offset buffer
|
||||
// Separate constant buffer
|
||||
void *mapped_buffer;
|
||||
CHECK_HRESULT(m_constants_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + 256), &mapped_buffer));
|
||||
fill_scale_offset_data((char*)mapped_buffer + heap_offset);
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + 256));
|
||||
fill_scale_offset_data(mapped_buffer);
|
||||
int is_alpha_tested = !!(rsx::method_registers[NV4097_SET_ALPHA_TEST_ENABLE]);
|
||||
float alpha_ref = (float&)rsx::method_registers[NV4097_SET_ALPHA_REF];
|
||||
memcpy((char*)mapped_buffer + heap_offset + 16 * sizeof(float), &is_alpha_tested, sizeof(int));
|
||||
memcpy((char*)mapped_buffer + heap_offset + 17 * sizeof(float), &alpha_ref, sizeof(float));
|
||||
|
||||
size_t tex_idx = 0;
|
||||
for (u32 i = 0; i < rsx::limits::textures_count; ++i)
|
||||
{
|
||||
if (!textures[i].enabled())
|
||||
{
|
||||
int is_unorm = false;
|
||||
memcpy((char*)mapped_buffer + heap_offset + (18 + tex_idx++) * sizeof(int), &is_unorm, sizeof(int));
|
||||
continue;
|
||||
}
|
||||
size_t w = textures[i].width(), h = textures[i].height();
|
||||
// if (!w || !h) continue;
|
||||
|
||||
int is_unorm = (textures[i].format() & CELL_GCM_TEXTURE_UN);
|
||||
memcpy((char*)mapped_buffer + heap_offset + (18 + tex_idx++) * sizeof(int), &is_unorm, sizeof(int));
|
||||
}
|
||||
m_constants_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + 256));
|
||||
u8 alpha_ref_raw = (u8)(rsx::method_registers[NV4097_SET_ALPHA_REF] & 0xFF);
|
||||
float alpha_ref = alpha_ref_raw / 255.f;
|
||||
memcpy((char*)mapped_buffer + 16 * sizeof(float), &is_alpha_tested, sizeof(int));
|
||||
memcpy((char*)mapped_buffer + 17 * sizeof(float), &alpha_ref, sizeof(float));
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + 256));
|
||||
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = {
|
||||
m_constants_data.m_heap->GetGPUVirtualAddress() + heap_offset,
|
||||
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
|
||||
256
|
||||
};
|
||||
m_device->CreateConstantBufferView(&constant_buffer_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)descriptorIndex, g_descriptor_stride_srv_cbv_uav));
|
||||
.Offset((INT)descriptorIndex, m_descriptor_stride_srv_cbv_uav));
|
||||
}
|
||||
|
||||
void D3D12GSRender::upload_and_bind_vertex_shader_constants(size_t descriptor_index)
|
||||
{
|
||||
size_t buffer_size = 512 * 4 * sizeof(float);
|
||||
|
||||
assert(m_constants_data.can_alloc(buffer_size));
|
||||
size_t heap_offset = m_constants_data.alloc(buffer_size);
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
void *mapped_buffer;
|
||||
CHECK_HRESULT(m_constants_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), &mapped_buffer));
|
||||
fill_vertex_program_constants_data((char*)mapped_buffer + heap_offset);
|
||||
m_constants_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
fill_vertex_program_constants_data(mapped_buffer);
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = {
|
||||
m_constants_data.m_heap->GetGPUVirtualAddress() + heap_offset,
|
||||
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size
|
||||
};
|
||||
m_device->CreateConstantBufferView(&constant_buffer_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)descriptor_index, g_descriptor_stride_srv_cbv_uav));
|
||||
.Offset((INT)descriptor_index, m_descriptor_stride_srv_cbv_uav));
|
||||
}
|
||||
|
||||
void D3D12GSRender::upload_and_bind_fragment_shader_constants(size_t descriptor_index)
|
||||
{
|
||||
// Get constant from fragment program
|
||||
size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(&fragment_program);
|
||||
size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(m_fragment_program);
|
||||
// Multiple of 256 never 0
|
||||
buffer_size = (buffer_size + 255) & ~255;
|
||||
|
||||
assert(m_constants_data.can_alloc(buffer_size));
|
||||
size_t heap_offset = m_constants_data.alloc(buffer_size);
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
size_t offset = 0;
|
||||
void *mapped_buffer;
|
||||
CHECK_HRESULT(m_constants_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), &mapped_buffer));
|
||||
m_pso_cache.fill_fragment_constans_buffer((char*)mapped_buffer + heap_offset, &fragment_program);
|
||||
m_constants_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
float *mapped_buffer = m_buffer_data.map<float>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
m_pso_cache.fill_fragment_constans_buffer({ mapped_buffer, gsl::narrow<int>(buffer_size) }, m_fragment_program);
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = {
|
||||
m_constants_data.m_heap->GetGPUVirtualAddress() + heap_offset,
|
||||
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size
|
||||
};
|
||||
m_device->CreateConstantBufferView(&constant_buffer_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)descriptor_index, g_descriptor_stride_srv_cbv_uav));
|
||||
.Offset((INT)descriptor_index, m_descriptor_stride_srv_cbv_uav));
|
||||
}
|
||||
|
||||
|
||||
std::tuple<D3D12_VERTEX_BUFFER_VIEW, size_t> D3D12GSRender::upload_inlined_vertex_array()
|
||||
{
|
||||
UINT offset = 0;
|
||||
m_IASet.clear();
|
||||
// Bind attributes
|
||||
for (int index = 0; index < rsx::limits::vertex_count; ++index)
|
||||
{
|
||||
const auto &info = vertex_arrays_info[index];
|
||||
|
||||
if (!info.size) // disabled
|
||||
continue;
|
||||
|
||||
D3D12_INPUT_ELEMENT_DESC IAElement = {};
|
||||
IAElement.SemanticName = "TEXCOORD";
|
||||
IAElement.SemanticIndex = (UINT)index;
|
||||
IAElement.InputSlot = 0;
|
||||
IAElement.Format = get_vertex_attribute_format(info.type, info.size);
|
||||
IAElement.AlignedByteOffset = offset;
|
||||
IAElement.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
IAElement.InstanceDataStepRate = 0;
|
||||
m_IASet.push_back(IAElement);
|
||||
|
||||
offset += rsx::get_vertex_type_size(info.type) * info.size;
|
||||
}
|
||||
|
||||
// Copy inline buffer
|
||||
size_t buffer_size = inline_vertex_array.size() * sizeof(int);
|
||||
assert(m_vertex_index_data.can_alloc(buffer_size));
|
||||
size_t heap_offset = m_vertex_index_data.alloc(buffer_size);
|
||||
void *buffer;
|
||||
CHECK_HRESULT(m_vertex_index_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
|
||||
void *mapped_buffer = (char*)buffer + heap_offset;
|
||||
write_inline_array_to_buffer(mapped_buffer);
|
||||
m_vertex_index_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view =
|
||||
{
|
||||
m_vertex_index_data.m_heap->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size,
|
||||
(UINT)offset
|
||||
};
|
||||
|
||||
return std::make_tuple(vertex_buffer_view, (u32)buffer_size / offset);
|
||||
}
|
||||
|
||||
std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> D3D12GSRender::generate_index_buffer_for_emulated_primitives_array(const std::vector<std::pair<u32, u32> > &vertex_ranges)
|
||||
{
|
||||
@@ -284,12 +277,9 @@ std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> D3D12GSRender::generate_index_buffer
|
||||
|
||||
// Alloc
|
||||
size_t buffer_size = align(index_count * sizeof(u16), 64);
|
||||
assert(m_vertex_index_data.can_alloc(buffer_size));
|
||||
size_t heap_offset = m_vertex_index_data.alloc(buffer_size);
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
void *buffer;
|
||||
CHECK_HRESULT(m_vertex_index_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
|
||||
void *mapped_buffer = (char*)buffer + heap_offset;
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
size_t first = 0;
|
||||
for (const auto &pair : vertex_ranges)
|
||||
{
|
||||
@@ -298,9 +288,9 @@ std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> D3D12GSRender::generate_index_buffer
|
||||
mapped_buffer = (char*)mapped_buffer + element_count * sizeof(u16);
|
||||
first += pair.second;
|
||||
}
|
||||
m_vertex_index_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
D3D12_INDEX_BUFFER_VIEW index_buffer_view = {
|
||||
m_vertex_index_data.m_heap->GetGPUVirtualAddress() + heap_offset,
|
||||
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size,
|
||||
DXGI_FORMAT_R16_UINT
|
||||
};
|
||||
@@ -308,84 +298,79 @@ std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> D3D12GSRender::generate_index_buffer
|
||||
return std::make_tuple(index_buffer_view, index_count);
|
||||
}
|
||||
|
||||
std::tuple<bool, size_t> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
|
||||
std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
|
||||
{
|
||||
if (draw_command == Draw_command::draw_command_inlined_array)
|
||||
if (draw_command == rsx::draw_command::inlined_array)
|
||||
{
|
||||
size_t vertex_count;
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view;
|
||||
std::tie(vertex_buffer_view, vertex_count) = upload_inlined_vertex_array();
|
||||
command_list->IASetVertexBuffers(0, (UINT)1, &vertex_buffer_view);
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_view;
|
||||
std::tie(vertex_buffer_view, vertex_count) = upload_inlined_vertex_array(
|
||||
vertex_arrays_info,
|
||||
{ (const gsl::byte*) inline_vertex_array.data(), gsl::narrow<int>(inline_vertex_array.size() * sizeof(uint)) },
|
||||
m_buffer_data, m_vertex_buffer_data.Get(), command_list);
|
||||
|
||||
if (is_primitive_native(draw_mode))
|
||||
return std::make_tuple(false, vertex_count);
|
||||
return std::make_tuple(false, vertex_count, vertex_buffer_view);
|
||||
|
||||
D3D12_INDEX_BUFFER_VIEW index_buffer_view;
|
||||
size_t index_count;
|
||||
std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array({ { 0, (u32)vertex_count } });
|
||||
command_list->IASetIndexBuffer(&index_buffer_view);
|
||||
return std::make_tuple(true, index_count);
|
||||
return std::make_tuple(true, index_count, vertex_buffer_view);
|
||||
}
|
||||
|
||||
if (draw_command == Draw_command::draw_command_array)
|
||||
if (draw_command == rsx::draw_command::array)
|
||||
{
|
||||
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertex_buffer_views = upload_vertex_attributes(m_first_count_pairs);
|
||||
command_list->IASetVertexBuffers(0, (UINT)vertex_buffer_views.size(), vertex_buffer_views.data());
|
||||
|
||||
if (is_primitive_native(draw_mode))
|
||||
{
|
||||
// Index count
|
||||
size_t vertex_count = 0;
|
||||
for (const auto &pair : m_first_count_pairs)
|
||||
vertex_count += pair.second;
|
||||
return std::make_tuple(false, vertex_count);
|
||||
size_t vertex_count = get_vertex_count(first_count_commands);
|
||||
return std::make_tuple(false, vertex_count, upload_vertex_attributes(first_count_commands, command_list));
|
||||
}
|
||||
|
||||
D3D12_INDEX_BUFFER_VIEW index_buffer_view;
|
||||
size_t index_count;
|
||||
std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array(m_first_count_pairs);
|
||||
std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array(first_count_commands);
|
||||
command_list->IASetIndexBuffer(&index_buffer_view);
|
||||
return std::make_tuple(true, index_count);
|
||||
return std::make_tuple(true, index_count, upload_vertex_attributes(first_count_commands, command_list));
|
||||
}
|
||||
|
||||
assert(draw_command == Draw_command::draw_command_indexed);
|
||||
|
||||
u32 indexed_type = rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4;
|
||||
size_t index_size = get_index_type_size(indexed_type);
|
||||
assert(draw_command == rsx::draw_command::indexed);
|
||||
|
||||
// Index count
|
||||
size_t index_count = 0;
|
||||
for (const auto &pair : m_first_count_pairs)
|
||||
index_count += get_index_count(draw_mode, pair.second);
|
||||
size_t index_count = get_index_count(draw_mode, gsl::narrow<int>(get_vertex_count(first_count_commands)));
|
||||
|
||||
rsx::index_array_type indexed_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
size_t index_size = get_index_type_size(indexed_type);
|
||||
|
||||
// Alloc
|
||||
size_t buffer_size = align(index_count * index_size, 64);
|
||||
assert(m_vertex_index_data.can_alloc(buffer_size));
|
||||
size_t heap_offset = m_vertex_index_data.alloc(buffer_size);
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
void *buffer;
|
||||
CHECK_HRESULT(m_vertex_index_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), (void**)&buffer));
|
||||
void *mapped_buffer = (char*)buffer + heap_offset;
|
||||
u32 min_index = (u32)-1, max_index = 0;
|
||||
for (const auto &pair : m_first_count_pairs)
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
u32 min_index, max_index;
|
||||
|
||||
if (indexed_type == rsx::index_array_type::u16)
|
||||
{
|
||||
size_t element_count = get_index_count(draw_mode, pair.second);
|
||||
write_index_array_data_to_buffer((char*)mapped_buffer, draw_mode, pair.first, pair.second, min_index, max_index);
|
||||
mapped_buffer = (char*)mapped_buffer + element_count * index_size;
|
||||
gsl::span<u16> dst = { (u16*)mapped_buffer, gsl::narrow<int>(buffer_size / index_size) };
|
||||
std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, draw_mode, first_count_commands);
|
||||
}
|
||||
m_vertex_index_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
if (indexed_type == rsx::index_array_type::u32)
|
||||
{
|
||||
gsl::span<u32> dst = { (u32*)mapped_buffer, gsl::narrow<int>(buffer_size / index_size) };
|
||||
std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, draw_mode, first_count_commands);
|
||||
}
|
||||
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
D3D12_INDEX_BUFFER_VIEW index_buffer_view = {
|
||||
m_vertex_index_data.m_heap->GetGPUVirtualAddress() + heap_offset,
|
||||
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size,
|
||||
get_index_type(indexed_type)
|
||||
};
|
||||
m_timers.m_buffer_upload_size += buffer_size;
|
||||
m_timers.buffer_upload_size += buffer_size;
|
||||
command_list->IASetIndexBuffer(&index_buffer_view);
|
||||
|
||||
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertex_buffer_views = upload_vertex_attributes({ std::make_pair(0, max_index + 1) });
|
||||
command_list->IASetVertexBuffers(0, (UINT)vertex_buffer_views.size(), vertex_buffer_views.data());
|
||||
|
||||
return std::make_tuple(true, index_count);
|
||||
return std::make_tuple(true, index_count, upload_vertex_attributes({ std::make_pair(0, max_index + 1) }, command_list));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,14 +42,30 @@ std::string getFunctionImp(FUNCTION f)
|
||||
return "float4(1., 1., 1., 1.)";
|
||||
case FUNCTION::FUNCTION_FRACT:
|
||||
return "frac($0)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D:
|
||||
return "$t.Sample($tsampler, $0.x)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ:
|
||||
return "$t.Sample($tsampler, ($0.x / $0.w))";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD:
|
||||
return "$t.SampleLevel($tsampler, $0.x, $1)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D:
|
||||
return "$t.Sample($tsampler, $0.xy * $t_scale)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ:
|
||||
return "$t.Sample($tsampler, ($0.xy / $0.z) * $t_scale)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ:
|
||||
return "$t.Sample($tsampler, ($0.xy / $0.w) * $t_scale)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD:
|
||||
return "$t.SampleLevel($tsampler, $0.xy * $t_scale, $1)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE:
|
||||
return "$t.Sample($tsampler, $0.xyz)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ:
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ:
|
||||
return "$t.Sample($tsampler, ($0.xyz / $0.w))";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD:
|
||||
return "$t.SampleLevel($tsampler, $0.xyz, $1)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D:
|
||||
return "$t.Sample($tsampler, $0.xyz)";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ:
|
||||
return "$t.Sample($tsampler, ($0.xyz / $0.w))";
|
||||
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD:
|
||||
return "$t.SampleLevel($tsampler, $0.xyz, $1)";
|
||||
case FUNCTION::FUNCTION_DFDX:
|
||||
return "ddx($0)";
|
||||
case FUNCTION::FUNCTION_DFDY:
|
||||
@@ -77,4 +93,40 @@ std::string compareFunctionImp(COMPARE f, const std::string &Op0, const std::str
|
||||
return "(" + Op0 + " != " + Op1 + ")";
|
||||
}
|
||||
}
|
||||
|
||||
void insert_d3d12_legacy_function(std::ostream& OS)
|
||||
{
|
||||
OS << "float4 divsq_legacy(float4 num, float4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return num / sqrt(max(denum.xxxx, 1.E-10));\n";
|
||||
OS << "}\n";
|
||||
|
||||
OS << "float4 rcp_legacy(float4 denum)\n";
|
||||
OS << "{\n";
|
||||
OS << " return 1. / denum;\n";
|
||||
OS << "}\n";
|
||||
|
||||
OS << "float4 rsq_legacy(float4 val)\n";
|
||||
OS << "{\n";
|
||||
OS << " return float(1.0 / sqrt(max(val.x, 1.E-10))).xxxx;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "float4 log2_legacy(float4 val)\n";
|
||||
OS << "{\n";
|
||||
OS << " return log2(max(val.x, 1.E-10)).xxxx;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "float4 lit_legacy(float4 val)";
|
||||
OS << "{\n";
|
||||
OS << " float4 clamped_val = val;\n";
|
||||
OS << " clamped_val.x = max(val.x, 0);\n";
|
||||
OS << " clamped_val.y = max(val.y, 0);\n";
|
||||
OS << " float4 result;\n";
|
||||
OS << " result.x = 1.0;\n";
|
||||
OS << " result.w = 1.;\n";
|
||||
OS << " result.y = clamped_val.x;\n";
|
||||
OS << " result.z = clamped_val.x > 0.0 ? exp(clamped_val.w * log(max(clamped_val.y, 1.E-10))) : 0.0;\n";
|
||||
OS << " return result;\n";
|
||||
OS << "}\n\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5,3 +5,5 @@
|
||||
std::string getFloatTypeNameImp(size_t elementCount);
|
||||
std::string getFunctionImp(FUNCTION f);
|
||||
std::string compareFunctionImp(COMPARE f, const std::string &Op0, const std::string &Op1);
|
||||
|
||||
void insert_d3d12_legacy_function(std::ostream&);
|
||||
|
||||
@@ -248,6 +248,7 @@ namespace
|
||||
{
|
||||
case CELL_GCM_TEXTURE_NEAREST: return D3D12_FILTER_TYPE_POINT;
|
||||
case CELL_GCM_TEXTURE_LINEAR: return D3D12_FILTER_TYPE_LINEAR;
|
||||
case CELL_GCM_TEXTURE_CONVOLUTION_MAG: return D3D12_FILTER_TYPE_LINEAR;
|
||||
}
|
||||
throw EXCEPTION("Invalid mag filter (0x%x)", mag_filter);
|
||||
}
|
||||
@@ -261,92 +262,99 @@ D3D12_FILTER get_texture_filter(u8 min_filter, u8 mag_filter)
|
||||
return D3D12_ENCODE_BASIC_FILTER(min, mag, mip, D3D12_FILTER_REDUCTION_TYPE_STANDARD);
|
||||
}
|
||||
|
||||
D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(u8 draw_mode)
|
||||
D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(rsx::primitive_type draw_mode)
|
||||
{
|
||||
switch (draw_mode)
|
||||
{
|
||||
case CELL_GCM_PRIMITIVE_POINTS: return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||||
case CELL_GCM_PRIMITIVE_LINES: return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||
case CELL_GCM_PRIMITIVE_LINE_LOOP: return D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
|
||||
case CELL_GCM_PRIMITIVE_LINE_STRIP: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLES: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case CELL_GCM_PRIMITIVE_QUADS: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case CELL_GCM_PRIMITIVE_QUAD_STRIP: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case CELL_GCM_PRIMITIVE_POLYGON: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::points: return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||||
case rsx::primitive_type::lines: return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||
case rsx::primitive_type::line_loop: return D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
|
||||
case rsx::primitive_type::line_strip: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
|
||||
case rsx::primitive_type::triangles: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::triangle_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
case rsx::primitive_type::triangle_fan: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::quads: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::quad_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::polygon: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
}
|
||||
throw EXCEPTION("Invalid draw mode (0x%x)", draw_mode);
|
||||
}
|
||||
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(u8 draw_mode)
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(rsx::primitive_type draw_mode)
|
||||
{
|
||||
switch (draw_mode)
|
||||
{
|
||||
case CELL_GCM_PRIMITIVE_POINTS: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
|
||||
case CELL_GCM_PRIMITIVE_LINES: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case CELL_GCM_PRIMITIVE_LINE_STRIP: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLES: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case CELL_GCM_PRIMITIVE_QUADS: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case CELL_GCM_PRIMITIVE_QUAD_STRIP: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case CELL_GCM_PRIMITIVE_POLYGON: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case CELL_GCM_PRIMITIVE_LINE_LOOP: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case rsx::primitive_type::points: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
|
||||
case rsx::primitive_type::lines: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case rsx::primitive_type::line_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case rsx::primitive_type::triangles: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::triangle_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::triangle_fan: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::quads: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::quad_strip: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::polygon: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
case rsx::primitive_type::line_loop: return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
}
|
||||
throw EXCEPTION("Invalid or unsupported draw mode (0x%x)", draw_mode);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_color_surface_format(u8 format)
|
||||
DXGI_FORMAT get_color_surface_format(rsx::surface_color_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_R5G6B5: return DXGI_FORMAT_B5G6R5_UNORM;
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8: return DXGI_FORMAT_B8G8R8X8_UNORM; //BIT.TRIP Runner2 use this
|
||||
case CELL_GCM_SURFACE_A8R8G8B8: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case CELL_GCM_SURFACE_F_X32: return DXGI_FORMAT_R32_FLOAT;
|
||||
case CELL_GCM_SURFACE_A8B8G8R8: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case rsx::surface_color_format::r5g6b5: return DXGI_FORMAT_B5G6R5_UNORM;
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
return DXGI_FORMAT_B8G8R8X8_UNORM; //BIT.TRIP Runner2 use this
|
||||
case rsx::surface_color_format::a8b8g8r8:
|
||||
case rsx::surface_color_format::a8r8g8b8: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case rsx::surface_color_format::b8: return DXGI_FORMAT_R8_UNORM;
|
||||
case rsx::surface_color_format::g8b8: return DXGI_FORMAT_R8G8_UNORM;
|
||||
case rsx::surface_color_format::w16z16y16x16: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case rsx::surface_color_format::w32z32y32x32: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
case rsx::surface_color_format::x32: return DXGI_FORMAT_R32_FLOAT;
|
||||
}
|
||||
throw EXCEPTION("Invalid format (0x%x)", format);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_depth_stencil_surface_format(u8 format)
|
||||
DXGI_FORMAT get_depth_stencil_surface_format(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return DXGI_FORMAT_D16_UNORM;
|
||||
case CELL_GCM_SURFACE_Z24S8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
case rsx::surface_depth_format::z16: return DXGI_FORMAT_D16_UNORM;
|
||||
case rsx::surface_depth_format::z24s8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
}
|
||||
throw EXCEPTION("Invalid format (0x%x)", format);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_depth_stencil_surface_clear_format(u8 format)
|
||||
DXGI_FORMAT get_depth_stencil_surface_clear_format(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return DXGI_FORMAT_D16_UNORM;
|
||||
case CELL_GCM_SURFACE_Z24S8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
case rsx::surface_depth_format::z16: return DXGI_FORMAT_D16_UNORM;
|
||||
case rsx::surface_depth_format::z24s8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
}
|
||||
throw EXCEPTION("Invalid format (0x%x)", format);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_depth_stencil_typeless_surface_format(u8 format)
|
||||
DXGI_FORMAT get_depth_stencil_typeless_surface_format(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return DXGI_FORMAT_R16_TYPELESS;
|
||||
case CELL_GCM_SURFACE_Z24S8: return DXGI_FORMAT_R24G8_TYPELESS;
|
||||
case rsx::surface_depth_format::z16: return DXGI_FORMAT_R16_TYPELESS;
|
||||
case rsx::surface_depth_format::z24s8: return DXGI_FORMAT_R24G8_TYPELESS;
|
||||
}
|
||||
throw EXCEPTION("Invalid format (0x%x)", format);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_depth_samplable_surface_format(u8 format)
|
||||
DXGI_FORMAT get_depth_samplable_surface_format(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return DXGI_FORMAT_R16_FLOAT;
|
||||
case CELL_GCM_SURFACE_Z24S8: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
|
||||
case rsx::surface_depth_format::z16: return DXGI_FORMAT_R16_UNORM;
|
||||
case rsx::surface_depth_format::z24s8: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
|
||||
}
|
||||
throw EXCEPTION("Invalid format (0x%x)", format);
|
||||
}
|
||||
@@ -362,21 +370,21 @@ BOOL get_front_face_ccw(u32 ffv)
|
||||
throw EXCEPTION("Invalid front face value (0x%x)", ffv);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_index_type(u8 index_type)
|
||||
DXGI_FORMAT get_index_type(rsx::index_array_type index_type)
|
||||
{
|
||||
switch (index_type)
|
||||
{
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: return DXGI_FORMAT_R16_UINT;
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: return DXGI_FORMAT_R32_UINT;
|
||||
case rsx::index_array_type::u16: return DXGI_FORMAT_R16_UINT;
|
||||
case rsx::index_array_type::u32: return DXGI_FORMAT_R32_UINT;
|
||||
}
|
||||
throw EXCEPTION("Invalid index_type (0x%x)", index_type);
|
||||
}
|
||||
|
||||
DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size)
|
||||
DXGI_FORMAT get_vertex_attribute_format(rsx::vertex_base_type type, u8 size)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case CELL_GCM_VERTEX_S1:
|
||||
case rsx::vertex_base_type::s1:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -387,7 +395,7 @@ DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_GCM_VERTEX_F:
|
||||
case rsx::vertex_base_type::f:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -398,7 +406,7 @@ DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_GCM_VERTEX_SF:
|
||||
case rsx::vertex_base_type::sf:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -409,7 +417,7 @@ DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_GCM_VERTEX_UB:
|
||||
case rsx::vertex_base_type::ub:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -420,7 +428,7 @@ DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_GCM_VERTEX_S32K:
|
||||
case rsx::vertex_base_type::s32k:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
@@ -431,18 +439,18 @@ DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_GCM_VERTEX_CMP:
|
||||
case rsx::vertex_base_type::cmp:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 1: return DXGI_FORMAT_R32_FLOAT;
|
||||
case 2: return DXGI_FORMAT_R32G32_FLOAT;
|
||||
case 3: return DXGI_FORMAT_R32G32B32_FLOAT;
|
||||
case 4: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
case 1: return DXGI_FORMAT_R16G16B16A16_SNORM;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4: throw EXCEPTION("Unsupported CMP vertex format with size > 1");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CELL_GCM_VERTEX_UB256:
|
||||
case rsx::vertex_base_type::ub256:
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
|
||||
@@ -56,37 +56,37 @@ D3D12_FILTER get_texture_filter(u8 min_filter, u8 mag_filter);
|
||||
/**
|
||||
* Convert draw mode to D3D12_PRIMITIVE_TOPOLOGY
|
||||
*/
|
||||
D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(u8 draw_mode);
|
||||
D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(rsx::primitive_type draw_mode);
|
||||
|
||||
/**
|
||||
* Convert draw mode to D3D12_PRIMITIVE_TOPOLOGY_TYPE
|
||||
*/
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(u8 draw_mode);
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE get_primitive_topology_type(rsx::primitive_type draw_mode);
|
||||
|
||||
/**
|
||||
* Convert color surface format to DXGI_FORMAT
|
||||
*/
|
||||
DXGI_FORMAT get_color_surface_format(u8 format);
|
||||
DXGI_FORMAT get_color_surface_format(rsx::surface_color_format format);
|
||||
|
||||
/**
|
||||
* Convert depth stencil surface format to DXGI_FORMAT
|
||||
*/
|
||||
DXGI_FORMAT get_depth_stencil_surface_format(u8 format);
|
||||
DXGI_FORMAT get_depth_stencil_surface_format(rsx::surface_depth_format format);
|
||||
|
||||
/**
|
||||
*Convert depth stencil surface format to DXGI_FORMAT suited for clear value
|
||||
*/
|
||||
DXGI_FORMAT get_depth_stencil_surface_clear_format(u8 format);
|
||||
DXGI_FORMAT get_depth_stencil_surface_clear_format(rsx::surface_depth_format format);
|
||||
|
||||
/**
|
||||
* Convert depth surface format to a typeless DXGI_FORMAT
|
||||
*/
|
||||
DXGI_FORMAT get_depth_stencil_typeless_surface_format(u8 format);
|
||||
DXGI_FORMAT get_depth_stencil_typeless_surface_format(rsx::surface_depth_format format);
|
||||
|
||||
/**
|
||||
* Convert depth surface format to a DXGI_FORMAT that can be depth sampled
|
||||
*/
|
||||
DXGI_FORMAT get_depth_samplable_surface_format(u8 format);
|
||||
DXGI_FORMAT get_depth_samplable_surface_format(rsx::surface_depth_format format);
|
||||
|
||||
/**
|
||||
* Convert front face value to bool value telling wheter front face is counterclockwise or not
|
||||
@@ -96,12 +96,12 @@ BOOL get_front_face_ccw(u32 set_front_face_value);
|
||||
/**
|
||||
* Convert index type to DXGI_FORMAT
|
||||
*/
|
||||
DXGI_FORMAT get_index_type(u8 index_type);
|
||||
DXGI_FORMAT get_index_type(rsx::index_array_type index_type);
|
||||
|
||||
/**
|
||||
* Convert vertex attribute format and size to DXGI_FORMAT
|
||||
*/
|
||||
DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size);
|
||||
DXGI_FORMAT get_vertex_attribute_format(rsx::vertex_base_type type, u8 size);
|
||||
|
||||
/**
|
||||
* Convert scissor register value to D3D12_RECT
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
D3D12FragmentDecompiler::D3D12FragmentDecompiler(u32 addr, u32& size, u32 ctrl, const std::vector<texture_dimension> &texture_dimensions) :
|
||||
FragmentProgramDecompiler(addr, size, ctrl, texture_dimensions)
|
||||
D3D12FragmentDecompiler::D3D12FragmentDecompiler(const RSXFragmentProgram &prog, u32& size) :
|
||||
FragmentProgramDecompiler(prog, size)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -39,22 +39,6 @@ void D3D12FragmentDecompiler::insertHeader(std::stringstream & OS)
|
||||
OS << " float4x4 scaleOffsetMat;" << std::endl;
|
||||
OS << " int isAlphaTested;" << std::endl;
|
||||
OS << " float alphaRef;" << std::endl;
|
||||
OS << " int tex0_is_unorm;" << std::endl;
|
||||
OS << " int tex1_is_unorm;" << std::endl;
|
||||
OS << " int tex2_is_unorm;" << std::endl;
|
||||
OS << " int tex3_is_unorm;" << std::endl;
|
||||
OS << " int tex4_is_unorm;" << std::endl;
|
||||
OS << " int tex5_is_unorm;" << std::endl;
|
||||
OS << " int tex6_is_unorm;" << std::endl;
|
||||
OS << " int tex7_is_unorm;" << std::endl;
|
||||
OS << " int tex8_is_unorm;" << std::endl;
|
||||
OS << " int tex9_is_unorm;" << std::endl;
|
||||
OS << " int tex10_is_unorm;" << std::endl;
|
||||
OS << " int tex11_is_unorm;" << std::endl;
|
||||
OS << " int tex12_is_unorm;" << std::endl;
|
||||
OS << " int tex13_is_unorm;" << std::endl;
|
||||
OS << " int tex14_is_unorm;" << std::endl;
|
||||
OS << " int tex15_is_unorm;" << std::endl;
|
||||
OS << "};" << std::endl;
|
||||
}
|
||||
|
||||
@@ -107,32 +91,50 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS)
|
||||
{
|
||||
OS << "cbuffer CONSTANT : register(b2)" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
{
|
||||
if (PT.type == "sampler2D" || PT.type == "samplerCube")
|
||||
if (PT.type == "sampler1D" || PT.type == "sampler2D" || PT.type == "samplerCube" || PT.type == "sampler3D")
|
||||
continue;
|
||||
for (ParamItem PI : PT.items)
|
||||
for (const ParamItem &PI : PT.items)
|
||||
OS << " " << PT.type << " " << PI.name << ";" << std::endl;
|
||||
}
|
||||
OS << "};" << std::endl << std::endl;
|
||||
|
||||
for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
{
|
||||
if (PT.type == "sampler2D")
|
||||
if (PT.type == "sampler1D")
|
||||
{
|
||||
for (ParamItem PI : PT.items)
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
size_t textureIndex = atoi(PI.name.data() + 3);
|
||||
OS << "Texture2D " << PI.name << " : register(t" << textureIndex << ");" << std::endl;
|
||||
OS << "Texture1D " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
|
||||
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
else if (PT.type == "sampler2D")
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
size_t textureIndex = atoi(PI.name.data() + 3);
|
||||
OS << "Texture2D " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
|
||||
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
else if (PT.type == "sampler3D")
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
size_t textureIndex = atoi(PI.name.data() + 3);
|
||||
OS << "Texture3D " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
|
||||
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
else if (PT.type == "samplerCube")
|
||||
{
|
||||
for (ParamItem PI : PT.items)
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
size_t textureIndex = atoi(PI.name.data() + 3);
|
||||
OS << "TextureCube " << PI.name << " : register(t" << textureIndex << ");" << std::endl;
|
||||
OS << "TextureCube " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
|
||||
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -141,39 +143,64 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS)
|
||||
|
||||
void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS)
|
||||
{
|
||||
insert_d3d12_legacy_function(OS);
|
||||
|
||||
const std::set<std::string> output_value =
|
||||
{
|
||||
"r0", "r1", "r2", "r3", "r4",
|
||||
"h0", "h4", "h6", "h8"
|
||||
"h0", "h2", "h4", "h6", "h8"
|
||||
};
|
||||
OS << "void ps_impl(PixelInput In, inout float4 r0, inout float4 h0, inout float4 r1, inout float4 r2, inout float4 h4, inout float4 r3, inout float4 h6, inout float4 r4, inout float4 h8)" << std::endl;
|
||||
OS << "void ps_impl(bool is_front_face, PixelInput In, inout float4 r0, inout float4 h0, inout float4 r1, inout float4 h2, inout float4 r2, inout float4 h4, inout float4 r3, inout float4 h6, inout float4 r4, inout float4 h8)" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
for (ParamType PT : m_parr.params[PF_PARAM_IN])
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_IN])
|
||||
{
|
||||
for (ParamItem PI : PT.items)
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
if (m_prog.front_back_color_enabled)
|
||||
{
|
||||
if (PI.name == "spec_color" && m_prog.back_color_specular_output)
|
||||
{
|
||||
OS << " float4 spec_color = is_front_face ? In.dst_reg4 : In.spec_color;\n";
|
||||
continue;
|
||||
}
|
||||
if (PI.name == "diff_color" && m_prog.back_color_diffuse_output)
|
||||
{
|
||||
OS << " float4 diff_color = is_front_face ? In.dst_reg3 : In.diff_color;\n";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
|
||||
}
|
||||
}
|
||||
// A bit unclean, but works.
|
||||
OS << " " << "float4 gl_Position = In.Position;" << std::endl;
|
||||
OS << " " << "float4 gl_FragCoord = In.Position;" << std::endl;
|
||||
if (m_prog.origin_mode == rsx::window_origin::bottom)
|
||||
OS << " gl_FragCoord.y = (" << std::to_string(m_prog.height) << " - gl_FragCoord.y);\n";
|
||||
// Declare output
|
||||
for (ParamType PT : m_parr.params[PF_PARAM_NONE])
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_NONE])
|
||||
{
|
||||
for (ParamItem PI : PT.items)
|
||||
for (const ParamItem &PI : PT.items)
|
||||
if (output_value.find(PI.name) == output_value.end())
|
||||
OS << " " << PT.type << " " << PI.name << " = float4(0., 0., 0., 0.);" << std::endl;
|
||||
}
|
||||
// Declare texture coordinate scaling component (to handle unormalized texture coordinates)
|
||||
|
||||
for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
{
|
||||
if (PT.type != "sampler2D")
|
||||
continue;
|
||||
for (const ParamItem& PI : PT.items)
|
||||
{
|
||||
size_t textureIndex = atoi(PI.name.data() + 3);
|
||||
bool is_unorm = !!(m_prog.unnormalized_coords & (1 << textureIndex));
|
||||
if (!is_unorm)
|
||||
{
|
||||
OS << " float2 " << PI.name << "_scale = float2(1., 1.);" << std::endl;
|
||||
continue;
|
||||
}
|
||||
OS << " float2 " << PI.name << "_dim;" << std::endl;
|
||||
OS << " " << PI.name << ".GetDimensions(" << PI.name << "_dim.x, " << PI.name << "_dim.y);" << std::endl;
|
||||
OS << " float2 " << PI.name << "_scale = (!!" << PI.name << "_is_unorm) ? float2(1., 1.) / " << PI.name << "_dim : float2(1., 1.);" << std::endl;
|
||||
OS << " float2 " << PI.name << "_scale = float2(1., 1.) / " << PI.name << "_dim;" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,7 +209,7 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS)
|
||||
{
|
||||
OS << "}" << std::endl;
|
||||
OS << std::endl;
|
||||
OS << "PixelOutput main(PixelInput In)" << std::endl;
|
||||
OS << "PixelOutput main(PixelInput In, bool is_front_face : SV_IsFrontFace)" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
OS << " float4 r0 = float4(0., 0., 0., 0.);" << std::endl;
|
||||
OS << " float4 r1 = float4(0., 0., 0., 0.);" << std::endl;
|
||||
@@ -194,7 +221,7 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS)
|
||||
OS << " float4 h4 = float4(0., 0., 0., 0.);" << std::endl;
|
||||
OS << " float4 h6 = float4(0., 0., 0., 0.);" << std::endl;
|
||||
OS << " float4 h8 = float4(0., 0., 0., 0.);" << std::endl;
|
||||
OS << " ps_impl(In, r0, h0, r1, r2, h4, r3, h6, r4, h8);" << std::endl;
|
||||
OS << " ps_impl(is_front_face, In, r0, h0, r1, h2, r2, h4, r3, h6, r4, h8);" << std::endl;
|
||||
|
||||
const std::pair<std::string, std::string> table[] =
|
||||
{
|
||||
@@ -204,21 +231,52 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS)
|
||||
{ "ocol3", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r4" : "h8" },
|
||||
};
|
||||
|
||||
size_t num_output = 0;
|
||||
std::string first_output_name;
|
||||
OS << " PixelOutput Out = (PixelOutput)0;" << std::endl;
|
||||
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
|
||||
{
|
||||
if (m_parr.HasParam(PF_PARAM_NONE, "float4", table[i].second))
|
||||
{
|
||||
OS << " Out." << table[i].first << " = " << table[i].second << ";" << std::endl;
|
||||
num_output++;
|
||||
if (first_output_name.empty()) first_output_name = table[i].first;
|
||||
}
|
||||
}
|
||||
if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT)
|
||||
OS << " Out.depth = " << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "r1.z;" : "h0.z;") << std::endl;
|
||||
{
|
||||
/**
|
||||
* Note: Naruto Shippuden : Ultimate Ninja Storm 2 sets CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS in a shader
|
||||
* but it writes depth in r1.z and not h2.z.
|
||||
* Maybe there's a different flag for depth ?
|
||||
*/
|
||||
// OS << " Out.depth = " << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "r1.z;" : "h2.z;") << std::endl;
|
||||
OS << " Out.depth = r1.z;\n";
|
||||
}
|
||||
// Shaders don't always output colors (for instance if they write to depth only)
|
||||
if (num_output > 0)
|
||||
OS << " if (isAlphaTested && Out.ocol0.a <= alphaRef) discard;" << std::endl;
|
||||
if (!first_output_name.empty())
|
||||
{
|
||||
switch (m_prog.alpha_func)
|
||||
{
|
||||
case rsx::comparaison_function::equal:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a != alphaRef) discard;\n";
|
||||
break;
|
||||
case rsx::comparaison_function::not_equal:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a == alphaRef) discard;\n";
|
||||
break;
|
||||
case rsx::comparaison_function::less_or_equal:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a > alphaRef) discard;\n";
|
||||
break;
|
||||
case rsx::comparaison_function::less:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a >= alphaRef) discard;\n";
|
||||
break;
|
||||
case rsx::comparaison_function::greater:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a <= alphaRef) discard;\n";
|
||||
break;
|
||||
case rsx::comparaison_function::greater_or_equal:
|
||||
OS << " if (isAlphaTested && Out." << first_output_name << ".a < alphaRef) discard;\n";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
OS << " return Out;" << std::endl;
|
||||
OS << "}" << std::endl;
|
||||
}
|
||||
|
||||
@@ -20,5 +20,5 @@ protected:
|
||||
virtual void insertMainStart(std::stringstream &OS) override;
|
||||
virtual void insertMainEnd(std::stringstream &OS) override;
|
||||
public:
|
||||
D3D12FragmentDecompiler(u32 addr, u32& size, u32 ctrl, const std::vector<texture_dimension> &texture_dimensions);
|
||||
D3D12FragmentDecompiler(const RSXFragmentProgram &prog, u32& size);
|
||||
};
|
||||
|
||||
@@ -58,17 +58,15 @@ void wait_for_command_queue(ID3D12Device *device, ID3D12CommandQueue *command_qu
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12GSRender::Shader::Release()
|
||||
void D3D12GSRender::shader::release()
|
||||
{
|
||||
m_PSO->Release();
|
||||
m_rootSignature->Release();
|
||||
m_vertexBuffer->Release();
|
||||
m_textureDescriptorHeap->Release();
|
||||
m_samplerDescriptorHeap->Release();
|
||||
pso->Release();
|
||||
root_signature->Release();
|
||||
vertex_buffer->Release();
|
||||
texture_descriptor_heap->Release();
|
||||
sampler_descriptor_heap->Release();
|
||||
}
|
||||
|
||||
extern std::function<bool(u32 addr)> gfxHandler;
|
||||
|
||||
bool D3D12GSRender::invalidate_address(u32 addr)
|
||||
{
|
||||
bool result = false;
|
||||
@@ -87,19 +85,8 @@ D3D12DLLManagement::~D3D12DLLManagement()
|
||||
}
|
||||
|
||||
D3D12GSRender::D3D12GSRender()
|
||||
: GSRender(frame_type::DX12), m_d3d12_lib(), m_current_pso(nullptr)
|
||||
: GSRender(frame_type::DX12), m_d3d12_lib(), m_current_pso({})
|
||||
{
|
||||
m_previous_address_a = 0;
|
||||
m_previous_address_b = 0;
|
||||
m_previous_address_c = 0;
|
||||
m_previous_address_d = 0;
|
||||
m_previous_address_z = 0;
|
||||
gfxHandler = [this](u32 addr) {
|
||||
bool result = invalidate_address(addr);
|
||||
if (result)
|
||||
LOG_WARNING(RSX, "Reporting Cell writing to 0x%x", addr);
|
||||
return result;
|
||||
};
|
||||
if (rpcs3::config.rsx.d3d12.debug_output.value())
|
||||
{
|
||||
Microsoft::WRL::ComPtr<ID3D12Debug> debugInterface;
|
||||
@@ -118,10 +105,10 @@ D3D12GSRender::D3D12GSRender()
|
||||
D3D12_COMMAND_QUEUE_DESC graphic_queue_desc = { D3D12_COMMAND_LIST_TYPE_DIRECT };
|
||||
CHECK_HRESULT(m_device->CreateCommandQueue(&graphic_queue_desc, IID_PPV_ARGS(m_command_queue.GetAddressOf())));
|
||||
|
||||
g_descriptor_stride_srv_cbv_uav = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
g_descriptor_stride_dsv = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
||||
g_descriptor_stride_rtv = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
g_descriptor_stride_samplers = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
m_descriptor_stride_srv_cbv_uav = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
m_descriptor_stride_dsv = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
||||
m_descriptor_stride_rtv = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
m_descriptor_stride_samplers = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
|
||||
// Create swap chain and put them in a descriptor heap as rendertarget
|
||||
DXGI_SWAP_CHAIN_DESC swap_chain = {};
|
||||
@@ -148,33 +135,43 @@ D3D12GSRender::D3D12GSRender()
|
||||
m_device->CreateRenderTargetView(m_backbuffer[1].Get(), &renter_target_view_desc, m_backbuffer_descriptor_heap[1]->GetCPUDescriptorHandleForHeapStart());
|
||||
|
||||
// Common root signatures
|
||||
for (unsigned texture_count = 0; texture_count < 17; texture_count++)
|
||||
for (int vertex_buffer_count = 0; vertex_buffer_count < 17; vertex_buffer_count++) // Some app (naruto ultimate ninja storm 2) uses a shader without inputs...
|
||||
{
|
||||
CD3DX12_DESCRIPTOR_RANGE descriptorRange[] =
|
||||
for (unsigned texture_count = 0; texture_count < 17; texture_count++)
|
||||
{
|
||||
// Scale Offset data
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0),
|
||||
// Constants
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 2, 1),
|
||||
// Textures
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture_count, 0),
|
||||
// Samplers
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, texture_count, 0),
|
||||
};
|
||||
CD3DX12_ROOT_PARAMETER RP[2];
|
||||
RP[0].InitAsDescriptorTable((texture_count > 0) ? 3 : 2, &descriptorRange[0]);
|
||||
RP[1].InitAsDescriptorTable(1, &descriptorRange[3]);
|
||||
CD3DX12_DESCRIPTOR_RANGE descriptorRange[] =
|
||||
{
|
||||
// Vertex buffer
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, vertex_buffer_count, 0),
|
||||
// Scale Offset data
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0),
|
||||
// Constants
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 2, 1),
|
||||
// Textures
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture_count, 16),
|
||||
// Samplers
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, texture_count, 0),
|
||||
};
|
||||
CD3DX12_ROOT_PARAMETER RP[2];
|
||||
UINT cbv_srv_uav_descriptor_size = 4;
|
||||
if (texture_count == 0)
|
||||
cbv_srv_uav_descriptor_size -= 1;
|
||||
if (vertex_buffer_count == 0)
|
||||
cbv_srv_uav_descriptor_size -= 1;
|
||||
RP[0].InitAsDescriptorTable(cbv_srv_uav_descriptor_size, (vertex_buffer_count > 0) ? &descriptorRange[0] : &descriptorRange[1]);
|
||||
RP[1].InitAsDescriptorTable(1, &descriptorRange[4]);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> rootSignatureBlob;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
|
||||
CHECK_HRESULT(wrapD3D12SerializeRootSignature(
|
||||
&CD3DX12_ROOT_SIGNATURE_DESC((texture_count > 0) ? 2 : 1, RP, 0, 0, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT),
|
||||
D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob));
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> rootSignatureBlob;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
|
||||
CHECK_HRESULT(wrapD3D12SerializeRootSignature(
|
||||
&CD3DX12_ROOT_SIGNATURE_DESC((texture_count > 0) ? 2 : 1, RP, 0, 0),
|
||||
D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob));
|
||||
|
||||
m_device->CreateRootSignature(0,
|
||||
rootSignatureBlob->GetBufferPointer(),
|
||||
rootSignatureBlob->GetBufferSize(),
|
||||
IID_PPV_ARGS(m_root_signatures[texture_count].GetAddressOf()));
|
||||
m_device->CreateRootSignature(0,
|
||||
rootSignatureBlob->GetBufferPointer(),
|
||||
rootSignatureBlob->GetBufferSize(),
|
||||
IID_PPV_ARGS(m_root_signatures[texture_count][vertex_buffer_count].GetAddressOf()));
|
||||
}
|
||||
}
|
||||
|
||||
m_per_frame_storage[0].init(m_device.Get());
|
||||
@@ -182,8 +179,8 @@ D3D12GSRender::D3D12GSRender()
|
||||
m_per_frame_storage[1].init(m_device.Get());
|
||||
m_per_frame_storage[1].reset();
|
||||
|
||||
initConvertShader();
|
||||
m_output_scaling_pass.Init(m_device.Get(), m_command_queue.Get());
|
||||
init_convert_shader();
|
||||
m_output_scaling_pass.init(m_device.Get(), m_command_queue.Get());
|
||||
|
||||
CHECK_HRESULT(
|
||||
m_device->CreateCommittedResource(
|
||||
@@ -195,14 +192,20 @@ D3D12GSRender::D3D12GSRender()
|
||||
IID_PPV_ARGS(&m_dummy_texture))
|
||||
);
|
||||
|
||||
m_readback_resources.init(m_device.Get(), 1024 * 1024 * 128, D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
m_uav_heap.init(m_device.Get(), 1024 * 1024 * 128, D3D12_HEAP_TYPE_DEFAULT, D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES);
|
||||
|
||||
m_rtts.init(m_device.Get());
|
||||
m_readback_resources.init(m_device.Get(), 1024 * 1024 * 128, D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
m_buffer_data.init(m_device.Get(), 1024 * 1024 * 896, D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ);
|
||||
|
||||
m_constants_data.init(m_device.Get(), 1024 * 1024 * 64, D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ);
|
||||
m_vertex_index_data.init(m_device.Get(), 1024 * 1024 * 384, D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ);
|
||||
m_texture_upload_data.init(m_device.Get(), 1024 * 1024 * 512, D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ);
|
||||
CHECK_HRESULT(
|
||||
m_device->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(1024 * 1024 * 16),
|
||||
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(m_vertex_buffer_data.GetAddressOf())
|
||||
)
|
||||
);
|
||||
|
||||
if (rpcs3::config.rsx.d3d12.overlay.value())
|
||||
init_d2d_structures();
|
||||
@@ -214,18 +217,12 @@ D3D12GSRender::~D3D12GSRender()
|
||||
|
||||
m_texture_cache.unprotect_all();
|
||||
|
||||
gfxHandler = [this](u32) { return false; };
|
||||
m_constants_data.release();
|
||||
m_vertex_index_data.release();
|
||||
m_texture_upload_data.release();
|
||||
m_uav_heap.m_heap->Release();
|
||||
m_readback_resources.m_heap->Release();
|
||||
m_dummy_texture->Release();
|
||||
m_convertPSO->Release();
|
||||
m_convertRootSignature->Release();
|
||||
m_convert_pso->Release();
|
||||
m_convert_root_signature->Release();
|
||||
m_per_frame_storage[0].release();
|
||||
m_per_frame_storage[1].release();
|
||||
m_output_scaling_pass.Release();
|
||||
m_output_scaling_pass.release();
|
||||
|
||||
release_d2d_structures();
|
||||
}
|
||||
@@ -261,68 +258,93 @@ void D3D12GSRender::end()
|
||||
prepare_render_targets(get_current_resource_storage().command_list.Get());
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> rtt_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_prepare_rtt_duration += std::chrono::duration_cast<std::chrono::microseconds>(rtt_duration_end - rtt_duration_start).count();
|
||||
m_timers.prepare_rtt_duration += std::chrono::duration_cast<std::chrono::microseconds>(rtt_duration_end - rtt_duration_start).count();
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> vertex_index_duration_start = std::chrono::system_clock::now();
|
||||
|
||||
size_t currentDescriptorIndex = get_current_resource_storage().descriptors_heap_index;
|
||||
|
||||
size_t vertex_count;
|
||||
bool indexed_draw;
|
||||
std::tie(indexed_draw, vertex_count) = upload_and_set_vertex_index_data(get_current_resource_storage().command_list.Get());
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_views;
|
||||
std::tie(indexed_draw, vertex_count, vertex_buffer_views) = upload_and_set_vertex_index_data(get_current_resource_storage().command_list.Get());
|
||||
|
||||
size_t vertex_buffer_count = vertex_buffer_views.size();
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> vertex_index_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_vertex_index_duration += std::chrono::duration_cast<std::chrono::microseconds>(vertex_index_duration_end - vertex_index_duration_start).count();
|
||||
m_timers.vertex_index_duration += std::chrono::duration_cast<std::chrono::microseconds>(vertex_index_duration_end - vertex_index_duration_start).count();
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> program_load_start = std::chrono::system_clock::now();
|
||||
load_program();
|
||||
std::chrono::time_point<std::chrono::system_clock> program_load_end = std::chrono::system_clock::now();
|
||||
m_timers.m_program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
|
||||
m_timers.program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
|
||||
|
||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_root_signatures[std::get<2>(*m_current_pso)].Get());
|
||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_root_signatures[std::get<2>(m_current_pso)][vertex_buffer_count].Get());
|
||||
get_current_resource_storage().command_list->OMSetStencilRef(rsx::method_registers[NV4097_SET_STENCIL_FUNC_REF]);
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> constants_duration_start = std::chrono::system_clock::now();
|
||||
|
||||
size_t currentDescriptorIndex = get_current_resource_storage().descriptors_heap_index;
|
||||
INT offset = 0;
|
||||
for (const auto view : vertex_buffer_views)
|
||||
{
|
||||
m_device->CreateShaderResourceView(m_vertex_buffer_data.Get(), &view,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)currentDescriptorIndex + offset++, m_descriptor_stride_srv_cbv_uav));
|
||||
}
|
||||
|
||||
// Constants
|
||||
upload_and_bind_scale_offset_matrix(currentDescriptorIndex);
|
||||
upload_and_bind_vertex_shader_constants(currentDescriptorIndex + 1);
|
||||
upload_and_bind_fragment_shader_constants(currentDescriptorIndex + 2);
|
||||
upload_and_bind_scale_offset_matrix(currentDescriptorIndex + vertex_buffer_count);
|
||||
upload_and_bind_vertex_shader_constants(currentDescriptorIndex + 1 + vertex_buffer_count);
|
||||
upload_and_bind_fragment_shader_constants(currentDescriptorIndex + 2 + vertex_buffer_count);
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> constants_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_constants_duration += std::chrono::duration_cast<std::chrono::microseconds>(constants_duration_end - constants_duration_start).count();
|
||||
m_timers.constants_duration += std::chrono::duration_cast<std::chrono::microseconds>(constants_duration_end - constants_duration_start).count();
|
||||
|
||||
get_current_resource_storage().command_list->SetPipelineState(std::get<0>(*m_current_pso));
|
||||
get_current_resource_storage().command_list->SetPipelineState(std::get<0>(m_current_pso).Get());
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> texture_duration_start = std::chrono::system_clock::now();
|
||||
if (std::get<2>(*m_current_pso) > 0)
|
||||
size_t texture_count = std::get<2>(m_current_pso);
|
||||
if (texture_count > 0)
|
||||
{
|
||||
upload_and_bind_textures(get_current_resource_storage().command_list.Get(), currentDescriptorIndex + 3, std::get<2>(*m_current_pso) > 0);
|
||||
upload_and_bind_textures(get_current_resource_storage().command_list.Get(), texture_count);
|
||||
|
||||
for (unsigned i = 0; i < texture_count; i++)
|
||||
{
|
||||
ID3D12Resource *tex_resource;
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srv;
|
||||
std::tie(tex_resource, srv) = m_current_shader_resources[i];
|
||||
m_device->CreateShaderResourceView(tex_resource, &srv,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)currentDescriptorIndex + 3 + (INT)vertex_buffer_count + (INT)i, m_descriptor_stride_srv_cbv_uav)
|
||||
);
|
||||
m_device->CreateSampler(&m_current_samplers[i],
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().sampler_descriptor_heap[get_current_resource_storage().sampler_descriptors_heap_index]->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((UINT)get_current_resource_storage().current_sampler_index + (UINT)i, m_descriptor_stride_samplers));
|
||||
}
|
||||
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetGPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)currentDescriptorIndex, g_descriptor_stride_srv_cbv_uav)
|
||||
.Offset((INT)currentDescriptorIndex, m_descriptor_stride_srv_cbv_uav)
|
||||
);
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(1,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(get_current_resource_storage().sampler_descriptor_heap[get_current_resource_storage().sampler_descriptors_heap_index]->GetGPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().current_sampler_index, g_descriptor_stride_samplers)
|
||||
.Offset((INT)get_current_resource_storage().current_sampler_index, m_descriptor_stride_samplers)
|
||||
);
|
||||
|
||||
get_current_resource_storage().current_sampler_index += std::get<2>(*m_current_pso);
|
||||
get_current_resource_storage().descriptors_heap_index += std::get<2>(*m_current_pso) + 3;
|
||||
get_current_resource_storage().current_sampler_index += std::get<2>(m_current_pso);
|
||||
get_current_resource_storage().descriptors_heap_index += std::get<2>(m_current_pso) + 3 + vertex_buffer_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
get_current_resource_storage().command_list->SetDescriptorHeaps(1, get_current_resource_storage().descriptors_heap.GetAddressOf());
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetGPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)currentDescriptorIndex, g_descriptor_stride_srv_cbv_uav)
|
||||
.Offset((INT)currentDescriptorIndex, m_descriptor_stride_srv_cbv_uav)
|
||||
);
|
||||
get_current_resource_storage().descriptors_heap_index += 3;
|
||||
get_current_resource_storage().descriptors_heap_index += 3 + vertex_buffer_count;
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> texture_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_texture_duration += std::chrono::duration_cast<std::chrono::microseconds>(texture_duration_end - texture_duration_start).count();
|
||||
m_timers.texture_duration += std::chrono::duration_cast<std::chrono::microseconds>(texture_duration_end - texture_duration_start).count();
|
||||
set_rtt_and_ds(get_current_resource_storage().command_list.Get());
|
||||
|
||||
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
@@ -348,10 +370,9 @@ void D3D12GSRender::end()
|
||||
else
|
||||
get_current_resource_storage().command_list->DrawInstanced((UINT)vertex_count, 1, 0, 0);
|
||||
|
||||
vertex_index_array.clear();
|
||||
std::chrono::time_point<std::chrono::system_clock> end_duration = std::chrono::system_clock::now();
|
||||
m_timers.m_draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(end_duration - start_duration).count();
|
||||
m_timers.m_draw_calls_count++;
|
||||
m_timers.draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(end_duration - start_duration).count();
|
||||
m_timers.draw_calls_count++;
|
||||
|
||||
if (rpcs3::config.rsx.d3d12.debug_output.value())
|
||||
{
|
||||
@@ -359,26 +380,25 @@ void D3D12GSRender::end()
|
||||
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
|
||||
get_current_resource_storage().set_new_command_list();
|
||||
}
|
||||
m_first_count_pairs.clear();
|
||||
thread::end();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool is_flip_surface_in_global_memory(u32 color_target)
|
||||
bool is_flip_surface_in_global_memory(rsx::surface_target color_target)
|
||||
{
|
||||
switch (color_target)
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
case CELL_GCM_SURFACE_TARGET_1:
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1:
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2:
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3:
|
||||
case rsx::surface_target::surface_a:
|
||||
case rsx::surface_target::surface_b:
|
||||
case rsx::surface_target::surfaces_a_b:
|
||||
case rsx::surface_target::surfaces_a_b_c:
|
||||
case rsx::surface_target::surfaces_a_b_c_d:
|
||||
return true;
|
||||
case CELL_GCM_SURFACE_TARGET_NONE:
|
||||
case rsx::surface_target::none:
|
||||
return false;
|
||||
}
|
||||
throw EXCEPTION("Wrong color_target (%u)", color_target);
|
||||
throw EXCEPTION("Wrong color_target");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,7 +407,7 @@ void D3D12GSRender::flip(int buffer)
|
||||
ID3D12Resource *resource_to_flip;
|
||||
float viewport_w, viewport_h;
|
||||
|
||||
if (!is_flip_surface_in_global_memory(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
if (!is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
|
||||
{
|
||||
resource_storage &storage = get_current_resource_storage();
|
||||
assert(storage.ram_framebuffer == nullptr);
|
||||
@@ -405,15 +425,12 @@ void D3D12GSRender::flip(int buffer)
|
||||
|
||||
row_pitch = align(w * 4, 256);
|
||||
size_t texture_size = row_pitch * h; // * 4 for mipmap levels
|
||||
assert(m_texture_upload_data.can_alloc(texture_size));
|
||||
size_t heap_offset = m_texture_upload_data.alloc(texture_size);
|
||||
size_t heap_offset = m_buffer_data.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(texture_size);
|
||||
|
||||
void *buffer;
|
||||
CHECK_HRESULT(m_texture_upload_data.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + texture_size), &buffer));
|
||||
void *mapped_buffer = (char*)buffer + heap_offset;
|
||||
void *mapped_buffer = m_buffer_data.map<void>(heap_offset);
|
||||
for (unsigned row = 0; row < h; row++)
|
||||
memcpy((char*)mapped_buffer + row * row_pitch, (char*)src_buffer + row * w * 4, w * 4);
|
||||
m_texture_upload_data.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + texture_size));
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + texture_size));
|
||||
offset = heap_offset;
|
||||
}
|
||||
|
||||
@@ -428,7 +445,7 @@ void D3D12GSRender::flip(int buffer)
|
||||
)
|
||||
);
|
||||
get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(storage.ram_framebuffer.Get(), 0), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(m_texture_upload_data.m_heap, { offset, { DXGI_FORMAT_R8G8B8A8_UNORM, (UINT)w, (UINT)h, 1, (UINT)row_pitch } }), nullptr);
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(m_buffer_data.get_heap(), { offset, { DXGI_FORMAT_R8G8B8A8_UNORM, (UINT)w, (UINT)h, 1, (UINT)row_pitch } }), nullptr);
|
||||
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(storage.ram_framebuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
resource_to_flip = storage.ram_framebuffer.Get();
|
||||
@@ -436,15 +453,15 @@ void D3D12GSRender::flip(int buffer)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_rtts.bound_render_targets[0] != nullptr)
|
||||
if (std::get<1>(m_rtts.m_bound_render_targets[0]) != nullptr)
|
||||
{
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_render_targets[0], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
resource_to_flip = m_rtts.bound_render_targets[0];
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_render_targets[0]), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
resource_to_flip = std::get<1>(m_rtts.m_bound_render_targets[0]);
|
||||
}
|
||||
else if (m_rtts.bound_render_targets[1] != nullptr)
|
||||
else if (std::get<1>(m_rtts.m_bound_render_targets[1]) != nullptr)
|
||||
{
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_render_targets[1], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
resource_to_flip = m_rtts.bound_render_targets[1];
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_render_targets[1]), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
resource_to_flip = std::get<1>(m_rtts.m_bound_render_targets[1]);
|
||||
}
|
||||
else
|
||||
resource_to_flip = nullptr;
|
||||
@@ -471,15 +488,15 @@ void D3D12GSRender::flip(int buffer)
|
||||
(LONG)m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()]->GetDesc().Height,
|
||||
};
|
||||
get_current_resource_storage().command_list->RSSetScissorRects(1, &box);
|
||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_output_scaling_pass.m_rootSignature);
|
||||
get_current_resource_storage().command_list->SetPipelineState(m_output_scaling_pass.m_PSO);
|
||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_output_scaling_pass.root_signature);
|
||||
get_current_resource_storage().command_list->SetPipelineState(m_output_scaling_pass.pso);
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shader_resource_view_desc = {};
|
||||
// FIXME: Not always true
|
||||
shader_resource_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
shader_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
shader_resource_view_desc.Texture2D.MipLevels = 1;
|
||||
if (is_flip_surface_in_global_memory(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
if (is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
|
||||
shader_resource_view_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
else
|
||||
shader_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||
@@ -489,7 +506,7 @@ void D3D12GSRender::flip(int buffer)
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0
|
||||
);
|
||||
m_device->CreateShaderResourceView(resource_to_flip, &shader_resource_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.m_textureDescriptorHeap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), g_descriptor_stride_srv_cbv_uav));
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.texture_descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_srv_cbv_uav));
|
||||
|
||||
D3D12_SAMPLER_DESC sampler_desc = {};
|
||||
sampler_desc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
||||
@@ -497,24 +514,24 @@ void D3D12GSRender::flip(int buffer)
|
||||
sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
m_device->CreateSampler(&sampler_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.m_samplerDescriptorHeap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), g_descriptor_stride_samplers));
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.sampler_descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_samplers));
|
||||
|
||||
ID3D12DescriptorHeap *descriptors_heaps[] =
|
||||
{
|
||||
m_output_scaling_pass.m_textureDescriptorHeap,
|
||||
m_output_scaling_pass.m_samplerDescriptorHeap
|
||||
m_output_scaling_pass.texture_descriptor_heap,
|
||||
m_output_scaling_pass.sampler_descriptor_heap
|
||||
};
|
||||
get_current_resource_storage().command_list->SetDescriptorHeaps(2, descriptors_heaps);
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.m_textureDescriptorHeap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), g_descriptor_stride_srv_cbv_uav));
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.texture_descriptor_heap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_srv_cbv_uav));
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(1,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.m_samplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), g_descriptor_stride_samplers));
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.sampler_descriptor_heap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_samplers));
|
||||
|
||||
get_current_resource_storage().command_list->OMSetRenderTargets(1,
|
||||
&CD3DX12_CPU_DESCRIPTOR_HANDLE(m_backbuffer_descriptor_heap[m_swap_chain->GetCurrentBackBufferIndex()]->GetCPUDescriptorHandleForHeapStart()),
|
||||
true, nullptr);
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view = {};
|
||||
vertex_buffer_view.BufferLocation = m_output_scaling_pass.m_vertexBuffer->GetGPUVirtualAddress();
|
||||
vertex_buffer_view.BufferLocation = m_output_scaling_pass.vertex_buffer->GetGPUVirtualAddress();
|
||||
vertex_buffer_view.StrideInBytes = 4 * sizeof(float);
|
||||
vertex_buffer_view.SizeInBytes = 16 * sizeof(float);
|
||||
get_current_resource_storage().command_list->IASetVertexBuffers(0, 1, &vertex_buffer_view);
|
||||
@@ -524,7 +541,7 @@ void D3D12GSRender::flip(int buffer)
|
||||
|
||||
if (!rpcs3::config.rsx.d3d12.overlay.value())
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
|
||||
if (is_flip_surface_in_global_memory(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]) && resource_to_flip != nullptr)
|
||||
if (is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])) && resource_to_flip != nullptr)
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(resource_to_flip, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET));
|
||||
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
|
||||
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
|
||||
@@ -546,15 +563,14 @@ void D3D12GSRender::flip(int buffer)
|
||||
storage.fence_value++;
|
||||
|
||||
storage.in_use = true;
|
||||
storage.dirty_textures.merge(m_rtts.invalidated_resources);
|
||||
m_rtts.invalidated_resources.clear();
|
||||
|
||||
// Get the put pos - 1. This way after cleaning we can set the get ptr to
|
||||
// this value, allowing heap to proceed even if we cleant before allocating
|
||||
// a new value (that's the reason of the -1)
|
||||
storage.constants_heap_get_pos = m_constants_data.get_current_put_pos_minus_one();
|
||||
storage.vertex_index_heap_get_pos = m_vertex_index_data.get_current_put_pos_minus_one();
|
||||
storage.texture_upload_heap_get_pos = m_texture_upload_data.get_current_put_pos_minus_one();
|
||||
storage.buffer_heap_get_pos = m_buffer_data.get_current_put_pos_minus_one();
|
||||
storage.readback_heap_get_pos = m_readback_resources.get_current_put_pos_minus_one();
|
||||
storage.uav_heap_get_pos = m_uav_heap.get_current_put_pos_minus_one();
|
||||
|
||||
// Now get ready for next frame
|
||||
resource_storage &new_storage = get_current_resource_storage();
|
||||
@@ -562,31 +578,44 @@ void D3D12GSRender::flip(int buffer)
|
||||
new_storage.wait_and_clean();
|
||||
if (new_storage.in_use)
|
||||
{
|
||||
m_constants_data.m_get_pos = new_storage.constants_heap_get_pos;
|
||||
m_vertex_index_data.m_get_pos = new_storage.vertex_index_heap_get_pos;
|
||||
m_texture_upload_data.m_get_pos = new_storage.texture_upload_heap_get_pos;
|
||||
m_buffer_data.m_get_pos = new_storage.buffer_heap_get_pos;
|
||||
m_readback_resources.m_get_pos = new_storage.readback_heap_get_pos;
|
||||
m_uav_heap.m_get_pos = new_storage.uav_heap_get_pos;
|
||||
}
|
||||
|
||||
m_frame->flip(nullptr);
|
||||
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> flip_end = std::chrono::system_clock::now();
|
||||
m_timers.m_flip_duration += std::chrono::duration_cast<std::chrono::microseconds>(flip_end - flip_start).count();
|
||||
m_timers.flip_duration += std::chrono::duration_cast<std::chrono::microseconds>(flip_end - flip_start).count();
|
||||
}
|
||||
|
||||
bool D3D12GSRender::on_access_violation(u32 address, bool is_writing)
|
||||
{
|
||||
if (!is_writing)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (invalidate_address(address))
|
||||
{
|
||||
LOG_WARNING(RSX, "Reporting Cell writing to 0x%x", address);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void D3D12GSRender::reset_timer()
|
||||
{
|
||||
m_timers.m_draw_calls_count = 0;
|
||||
m_timers.m_draw_calls_duration = 0;
|
||||
m_timers.m_prepare_rtt_duration = 0;
|
||||
m_timers.m_vertex_index_duration = 0;
|
||||
m_timers.m_buffer_upload_size = 0;
|
||||
m_timers.m_program_load_duration = 0;
|
||||
m_timers.m_constants_duration = 0;
|
||||
m_timers.m_texture_duration = 0;
|
||||
m_timers.m_flip_duration = 0;
|
||||
m_timers.draw_calls_count = 0;
|
||||
m_timers.draw_calls_duration = 0;
|
||||
m_timers.prepare_rtt_duration = 0;
|
||||
m_timers.vertex_index_duration = 0;
|
||||
m_timers.buffer_upload_size = 0;
|
||||
m_timers.program_load_duration = 0;
|
||||
m_timers.constants_duration = 0;
|
||||
m_timers.texture_duration = 0;
|
||||
m_timers.flip_duration = 0;
|
||||
}
|
||||
|
||||
resource_storage& D3D12GSRender::get_current_resource_storage()
|
||||
|
||||
@@ -56,7 +56,7 @@ private:
|
||||
ComPtr<ID3D12Resource> m_backbuffer[2];
|
||||
ComPtr<ID3D12DescriptorHeap> m_backbuffer_descriptor_heap[2];
|
||||
// m_rootSignatures[N] is RS with N texture/sample
|
||||
ComPtr<ID3D12RootSignature> m_root_signatures[17];
|
||||
ComPtr<ID3D12RootSignature> m_root_signatures[17][17]; // indexed by [texture count][vertex count]
|
||||
|
||||
// TODO: Use a tree structure to parse more efficiently
|
||||
data_cache m_texture_cache;
|
||||
@@ -64,89 +64,81 @@ private:
|
||||
|
||||
rsx::surface_info m_surface;
|
||||
|
||||
RSXVertexProgram vertex_program;
|
||||
RSXFragmentProgram fragment_program;
|
||||
RSXVertexProgram m_vertex_program;
|
||||
RSXFragmentProgram m_fragment_program;
|
||||
PipelineStateObjectCache m_pso_cache;
|
||||
std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> *m_current_pso;
|
||||
std::tuple<ComPtr<ID3D12PipelineState>, size_t, size_t> m_current_pso;
|
||||
|
||||
struct
|
||||
{
|
||||
size_t m_draw_calls_duration;
|
||||
size_t m_draw_calls_count;
|
||||
size_t m_prepare_rtt_duration;
|
||||
size_t m_vertex_index_duration;
|
||||
size_t m_buffer_upload_size;
|
||||
size_t m_program_load_duration;
|
||||
size_t m_constants_duration;
|
||||
size_t m_texture_duration;
|
||||
size_t m_flip_duration;
|
||||
size_t draw_calls_duration;
|
||||
size_t draw_calls_count;
|
||||
size_t prepare_rtt_duration;
|
||||
size_t vertex_index_duration;
|
||||
size_t buffer_upload_size;
|
||||
size_t program_load_duration;
|
||||
size_t constants_duration;
|
||||
size_t texture_duration;
|
||||
size_t flip_duration;
|
||||
} m_timers;
|
||||
|
||||
void reset_timer();
|
||||
|
||||
struct Shader
|
||||
struct shader
|
||||
{
|
||||
ID3D12PipelineState *m_PSO;
|
||||
ID3D12RootSignature *m_rootSignature;
|
||||
ID3D12Resource *m_vertexBuffer;
|
||||
ID3D12DescriptorHeap *m_textureDescriptorHeap;
|
||||
ID3D12DescriptorHeap *m_samplerDescriptorHeap;
|
||||
void Init(ID3D12Device *device, ID3D12CommandQueue *gfxcommandqueue);
|
||||
void Release();
|
||||
ID3D12PipelineState *pso;
|
||||
ID3D12RootSignature *root_signature;
|
||||
ID3D12Resource *vertex_buffer;
|
||||
ID3D12DescriptorHeap *texture_descriptor_heap;
|
||||
ID3D12DescriptorHeap *sampler_descriptor_heap;
|
||||
void init(ID3D12Device *device, ID3D12CommandQueue *gfx_command_queue);
|
||||
void release();
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores data related to the scaling pass that turns internal
|
||||
* render targets into presented buffers.
|
||||
*/
|
||||
Shader m_output_scaling_pass;
|
||||
shader m_output_scaling_pass;
|
||||
|
||||
/**
|
||||
* Data used when depth buffer is converted to uchar textures.
|
||||
*/
|
||||
ID3D12PipelineState *m_convertPSO;
|
||||
ID3D12RootSignature *m_convertRootSignature;
|
||||
void initConvertShader();
|
||||
ID3D12PipelineState *m_convert_pso;
|
||||
ID3D12RootSignature *m_convert_root_signature;
|
||||
void init_convert_shader();
|
||||
|
||||
resource_storage m_per_frame_storage[2];
|
||||
resource_storage &get_current_resource_storage();
|
||||
resource_storage &get_non_current_resource_storage();
|
||||
|
||||
// Constants storage
|
||||
data_heap<ID3D12Resource, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT> m_constants_data;
|
||||
// Vertex storage
|
||||
data_heap<ID3D12Resource, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT> m_vertex_index_data;
|
||||
// Texture storage
|
||||
data_heap<ID3D12Resource, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT> m_texture_upload_data;
|
||||
data_heap<ID3D12Heap, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT> m_uav_heap;
|
||||
data_heap<ID3D12Resource, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT> m_readback_resources;
|
||||
// Textures, constants, index and vertex buffers storage
|
||||
data_heap m_buffer_data;
|
||||
data_heap m_readback_resources;
|
||||
ComPtr<ID3D12Resource> m_vertex_buffer_data;
|
||||
|
||||
render_targets m_rtts;
|
||||
rsx::render_targets m_rtts;
|
||||
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> m_IASet;
|
||||
|
||||
INT g_descriptor_stride_srv_cbv_uav;
|
||||
INT g_descriptor_stride_dsv;
|
||||
INT g_descriptor_stride_rtv;
|
||||
INT g_descriptor_stride_samplers;
|
||||
INT m_descriptor_stride_srv_cbv_uav;
|
||||
INT m_descriptor_stride_dsv;
|
||||
INT m_descriptor_stride_rtv;
|
||||
INT m_descriptor_stride_samplers;
|
||||
|
||||
// Used to fill unused texture slot
|
||||
ID3D12Resource *m_dummy_texture;
|
||||
|
||||
// Store previous fbo addresses to detect RTT config changes.
|
||||
u32 m_previous_address_a;
|
||||
u32 m_previous_address_b;
|
||||
u32 m_previous_address_c;
|
||||
u32 m_previous_address_d;
|
||||
u32 m_previous_address_z;
|
||||
// Currently used shader resources / samplers descriptor
|
||||
std::array<std::tuple<ID3D12Resource*, D3D12_SHADER_RESOURCE_VIEW_DESC>, 16> m_current_shader_resources = {};
|
||||
std::array<D3D12_SAMPLER_DESC, 16> m_current_samplers = {};
|
||||
public:
|
||||
D3D12GSRender();
|
||||
virtual ~D3D12GSRender();
|
||||
|
||||
private:
|
||||
void init_d2d_structures();
|
||||
void release_d2d_structures();
|
||||
|
||||
bool load_program();
|
||||
void load_program();
|
||||
|
||||
void set_rtt_and_ds(ID3D12GraphicsCommandList *command_list);
|
||||
|
||||
@@ -155,17 +147,15 @@ private:
|
||||
* Non native primitive type are emulated by index buffers expansion.
|
||||
* Returns whether the draw call is indexed or not and the vertex count to draw.
|
||||
*/
|
||||
std::tuple<bool, size_t> upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list);
|
||||
std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> > upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list);
|
||||
|
||||
std::vector<std::pair<u32, u32> > m_first_count_pairs;
|
||||
/**
|
||||
* Upload all enabled vertex attributes for vertex in ranges described by vertex_ranges.
|
||||
* A range in vertex_range is a pair whose first element is the index of the beginning of the
|
||||
* range, and whose second element is the number of vertex in this range.
|
||||
*/
|
||||
std::vector<D3D12_VERTEX_BUFFER_VIEW> upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges);
|
||||
|
||||
std::tuple<D3D12_VERTEX_BUFFER_VIEW, size_t> upload_inlined_vertex_array();
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges,
|
||||
gsl::not_null<ID3D12GraphicsCommandList*> command_list);
|
||||
|
||||
std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> generate_index_buffer_for_emulated_primitives_array(const std::vector<std::pair<u32, u32> > &vertex_ranges);
|
||||
|
||||
@@ -178,7 +168,7 @@ private:
|
||||
* Create necessary resource view/sampler descriptors in the per frame storage struct.
|
||||
* If the count of enabled texture is below texture_count, fills with dummy texture and sampler.
|
||||
*/
|
||||
void upload_and_bind_textures(ID3D12GraphicsCommandList *command_list, size_t descriptor_index, size_t texture_count);
|
||||
void upload_and_bind_textures(ID3D12GraphicsCommandList *command_list, size_t texture_count);
|
||||
|
||||
/**
|
||||
* Creates render target if necessary.
|
||||
@@ -206,11 +196,9 @@ protected:
|
||||
virtual void end() override;
|
||||
virtual void flip(int buffer) override;
|
||||
|
||||
virtual void load_vertex_data(u32 first, u32 count) override;
|
||||
virtual void load_vertex_index_data(u32 first, u32 count) override;
|
||||
virtual bool on_access_violation(u32 address, bool is_writing) override;
|
||||
|
||||
virtual void copy_render_targets_to_memory(void *buffer, u8 rtt) override;
|
||||
virtual void copy_depth_buffer_to_memory(void *buffer) override;
|
||||
virtual void copy_stencil_buffer_to_memory(void *buffer) override;
|
||||
virtual std::array<std::vector<gsl::byte>, 4> copy_render_targets_to_memory() override;
|
||||
virtual std::array<std::vector<gsl::byte>, 2> copy_depth_stencil_buffer_to_memory() override;
|
||||
virtual std::pair<std::string, std::string> get_programs() const override;
|
||||
};
|
||||
|
||||
@@ -4,18 +4,19 @@
|
||||
#include "D3D12MemoryHelpers.h"
|
||||
|
||||
|
||||
void data_cache::store_and_protect_data(u64 key, u32 start, size_t size, u8 format, size_t w, size_t h, size_t m, ComPtr<ID3D12Resource> data)
|
||||
void data_cache::store_and_protect_data(u64 key, u32 start, size_t size, u8 format, size_t w, size_t h, size_t d, size_t m, ComPtr<ID3D12Resource> data)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mut);
|
||||
m_address_to_data[key] = std::make_pair(texture_entry(format, w, h, m), data);
|
||||
m_address_to_data[key] = std::make_pair(texture_entry(format, w, h, d, m), data);
|
||||
protect_data(key, start, size);
|
||||
}
|
||||
|
||||
void data_cache::protect_data(u64 key, u32 start, size_t size)
|
||||
{
|
||||
/// align start to 4096 byte
|
||||
u32 protected_range_start = align(start, 4096);
|
||||
u32 protected_range_size = (u32)align(size, 4096);
|
||||
static const u32 memory_page_size = 4096;
|
||||
u32 protected_range_start = start & ~(memory_page_size - 1);
|
||||
u32 protected_range_size = (u32)align(size, memory_page_size);
|
||||
m_protected_ranges.push_back(std::make_tuple(key, protected_range_start, protected_range_size));
|
||||
vm::page_protect(protected_range_start, protected_range_size, 0, 0, vm::page_writable);
|
||||
}
|
||||
@@ -105,7 +106,7 @@ void resource_storage::init(ID3D12Device *device)
|
||||
CHECK_HRESULT(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, command_allocator.Get(), nullptr, IID_PPV_ARGS(command_list.GetAddressOf())));
|
||||
CHECK_HRESULT(command_list->Close());
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC descriptor_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 10000, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
|
||||
D3D12_DESCRIPTOR_HEAP_DESC descriptor_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 50000, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
|
||||
CHECK_HRESULT(device->CreateDescriptorHeap(&descriptor_heap_desc, IID_PPV_ARGS(&descriptors_heap)));
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC sampler_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER , 2048, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
|
||||
|
||||
@@ -3,48 +3,6 @@
|
||||
#include "d3dx12.h"
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct init_heap
|
||||
{
|
||||
static T* init(ID3D12Device *device, size_t heapSize, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct init_heap<ID3D12Heap>
|
||||
{
|
||||
static ID3D12Heap* init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags)
|
||||
{
|
||||
ID3D12Heap *result;
|
||||
D3D12_HEAP_DESC heap_desc = {};
|
||||
heap_desc.SizeInBytes = heap_size;
|
||||
heap_desc.Properties.Type = type;
|
||||
heap_desc.Flags = flags;
|
||||
CHECK_HRESULT(device->CreateHeap(&heap_desc, IID_PPV_ARGS(&result)));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct init_heap<ID3D12Resource>
|
||||
{
|
||||
static ID3D12Resource* init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, D3D12_RESOURCE_STATES state)
|
||||
{
|
||||
ID3D12Resource *result;
|
||||
D3D12_HEAP_PROPERTIES heap_properties = {};
|
||||
heap_properties.Type = type;
|
||||
CHECK_HRESULT(device->CreateCommittedResource(&heap_properties,
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(heap_size),
|
||||
state,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&result))
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper around a ID3D12Resource or a ID3D12Heap.
|
||||
* Acts as a ring buffer : hold a get and put pointers,
|
||||
@@ -52,43 +10,30 @@ struct init_heap<ID3D12Resource>
|
||||
* and get is used as beginning of in use data space.
|
||||
* This wrapper checks that put pointer doesn't cross get one.
|
||||
*/
|
||||
template<typename T, size_t alignment>
|
||||
struct data_heap
|
||||
class data_heap
|
||||
{
|
||||
T *m_heap;
|
||||
size_t m_size;
|
||||
size_t m_put_pos; // Start of free space
|
||||
size_t m_get_pos; // End of free space
|
||||
|
||||
template <typename... arg_type>
|
||||
void init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, arg_type... args)
|
||||
{
|
||||
m_size = heap_size;
|
||||
m_heap = init_heap<T>::init(device, heap_size, type, args...);
|
||||
m_put_pos = 0;
|
||||
m_get_pos = heap_size - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does alloc cross get position ?
|
||||
*/
|
||||
template<int Alignement>
|
||||
bool can_alloc(size_t size) const
|
||||
{
|
||||
size_t alloc_size = align(size, alignment);
|
||||
if (m_put_pos + alloc_size < m_size)
|
||||
size_t alloc_size = align(size, Alignement);
|
||||
size_t aligned_put_pos = align(m_put_pos, Alignement);
|
||||
if (aligned_put_pos + alloc_size < m_size)
|
||||
{
|
||||
// range before get
|
||||
if (m_put_pos + alloc_size < m_get_pos)
|
||||
if (aligned_put_pos + alloc_size < m_get_pos)
|
||||
return true;
|
||||
// range after get
|
||||
if (m_put_pos > m_get_pos)
|
||||
if (aligned_put_pos > m_get_pos)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ..]....[..get..
|
||||
if (m_put_pos < m_get_pos)
|
||||
if (aligned_put_pos < m_get_pos)
|
||||
return false;
|
||||
// ..get..]...[...
|
||||
// Actually all resources extending beyond heap space starts at 0
|
||||
@@ -98,15 +43,45 @@ struct data_heap
|
||||
}
|
||||
}
|
||||
|
||||
size_t m_size;
|
||||
size_t m_put_pos; // Start of free space
|
||||
ComPtr<ID3D12Resource> m_heap;
|
||||
public:
|
||||
data_heap() = default;
|
||||
~data_heap() = default;
|
||||
data_heap(const data_heap&) = delete;
|
||||
data_heap(data_heap&&) = delete;
|
||||
|
||||
size_t m_get_pos; // End of free space
|
||||
|
||||
template <typename... arg_type>
|
||||
void init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, D3D12_RESOURCE_STATES state)
|
||||
{
|
||||
m_size = heap_size;
|
||||
m_put_pos = 0;
|
||||
m_get_pos = heap_size - 1;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heap_properties = {};
|
||||
heap_properties.Type = type;
|
||||
CHECK_HRESULT(device->CreateCommittedResource(&heap_properties,
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(heap_size),
|
||||
state,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(m_heap.GetAddressOf()))
|
||||
);
|
||||
}
|
||||
|
||||
template<int Alignement>
|
||||
size_t alloc(size_t size)
|
||||
{
|
||||
assert(can_alloc(size));
|
||||
size_t alloc_size = align(size, alignment);
|
||||
if (m_put_pos + alloc_size < m_size)
|
||||
if (!can_alloc<Alignement>(size)) throw EXCEPTION("Working buffer not big enough");
|
||||
size_t alloc_size = align(size, Alignement);
|
||||
size_t aligned_put_pos = align(m_put_pos, Alignement);
|
||||
if (aligned_put_pos + alloc_size < m_size)
|
||||
{
|
||||
size_t old_put_pos = m_put_pos;
|
||||
m_put_pos += alloc_size;
|
||||
return old_put_pos;
|
||||
m_put_pos = aligned_put_pos + alloc_size;
|
||||
return aligned_put_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -115,9 +90,37 @@ struct data_heap
|
||||
}
|
||||
}
|
||||
|
||||
void release()
|
||||
template<typename T>
|
||||
T* map(const D3D12_RANGE &range)
|
||||
{
|
||||
m_heap->Release();
|
||||
void *buffer;
|
||||
CHECK_HRESULT(m_heap->Map(0, &range, &buffer));
|
||||
void *mapped_buffer = (char*)buffer + range.Begin;
|
||||
return static_cast<T*>(mapped_buffer);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* map(size_t heap_offset)
|
||||
{
|
||||
void *buffer;
|
||||
CHECK_HRESULT(m_heap->Map(0, nullptr, &buffer));
|
||||
void *mapped_buffer = (char*)buffer + heap_offset;
|
||||
return static_cast<T*>(mapped_buffer);
|
||||
}
|
||||
|
||||
void unmap(const D3D12_RANGE &range)
|
||||
{
|
||||
m_heap->Unmap(0, &range);
|
||||
}
|
||||
|
||||
void unmap()
|
||||
{
|
||||
m_heap->Unmap(0, nullptr);
|
||||
}
|
||||
|
||||
ID3D12Resource* get_heap()
|
||||
{
|
||||
return m_heap.Get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,16 +139,17 @@ struct texture_entry
|
||||
size_t m_width;
|
||||
size_t m_height;
|
||||
size_t m_mipmap;
|
||||
size_t m_depth;
|
||||
|
||||
texture_entry() : m_format(0), m_width(0), m_height(0), m_is_dirty(true)
|
||||
texture_entry() : m_format(0), m_width(0), m_height(0), m_depth(0), m_is_dirty(true)
|
||||
{}
|
||||
|
||||
texture_entry(u8 f, size_t w, size_t h, size_t m) : m_format(f), m_width(w), m_height(h), m_is_dirty(false)
|
||||
texture_entry(u8 f, size_t w, size_t h, size_t d, size_t m) : m_format(f), m_width(w), m_height(h), m_depth(d), m_is_dirty(false), m_mipmap(m)
|
||||
{}
|
||||
|
||||
bool operator==(const texture_entry &other)
|
||||
{
|
||||
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height);
|
||||
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height && m_mipmap == other.m_mipmap && m_depth == other.m_depth);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -165,7 +169,12 @@ private:
|
||||
std::unordered_map<u64, std::pair<texture_entry, ComPtr<ID3D12Resource>> > m_address_to_data; // Storage
|
||||
std::list <std::tuple<u64, u32, u32> > m_protected_ranges; // address, start of protected range, size of protected range
|
||||
public:
|
||||
void store_and_protect_data(u64 key, u32 start, size_t size, u8 format, size_t w, size_t h, size_t m, ComPtr<ID3D12Resource> data);
|
||||
data_cache() = default;
|
||||
~data_cache() = default;
|
||||
data_cache(const data_cache&) = delete;
|
||||
data_cache(data_cache&&) = delete;
|
||||
|
||||
void store_and_protect_data(u64 key, u32 start, size_t size, u8 format, size_t w, size_t h, size_t d, size_t m, ComPtr<ID3D12Resource> data);
|
||||
|
||||
/**
|
||||
* Make memory from start to start + size write protected.
|
||||
@@ -196,6 +205,11 @@ public:
|
||||
*/
|
||||
struct resource_storage
|
||||
{
|
||||
resource_storage() = default;
|
||||
~resource_storage() = default;
|
||||
resource_storage(const resource_storage&) = delete;
|
||||
resource_storage(resource_storage&&) = delete;
|
||||
|
||||
bool in_use; // False until command list has been populated at least once
|
||||
ComPtr<ID3D12Fence> frame_finished_fence;
|
||||
UINT64 fence_value;
|
||||
@@ -230,11 +244,8 @@ struct resource_storage
|
||||
* This means newer resources shouldn't allocate memory crossing this position
|
||||
* until the frame rendering is over.
|
||||
*/
|
||||
size_t constants_heap_get_pos;
|
||||
size_t vertex_index_heap_get_pos;
|
||||
size_t texture_upload_heap_get_pos;
|
||||
size_t buffer_heap_get_pos;
|
||||
size_t readback_heap_get_pos;
|
||||
size_t uav_heap_get_pos;
|
||||
|
||||
void reset();
|
||||
void init(ID3D12Device *device);
|
||||
|
||||
@@ -152,21 +152,21 @@ void D3D12GSRender::release_d2d_structures()
|
||||
void D3D12GSRender::render_overlay()
|
||||
{
|
||||
D2D1_SIZE_F rtSize = g_d2d_render_targets[m_swap_chain->GetCurrentBackBufferIndex()]->GetSize();
|
||||
std::wstring duration = L"Draw duration : " + std::to_wstring(m_timers.m_draw_calls_duration) + L" us";
|
||||
float vtxIdxPercent = (float)m_timers.m_vertex_index_duration / (float)m_timers.m_draw_calls_duration;
|
||||
std::wstring vertexIndexDuration = L"Vtx/Idx upload : " + std::to_wstring(m_timers.m_vertex_index_duration) + L" us (" + std::to_wstring(100.f * vtxIdxPercent) + L" %)";
|
||||
std::wstring size = L"Upload size : " + std::to_wstring(m_timers.m_buffer_upload_size) + L" Bytes";
|
||||
float texPercent = (float)m_timers.m_texture_duration / (float)m_timers.m_draw_calls_duration;
|
||||
std::wstring texDuration = L"Textures : " + std::to_wstring(m_timers.m_texture_duration) + L" us (" + std::to_wstring(100.f * texPercent) + L" %)";
|
||||
float programPercent = (float)m_timers.m_program_load_duration / (float)m_timers.m_draw_calls_duration;
|
||||
std::wstring programDuration = L"Program : " + std::to_wstring(m_timers.m_program_load_duration) + L" us (" + std::to_wstring(100.f * programPercent) + L" %)";
|
||||
float constantsPercent = (float)m_timers.m_constants_duration / (float)m_timers.m_draw_calls_duration;
|
||||
std::wstring constantDuration = L"Constants : " + std::to_wstring(m_timers.m_constants_duration) + L" us (" + std::to_wstring(100.f * constantsPercent) + L" %)";
|
||||
float rttPercent = (float)m_timers.m_prepare_rtt_duration / (float)m_timers.m_draw_calls_duration;
|
||||
std::wstring rttDuration = L"RTT : " + std::to_wstring(m_timers.m_prepare_rtt_duration) + L" us (" + std::to_wstring(100.f * rttPercent) + L" %)";
|
||||
std::wstring flipDuration = L"Flip : " + std::to_wstring(m_timers.m_flip_duration) + L" us";
|
||||
std::wstring duration = L"Draw duration : " + std::to_wstring(m_timers.draw_calls_duration) + L" us";
|
||||
float vtxIdxPercent = (float)m_timers.vertex_index_duration / (float)m_timers.draw_calls_duration;
|
||||
std::wstring vertexIndexDuration = L"Vtx/Idx upload : " + std::to_wstring(m_timers.vertex_index_duration) + L" us (" + std::to_wstring(100.f * vtxIdxPercent) + L" %)";
|
||||
std::wstring size = L"Upload size : " + std::to_wstring(m_timers.buffer_upload_size) + L" Bytes";
|
||||
float texPercent = (float)m_timers.texture_duration / (float)m_timers.draw_calls_duration;
|
||||
std::wstring texDuration = L"Textures : " + std::to_wstring(m_timers.texture_duration) + L" us (" + std::to_wstring(100.f * texPercent) + L" %)";
|
||||
float programPercent = (float)m_timers.program_load_duration / (float)m_timers.draw_calls_duration;
|
||||
std::wstring programDuration = L"Program : " + std::to_wstring(m_timers.program_load_duration) + L" us (" + std::to_wstring(100.f * programPercent) + L" %)";
|
||||
float constantsPercent = (float)m_timers.constants_duration / (float)m_timers.draw_calls_duration;
|
||||
std::wstring constantDuration = L"Constants : " + std::to_wstring(m_timers.constants_duration) + L" us (" + std::to_wstring(100.f * constantsPercent) + L" %)";
|
||||
float rttPercent = (float)m_timers.prepare_rtt_duration / (float)m_timers.draw_calls_duration;
|
||||
std::wstring rttDuration = L"RTT : " + std::to_wstring(m_timers.prepare_rtt_duration) + L" us (" + std::to_wstring(100.f * rttPercent) + L" %)";
|
||||
std::wstring flipDuration = L"Flip : " + std::to_wstring(m_timers.flip_duration) + L" us";
|
||||
|
||||
std::wstring count = L"Draw count : " + std::to_wstring(m_timers.m_draw_calls_count);
|
||||
std::wstring count = L"Draw count : " + std::to_wstring(m_timers.draw_calls_count);
|
||||
draw_strings(rtSize, m_swap_chain->GetCurrentBackBufferIndex(),
|
||||
{
|
||||
duration,
|
||||
|
||||
@@ -36,38 +36,10 @@ void Shader::Compile(const std::string &code, SHADER_TYPE st)
|
||||
}
|
||||
}
|
||||
|
||||
bool D3D12GSRender::load_program()
|
||||
void D3D12GSRender::load_program()
|
||||
{
|
||||
u32 transform_program_start = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START];
|
||||
vertex_program.data.reserve((512 - transform_program_start) * 4);
|
||||
|
||||
for (int i = transform_program_start; i < 512; ++i)
|
||||
{
|
||||
vertex_program.data.resize((i - transform_program_start) * 4 + 4);
|
||||
memcpy(vertex_program.data.data() + (i - transform_program_start) * 4, transform_program + i * 4, 4 * sizeof(u32));
|
||||
|
||||
D3 d3;
|
||||
d3.HEX = transform_program[i * 4 + 3];
|
||||
|
||||
if (d3.end)
|
||||
break;
|
||||
}
|
||||
|
||||
u32 shader_program = rsx::method_registers[NV4097_SET_SHADER_PROGRAM];
|
||||
fragment_program.offset = shader_program & ~0x3;
|
||||
fragment_program.addr = rsx::get_address(fragment_program.offset, (shader_program & 0x3) - 1);
|
||||
fragment_program.ctrl = rsx::method_registers[NV4097_SET_SHADER_CONTROL];
|
||||
fragment_program.texture_dimensions.clear();
|
||||
|
||||
for (u32 i = 0; i < rsx::limits::textures_count; ++i)
|
||||
{
|
||||
if (!textures[i].enabled())
|
||||
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d);
|
||||
else if (textures[i].cubemap())
|
||||
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_cubemap);
|
||||
else
|
||||
fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d);
|
||||
}
|
||||
m_vertex_program = get_current_vertex_program();
|
||||
m_fragment_program = get_current_fragment_program();
|
||||
|
||||
D3D12PipelineProperties prop = {};
|
||||
prop.Topology = get_primitive_topology_type(draw_mode);
|
||||
@@ -162,19 +134,19 @@ bool D3D12GSRender::load_program()
|
||||
prop.DepthStencilFormat = get_depth_stencil_surface_format(m_surface.depth_format);
|
||||
prop.RenderTargetsFormat = get_color_surface_format(m_surface.color_format);
|
||||
|
||||
switch (u32 color_target = rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])
|
||||
switch (rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
case CELL_GCM_SURFACE_TARGET_1:
|
||||
case rsx::surface_target::surface_a:
|
||||
case rsx::surface_target::surface_b:
|
||||
prop.numMRT = 1;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1:
|
||||
case rsx::surface_target::surfaces_a_b:
|
||||
prop.numMRT = 2;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2:
|
||||
case rsx::surface_target::surfaces_a_b_c:
|
||||
prop.numMRT = 3;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3:
|
||||
case rsx::surface_target::surfaces_a_b_c_d:
|
||||
prop.numMRT = 4;
|
||||
break;
|
||||
default:
|
||||
@@ -223,7 +195,7 @@ bool D3D12GSRender::load_program()
|
||||
D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF,
|
||||
};
|
||||
prop.Rasterization = CD3D12_RASTERIZER_DESC;
|
||||
if (rsx::method_registers[NV4097_SET_CULL_FACE_ENABLE])
|
||||
if (!!rsx::method_registers[NV4097_SET_CULL_FACE_ENABLE])
|
||||
{
|
||||
switch (rsx::method_registers[NV4097_SET_CULL_FACE])
|
||||
{
|
||||
@@ -251,17 +223,25 @@ bool D3D12GSRender::load_program()
|
||||
for (unsigned i = 0; i < prop.numMRT; i++)
|
||||
prop.Blend.RenderTarget[i].RenderTargetWriteMask = mask;
|
||||
|
||||
prop.IASet = m_IASet;
|
||||
if (!!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE])
|
||||
prop.CutValue = ((rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4) == CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32) ?
|
||||
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF : D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
|
||||
{
|
||||
rsx::index_array_type index_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
|
||||
if (index_type == rsx::index_array_type::u32)
|
||||
{
|
||||
prop.CutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
|
||||
}
|
||||
if (index_type == rsx::index_array_type::u16)
|
||||
{
|
||||
prop.CutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
m_current_pso = m_pso_cache.getGraphicPipelineState(&vertex_program, &fragment_program, prop, std::make_pair(m_device.Get(), m_root_signatures));
|
||||
return m_current_pso != nullptr;
|
||||
m_current_pso = m_pso_cache.getGraphicPipelineState(m_vertex_program, m_fragment_program, prop, m_device.Get(), m_root_signatures);
|
||||
return;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> D3D12GSRender::get_programs() const
|
||||
{
|
||||
return std::make_pair(m_pso_cache.get_transform_program(vertex_program)->content, m_pso_cache.get_shader_program(fragment_program)->content);
|
||||
return std::make_pair(m_pso_cache.get_transform_program(m_vertex_program).content, m_pso_cache.get_shader_program(m_fragment_program).content);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,6 @@ struct D3D12PipelineProperties
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE Topology;
|
||||
DXGI_FORMAT DepthStencilFormat;
|
||||
DXGI_FORMAT RenderTargetsFormat;
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> IASet;
|
||||
D3D12_BLEND_DESC Blend;
|
||||
unsigned numMRT : 3;
|
||||
D3D12_DEPTH_STENCIL_DESC DepthStencil;
|
||||
@@ -19,23 +18,6 @@ struct D3D12PipelineProperties
|
||||
|
||||
bool operator==(const D3D12PipelineProperties &in) const
|
||||
{
|
||||
if (IASet.size() != in.IASet.size())
|
||||
return false;
|
||||
for (unsigned i = 0; i < IASet.size(); i++)
|
||||
{
|
||||
const D3D12_INPUT_ELEMENT_DESC &a = IASet[i], &b = in.IASet[i];
|
||||
if (a.AlignedByteOffset != b.AlignedByteOffset)
|
||||
return false;
|
||||
if (a.Format != b.Format)
|
||||
return false;
|
||||
if (a.InputSlot != b.InputSlot)
|
||||
return false;
|
||||
if (a.InstanceDataStepRate != b.InstanceDataStepRate)
|
||||
return false;
|
||||
if (a.SemanticIndex != b.SemanticIndex)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(&DepthStencil, &in.DepthStencil, sizeof(D3D12_DEPTH_STENCIL_DESC)))
|
||||
return false;
|
||||
if (memcmp(&Blend, &in.Blend, sizeof(D3D12_BLEND_DESC)))
|
||||
@@ -85,14 +67,15 @@ public:
|
||||
SHADER_TYPE_FRAGMENT
|
||||
};
|
||||
|
||||
Shader() : bytecode(nullptr) {}
|
||||
~Shader() {}
|
||||
Shader() = default;
|
||||
~Shader() = default;
|
||||
Shader(const Shader &) = delete;
|
||||
|
||||
u32 id;
|
||||
ComPtr<ID3DBlob> bytecode;
|
||||
// For debugging
|
||||
std::string content;
|
||||
std::vector<size_t> vertex_shader_inputs;
|
||||
size_t vertex_shader_input_count;
|
||||
std::vector<size_t> FragmentConstantOffsetCache;
|
||||
size_t m_textureCount;
|
||||
|
||||
@@ -117,36 +100,18 @@ bool has_attribute(size_t attribute, const std::vector<D3D12_INPUT_ELEMENT_DESC>
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> completes_IA_desc(const std::vector<D3D12_INPUT_ELEMENT_DESC> &desc, const std::vector<size_t> &inputs)
|
||||
{
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> result(desc);
|
||||
for (size_t attribute : inputs)
|
||||
{
|
||||
if (has_attribute(attribute, desc))
|
||||
continue;
|
||||
D3D12_INPUT_ELEMENT_DESC extra_ia_desc = {};
|
||||
extra_ia_desc.SemanticIndex = (UINT)attribute;
|
||||
extra_ia_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
extra_ia_desc.SemanticName = "TEXCOORD";
|
||||
extra_ia_desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
result.push_back(extra_ia_desc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct D3D12Traits
|
||||
{
|
||||
typedef Shader VertexProgramData;
|
||||
typedef Shader FragmentProgramData;
|
||||
typedef std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> PipelineData;
|
||||
typedef D3D12PipelineProperties PipelineProperties;
|
||||
typedef std::pair<ID3D12Device *, ComPtr<ID3D12RootSignature> *> ExtraData;
|
||||
using vertex_program_type = Shader;
|
||||
using fragment_program_type = Shader;
|
||||
using pipeline_storage_type = std::tuple<ComPtr<ID3D12PipelineState>, size_t, size_t>;
|
||||
using pipeline_properties = D3D12PipelineProperties;
|
||||
|
||||
static
|
||||
void RecompileFragmentProgram(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID)
|
||||
void recompile_fragment_program(const RSXFragmentProgram &RSXFP, fragment_program_type& fragmentProgramData, size_t ID)
|
||||
{
|
||||
D3D12FragmentDecompiler FS(RSXFP->addr, RSXFP->size, RSXFP->ctrl, RSXFP->texture_dimensions);
|
||||
u32 size;
|
||||
D3D12FragmentDecompiler FS(RSXFP, size);
|
||||
const std::string &shader = FS.Decompile();
|
||||
fragmentProgramData.Compile(shader, Shader::SHADER_TYPE::SHADER_TYPE_FRAGMENT);
|
||||
fragmentProgramData.m_textureCount = 0;
|
||||
@@ -154,7 +119,7 @@ struct D3D12Traits
|
||||
{
|
||||
for (const ParamItem PI : PT.items)
|
||||
{
|
||||
if (PT.type == "sampler2D" || PT.type == "samplerCube")
|
||||
if (PT.type == "sampler1D" || PT.type == "sampler2D" || PT.type == "samplerCube" || PT.type == "sampler3D")
|
||||
{
|
||||
size_t texture_unit = atoi(PI.name.c_str() + 3);
|
||||
fragmentProgramData.m_textureCount = std::max(texture_unit + 1, fragmentProgramData.m_textureCount);
|
||||
@@ -165,40 +130,40 @@ struct D3D12Traits
|
||||
}
|
||||
}
|
||||
|
||||
fs::file(fs::get_config_dir() + "FragmentProgram" + std::to_string(ID) + ".hlsl", fom::rewrite) << shader;
|
||||
fs::file(fs::get_config_dir() + "FragmentProgram" + std::to_string(ID) + ".hlsl", fom::rewrite).write(shader);
|
||||
fragmentProgramData.id = (u32)ID;
|
||||
}
|
||||
|
||||
static
|
||||
void RecompileVertexProgram(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID)
|
||||
void recompile_vertex_program(const RSXVertexProgram &RSXVP, vertex_program_type& vertexProgramData, size_t ID)
|
||||
{
|
||||
D3D12VertexProgramDecompiler VS(RSXVP->data);
|
||||
D3D12VertexProgramDecompiler VS(RSXVP);
|
||||
std::string shaderCode = VS.Decompile();
|
||||
vertexProgramData.Compile(shaderCode, Shader::SHADER_TYPE::SHADER_TYPE_VERTEX);
|
||||
vertexProgramData.vertex_shader_inputs = VS.input_slots;
|
||||
fs::file(fs::get_config_dir() + "VertexProgram" + std::to_string(ID) + ".hlsl", fom::rewrite) << shaderCode;
|
||||
vertexProgramData.vertex_shader_input_count = RSXVP.rsx_vertex_inputs.size();
|
||||
fs::file(fs::get_config_dir() + "VertexProgram" + std::to_string(ID) + ".hlsl", fom::rewrite).write(shaderCode);
|
||||
vertexProgramData.id = (u32)ID;
|
||||
}
|
||||
|
||||
static
|
||||
PipelineData *BuildProgram(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData)
|
||||
pipeline_storage_type build_pipeline(
|
||||
const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, const pipeline_properties &pipelineProperties,
|
||||
ID3D12Device *device, gsl::span<ComPtr<ID3D12RootSignature>, 17, 17> root_signatures)
|
||||
{
|
||||
|
||||
std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> *result = new std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t>();
|
||||
std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> result = {};
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {};
|
||||
|
||||
if (vertexProgramData.bytecode == nullptr)
|
||||
return nullptr;
|
||||
throw new EXCEPTION("Vertex program compilation failure");
|
||||
graphicPipelineStateDesc.VS.BytecodeLength = vertexProgramData.bytecode->GetBufferSize();
|
||||
graphicPipelineStateDesc.VS.pShaderBytecode = vertexProgramData.bytecode->GetBufferPointer();
|
||||
|
||||
if (fragmentProgramData.bytecode == nullptr)
|
||||
return nullptr;
|
||||
throw new EXCEPTION("fragment program compilation failure");
|
||||
graphicPipelineStateDesc.PS.BytecodeLength = fragmentProgramData.bytecode->GetBufferSize();
|
||||
graphicPipelineStateDesc.PS.pShaderBytecode = fragmentProgramData.bytecode->GetBufferPointer();
|
||||
|
||||
graphicPipelineStateDesc.pRootSignature = extraData.second[fragmentProgramData.m_textureCount].Get();
|
||||
std::get<2>(*result) = fragmentProgramData.m_textureCount;
|
||||
graphicPipelineStateDesc.pRootSignature = root_signatures[fragmentProgramData.m_textureCount][vertexProgramData.vertex_shader_input_count].Get();
|
||||
|
||||
graphicPipelineStateDesc.BlendState = pipelineProperties.Blend;
|
||||
graphicPipelineStateDesc.DepthStencilState = pipelineProperties.DepthStencil;
|
||||
@@ -210,32 +175,21 @@ struct D3D12Traits
|
||||
graphicPipelineStateDesc.RTVFormats[i] = pipelineProperties.RenderTargetsFormat;
|
||||
graphicPipelineStateDesc.DSVFormat = pipelineProperties.DepthStencilFormat;
|
||||
|
||||
const std::vector<D3D12_INPUT_ELEMENT_DESC> &completed_IA_desc = completes_IA_desc(pipelineProperties.IASet, vertexProgramData.vertex_shader_inputs);
|
||||
|
||||
graphicPipelineStateDesc.InputLayout.pInputElementDescs = completed_IA_desc.data();
|
||||
graphicPipelineStateDesc.InputLayout.NumElements = (UINT)completed_IA_desc.size();
|
||||
graphicPipelineStateDesc.SampleDesc.Count = 1;
|
||||
graphicPipelineStateDesc.SampleMask = UINT_MAX;
|
||||
graphicPipelineStateDesc.NodeMask = 1;
|
||||
|
||||
graphicPipelineStateDesc.IBStripCutValue = pipelineProperties.CutValue;
|
||||
|
||||
CHECK_HRESULT(extraData.first->CreateGraphicsPipelineState(&graphicPipelineStateDesc, IID_PPV_ARGS(&std::get<0>(*result))));
|
||||
std::get<1>(*result) = vertexProgramData.vertex_shader_inputs;
|
||||
ComPtr<ID3D12PipelineState> pso;
|
||||
CHECK_HRESULT(device->CreateGraphicsPipelineState(&graphicPipelineStateDesc, IID_PPV_ARGS(pso.GetAddressOf())));
|
||||
|
||||
std::wstring name = L"PSO_" + std::to_wstring(vertexProgramData.id) + L"_" + std::to_wstring(fragmentProgramData.id);
|
||||
std::get<0>(*result)->SetName(name.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
void DeleteProgram(PipelineData *ptr)
|
||||
{
|
||||
std::get<0>(*ptr)->Release();
|
||||
delete ptr;
|
||||
pso->SetName(name.c_str());
|
||||
return std::make_tuple(pso, vertexProgramData.vertex_shader_input_count, fragmentProgramData.m_textureCount);
|
||||
}
|
||||
};
|
||||
|
||||
class PipelineStateObjectCache : public ProgramStateCache<D3D12Traits>
|
||||
class PipelineStateObjectCache : public program_state_cache<D3D12Traits>
|
||||
{
|
||||
};
|
||||
|
||||
@@ -13,33 +13,42 @@
|
||||
#include "D3D12GSRender.h"
|
||||
#include "D3D12Formats.h"
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
UINT get_num_rtt(u8 color_target)
|
||||
u32 get_max_depth_value(rsx::surface_depth_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_depth_format::z16: return 0xFFFF;
|
||||
case rsx::surface_depth_format::z24s8: return 0xFFFFFF;
|
||||
}
|
||||
throw EXCEPTION("Unknow depth format");
|
||||
}
|
||||
|
||||
UINT get_num_rtt(rsx::surface_target color_target)
|
||||
{
|
||||
switch (color_target)
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE: return 0;
|
||||
case CELL_GCM_SURFACE_TARGET_0:
|
||||
case CELL_GCM_SURFACE_TARGET_1: return 1;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1: return 2;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2: return 3;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3: return 4;
|
||||
case rsx::surface_target::none: return 0;
|
||||
case rsx::surface_target::surface_a:
|
||||
case rsx::surface_target::surface_b: return 1;
|
||||
case rsx::surface_target::surfaces_a_b: return 2;
|
||||
case rsx::surface_target::surfaces_a_b_c: return 3;
|
||||
case rsx::surface_target::surfaces_a_b_c_d: return 4;
|
||||
}
|
||||
throw EXCEPTION("Wrong color_target (%d)", color_target);
|
||||
}
|
||||
|
||||
std::vector<u8> get_rtt_indexes(u8 color_target)
|
||||
std::vector<u8> get_rtt_indexes(rsx::surface_target color_target)
|
||||
{
|
||||
switch (color_target)
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE: return{};
|
||||
case CELL_GCM_SURFACE_TARGET_0: return{ 0 };
|
||||
case CELL_GCM_SURFACE_TARGET_1: return{ 1 };
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1: return{ 0, 1 };
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2: return{ 0, 1, 2 };
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3: return{ 0, 1, 2, 3 };
|
||||
case rsx::surface_target::none: return{};
|
||||
case rsx::surface_target::surface_a: return{ 0 };
|
||||
case rsx::surface_target::surface_b: return{ 1 };
|
||||
case rsx::surface_target::surfaces_a_b: return{ 0, 1 };
|
||||
case rsx::surface_target::surfaces_a_b_c: return{ 0, 1, 2 };
|
||||
case rsx::surface_target::surfaces_a_b_c_d: return{ 0, 1, 2, 3 };
|
||||
}
|
||||
throw EXCEPTION("Wrong color_target (%d)", color_target);
|
||||
}
|
||||
@@ -63,6 +72,50 @@ namespace
|
||||
{
|
||||
return register_value & 0xff;
|
||||
}
|
||||
|
||||
size_t get_aligned_pitch(rsx::surface_color_format format, u32 width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_color_format::b8: return align(width, 256);
|
||||
case rsx::surface_color_format::g8b8:
|
||||
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case rsx::surface_color_format::r5g6b5: return align(width * 2, 256);
|
||||
case rsx::surface_color_format::a8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case rsx::surface_color_format::x32:
|
||||
case rsx::surface_color_format::a8r8g8b8: return align(width * 4, 256);
|
||||
case rsx::surface_color_format::w16z16y16x16: return align(width * 8, 256);
|
||||
case rsx::surface_color_format::w32z32y32x32: return align(width * 16, 256);
|
||||
}
|
||||
throw EXCEPTION("Unknow color surface format");
|
||||
}
|
||||
|
||||
size_t get_packed_pitch(rsx::surface_color_format format, u32 width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case rsx::surface_color_format::b8: return width;
|
||||
case rsx::surface_color_format::g8b8:
|
||||
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case rsx::surface_color_format::r5g6b5: return width * 2;
|
||||
case rsx::surface_color_format::a8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case rsx::surface_color_format::x32:
|
||||
case rsx::surface_color_format::a8r8g8b8: return width * 4;
|
||||
case rsx::surface_color_format::w16z16y16x16: return width * 8;
|
||||
case rsx::surface_color_format::w32z32y32x32: return width * 16;
|
||||
}
|
||||
throw EXCEPTION("Unknow color surface format");
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12GSRender::clear_surface(u32 arg)
|
||||
@@ -73,42 +126,38 @@ void D3D12GSRender::clear_surface(u32 arg)
|
||||
prepare_render_targets(get_current_resource_storage().command_list.Get());
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> rtt_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_prepare_rtt_duration += std::chrono::duration_cast<std::chrono::microseconds>(rtt_duration_end - rtt_duration_start).count();
|
||||
m_timers.prepare_rtt_duration += std::chrono::duration_cast<std::chrono::microseconds>(rtt_duration_end - rtt_duration_start).count();
|
||||
|
||||
if (arg & 0x1 || arg & 0x2)
|
||||
{
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().depth_stencil_descriptor_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().depth_stencil_descriptor_heap_index * g_descriptor_stride_rtv);
|
||||
m_rtts.bind_depth_stencil(m_device.Get(), m_surface.depth_format, handle);
|
||||
get_current_resource_storage().depth_stencil_descriptor_heap_index++;
|
||||
|
||||
if (arg & 0x1)
|
||||
{
|
||||
u32 clear_depth = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] >> 8;
|
||||
u32 max_depth_value = m_surface.depth_format == CELL_GCM_SURFACE_Z16 ? 0x0000ffff : 0x00ffffff;
|
||||
get_current_resource_storage().command_list->ClearDepthStencilView(handle, D3D12_CLEAR_FLAG_DEPTH, clear_depth / (float)max_depth_value, 0,
|
||||
u32 max_depth_value = get_max_depth_value(m_surface.depth_format);
|
||||
get_current_resource_storage().command_list->ClearDepthStencilView(m_rtts.current_ds_handle, D3D12_CLEAR_FLAG_DEPTH, clear_depth / (float)max_depth_value, 0,
|
||||
1, &get_scissor(rsx::method_registers[NV4097_SET_SCISSOR_HORIZONTAL], rsx::method_registers[NV4097_SET_SCISSOR_VERTICAL]));
|
||||
}
|
||||
|
||||
if (arg & 0x2)
|
||||
get_current_resource_storage().command_list->ClearDepthStencilView(handle, D3D12_CLEAR_FLAG_STENCIL, 0.f, get_clear_stencil(rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE]),
|
||||
get_current_resource_storage().command_list->ClearDepthStencilView(m_rtts.current_ds_handle, D3D12_CLEAR_FLAG_STENCIL, 0.f, get_clear_stencil(rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE]),
|
||||
1, &get_scissor(rsx::method_registers[NV4097_SET_SCISSOR_HORIZONTAL], rsx::method_registers[NV4097_SET_SCISSOR_VERTICAL]));
|
||||
}
|
||||
|
||||
if (arg & 0xF0)
|
||||
{
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().render_targets_descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().render_targets_descriptors_heap_index * g_descriptor_stride_rtv);
|
||||
size_t rtt_index = m_rtts.bind_render_targets(m_device.Get(), m_surface.color_format, handle);
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(m_rtts.current_rtts_handle);
|
||||
size_t rtt_index = get_num_rtt(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]));
|
||||
get_current_resource_storage().render_targets_descriptors_heap_index += rtt_index;
|
||||
for (unsigned i = 0; i < rtt_index; i++)
|
||||
get_current_resource_storage().command_list->ClearRenderTargetView(handle.Offset(i, g_descriptor_stride_rtv), get_clear_color(rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE]).data(),
|
||||
get_current_resource_storage().command_list->ClearRenderTargetView(handle.Offset(i, m_descriptor_stride_rtv), get_clear_color(rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE]).data(),
|
||||
1, &get_scissor(rsx::method_registers[NV4097_SET_SCISSOR_HORIZONTAL], rsx::method_registers[NV4097_SET_SCISSOR_VERTICAL]));
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> end_duration = std::chrono::system_clock::now();
|
||||
m_timers.m_draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(end_duration - start_duration).count();
|
||||
m_timers.m_draw_calls_count++;
|
||||
m_timers.draw_calls_duration += std::chrono::duration_cast<std::chrono::microseconds>(end_duration - start_duration).count();
|
||||
m_timers.draw_calls_count++;
|
||||
|
||||
if (rpcs3::config.rsx.d3d12.debug_output.value())
|
||||
{
|
||||
@@ -120,240 +169,65 @@ void D3D12GSRender::clear_surface(u32 arg)
|
||||
|
||||
void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlist)
|
||||
{
|
||||
// check if something has changed
|
||||
u32 surface_format = rsx::method_registers[NV4097_SET_SURFACE_FORMAT];
|
||||
|
||||
u32 clip_horizontal = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL];
|
||||
u32 clip_vertical = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL];
|
||||
|
||||
u32 clip_width = clip_horizontal >> 16;
|
||||
u32 clip_height = clip_vertical >> 16;
|
||||
u32 clip_x = clip_horizontal;
|
||||
u32 clip_y = clip_vertical;
|
||||
|
||||
u32 context_dma_color[] =
|
||||
{
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_A],
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_B],
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_C],
|
||||
rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_D]
|
||||
};
|
||||
u32 m_context_dma_z = rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA];
|
||||
|
||||
u32 offset_color[] =
|
||||
{
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_AOFFSET],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_BOFFSET],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_COFFSET],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_COLOR_DOFFSET]
|
||||
};
|
||||
u32 offset_zeta = rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET];
|
||||
|
||||
// FBO location has changed, previous data might be copied
|
||||
u32 address_color[] =
|
||||
{
|
||||
rsx::get_address(offset_color[0], context_dma_color[0]),
|
||||
rsx::get_address(offset_color[1], context_dma_color[1]),
|
||||
rsx::get_address(offset_color[2], context_dma_color[2]),
|
||||
rsx::get_address(offset_color[3], context_dma_color[3]),
|
||||
};
|
||||
u32 address_z = rsx::get_address(offset_zeta, m_context_dma_z);
|
||||
|
||||
// Exit early if there is no rtt changes
|
||||
if (m_previous_address_a == address_color[0] &&
|
||||
m_previous_address_b == address_color[1] &&
|
||||
m_previous_address_c == address_color[2] &&
|
||||
m_previous_address_d == address_color[3] &&
|
||||
m_previous_address_z == address_z &&
|
||||
m_surface.format == surface_format)
|
||||
if (!m_rtts_dirty)
|
||||
return;
|
||||
m_rtts_dirty = false;
|
||||
|
||||
m_previous_address_a = address_color[0];
|
||||
m_previous_address_b = address_color[1];
|
||||
m_previous_address_c = address_color[2];
|
||||
m_previous_address_d = address_color[3];
|
||||
m_previous_address_z = address_z;
|
||||
|
||||
if (m_surface.format != surface_format)
|
||||
{
|
||||
m_surface.unpack(surface_format);
|
||||
m_surface.width = clip_width;
|
||||
m_surface.height = clip_height;
|
||||
}
|
||||
|
||||
// Make previous RTTs sampleable
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
if (m_rtts.bound_render_targets[i] == nullptr)
|
||||
continue;
|
||||
copycmdlist->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_render_targets[i], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
}
|
||||
// Reset bound data
|
||||
memset(m_rtts.bound_render_targets_address, 0, 4 * sizeof(u32));
|
||||
memset(m_rtts.bound_render_targets, 0, 4 * sizeof(ID3D12Resource *));
|
||||
|
||||
|
||||
// Create/Reuse requested rtts
|
||||
std::array<float, 4> clear_color = get_clear_color(rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE]);
|
||||
for (u8 i : get_rtt_indexes(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
{
|
||||
ComPtr<ID3D12Resource> old_render_target_resource;
|
||||
m_rtts.bound_render_targets[i] = m_rtts.bind_address_as_render_targets(m_device.Get(), copycmdlist, address_color[i], clip_width, clip_height, m_surface.color_format,
|
||||
clear_color, old_render_target_resource);
|
||||
if (old_render_target_resource)
|
||||
get_current_resource_storage().dirty_textures.push_back(old_render_target_resource);
|
||||
m_rtts.bound_render_targets_address[i] = address_color[i];
|
||||
}
|
||||
m_rtts.prepare_render_target(copycmdlist,
|
||||
rsx::method_registers[NV4097_SET_SURFACE_FORMAT],
|
||||
rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL], rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL],
|
||||
rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]),
|
||||
get_color_surface_addresses(), get_zeta_surface_address(),
|
||||
m_device.Get(), clear_color, 1.f, 0);
|
||||
|
||||
// Same for depth buffer
|
||||
if (m_rtts.bound_depth_stencil != nullptr)
|
||||
copycmdlist->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
m_rtts.bound_depth_stencil = nullptr;
|
||||
m_rtts.bound_depth_stencil_address = 0;
|
||||
if (!address_z)
|
||||
return;
|
||||
ComPtr<ID3D12Resource> old_depth_stencil_resource;
|
||||
ID3D12Resource *ds = m_rtts.bind_address_as_depth_stencil(m_device.Get(), copycmdlist, address_z, clip_width, clip_height, m_surface.depth_format, 1., 0, old_depth_stencil_resource);
|
||||
if (old_depth_stencil_resource)
|
||||
get_current_resource_storage().dirty_textures.push_back(old_depth_stencil_resource);
|
||||
m_rtts.bound_depth_stencil_address = address_z;
|
||||
m_rtts.bound_depth_stencil = ds;
|
||||
}
|
||||
|
||||
size_t render_targets::bind_render_targets(ID3D12Device *device, u32 color_format, D3D12_CPU_DESCRIPTOR_HANDLE handle)
|
||||
{
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(color_format);
|
||||
// write descriptors
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(m_surface.color_format);
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtt_view_desc = {};
|
||||
rtt_view_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||
rtt_view_desc.Format = dxgi_format;
|
||||
|
||||
m_rtts.current_rtts_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().render_targets_descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().render_targets_descriptors_heap_index * m_descriptor_stride_rtv);
|
||||
size_t rtt_index = 0;
|
||||
for (u8 i : get_rtt_indexes(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
for (u8 i : get_rtt_indexes(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
|
||||
{
|
||||
if (bound_render_targets[i] == nullptr)
|
||||
if (std::get<1>(m_rtts.m_bound_render_targets[i]) == nullptr)
|
||||
continue;
|
||||
device->CreateRenderTargetView(bound_render_targets[i], &rtt_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(handle).Offset((INT)rtt_index * g_descriptor_stride_rtv));
|
||||
m_device->CreateRenderTargetView(std::get<1>(m_rtts.m_bound_render_targets[i]), &rtt_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(m_rtts.current_rtts_handle).Offset((INT)rtt_index * m_descriptor_stride_rtv));
|
||||
rtt_index++;
|
||||
}
|
||||
return rtt_index;
|
||||
}
|
||||
get_current_resource_storage().render_targets_descriptors_heap_index += rtt_index;
|
||||
|
||||
size_t render_targets::bind_depth_stencil(ID3D12Device *device, u32 depth_format, D3D12_CPU_DESCRIPTOR_HANDLE handle)
|
||||
{
|
||||
if (!bound_depth_stencil)
|
||||
return 0;
|
||||
if (std::get<1>(m_rtts.m_bound_depth_stencil) == nullptr)
|
||||
return;
|
||||
m_rtts.current_ds_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().depth_stencil_descriptor_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().depth_stencil_descriptor_heap_index * m_descriptor_stride_dsv);
|
||||
get_current_resource_storage().depth_stencil_descriptor_heap_index += 1;
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC depth_stencil_view_desc = {};
|
||||
depth_stencil_view_desc.Format = get_depth_stencil_surface_format(depth_format);
|
||||
depth_stencil_view_desc.Format = get_depth_stencil_surface_format(m_surface.depth_format);
|
||||
depth_stencil_view_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
|
||||
device->CreateDepthStencilView(bound_depth_stencil, &depth_stencil_view_desc, handle);
|
||||
return 1;
|
||||
m_device->CreateDepthStencilView(std::get<1>(m_rtts.m_bound_depth_stencil), &depth_stencil_view_desc, m_rtts.current_ds_handle);
|
||||
}
|
||||
|
||||
void D3D12GSRender::set_rtt_and_ds(ID3D12GraphicsCommandList *command_list)
|
||||
{
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().render_targets_descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().render_targets_descriptors_heap_index * g_descriptor_stride_rtv);
|
||||
size_t num_rtt = m_rtts.bind_render_targets(m_device.Get(), m_surface.color_format, handle);
|
||||
get_current_resource_storage().render_targets_descriptors_heap_index += num_rtt;
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE depth_stencil_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().depth_stencil_descriptor_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().depth_stencil_descriptor_heap_index * g_descriptor_stride_rtv);
|
||||
size_t num_ds = m_rtts.bind_depth_stencil(m_device.Get(), m_surface.depth_format, depth_stencil_handle);
|
||||
get_current_resource_storage().depth_stencil_descriptor_heap_index += num_ds;
|
||||
command_list->OMSetRenderTargets((UINT)num_rtt, num_rtt > 0 ? &handle : nullptr, !!num_rtt,
|
||||
num_ds > 0 ? &depth_stencil_handle : nullptr);
|
||||
UINT num_rtt = get_num_rtt(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]));
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE* ds_handle = (std::get<1>(m_rtts.m_bound_depth_stencil) != nullptr) ? &m_rtts.current_ds_handle : nullptr;
|
||||
command_list->OMSetRenderTargets((UINT)num_rtt, &m_rtts.current_rtts_handle, true, ds_handle);
|
||||
}
|
||||
|
||||
ID3D12Resource *render_targets::bind_address_as_render_targets(ID3D12Device *device, ID3D12GraphicsCommandList *cmdList, u32 address,
|
||||
size_t width, size_t height, u8 surfaceColorFormat, const std::array<float, 4> &clear_color, ComPtr<ID3D12Resource> &dirtyRTT)
|
||||
void rsx::render_targets::init(ID3D12Device *device)
|
||||
{
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(surfaceColorFormat);
|
||||
auto It = render_targets_storage.find(address);
|
||||
// TODO: Check if format and size match
|
||||
if (It != render_targets_storage.end())
|
||||
{
|
||||
ComPtr<ID3D12Resource> rtt;
|
||||
rtt = It->second.Get();
|
||||
if (rtt->GetDesc().Format == dxgi_format && rtt->GetDesc().Width == width && rtt->GetDesc().Height == height)
|
||||
{
|
||||
cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rtt.Get(), D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET));
|
||||
return rtt.Get();
|
||||
}
|
||||
render_targets_storage.erase(address);
|
||||
dirtyRTT = rtt;
|
||||
}
|
||||
ComPtr<ID3D12Resource> rtt;
|
||||
LOG_WARNING(RSX, "Creating RTT");
|
||||
|
||||
D3D12_CLEAR_VALUE clear_color_value = {};
|
||||
clear_color_value.Format = dxgi_format;
|
||||
clear_color_value.Color[0] = clear_color[0];
|
||||
clear_color_value.Color[1] = clear_color[1];
|
||||
clear_color_value.Color[2] = clear_color[2];
|
||||
clear_color_value.Color[3] = clear_color[3];
|
||||
|
||||
device->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)width, (UINT)height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET),
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||
&clear_color_value,
|
||||
IID_PPV_ARGS(rtt.GetAddressOf())
|
||||
);
|
||||
render_targets_storage[address] = rtt;
|
||||
std::wstring name = L"rtt_@" + std::to_wstring(address);
|
||||
rtt->SetName(name.c_str());
|
||||
|
||||
return rtt.Get();
|
||||
}
|
||||
|
||||
ID3D12Resource * render_targets::bind_address_as_depth_stencil(ID3D12Device * device, ID3D12GraphicsCommandList * cmdList, u32 address, size_t width, size_t height, u8 surfaceDepthFormat, float depthClear, u8 stencilClear, ComPtr<ID3D12Resource> &dirtyDS)
|
||||
{
|
||||
auto It = depth_stencil_storage.find(address);
|
||||
|
||||
// TODO: Check if surface depth format match
|
||||
|
||||
if (It != depth_stencil_storage.end())
|
||||
{
|
||||
ComPtr<ID3D12Resource> ds = It->second;
|
||||
if (ds->GetDesc().Width == width && ds->GetDesc().Height == height)
|
||||
{
|
||||
// set the resource as depth write
|
||||
cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds.Get(), D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE));
|
||||
return ds.Get();
|
||||
}
|
||||
// If size doesn't match, remove ds from cache
|
||||
depth_stencil_storage.erase(address);
|
||||
dirtyDS = ds;
|
||||
}
|
||||
|
||||
D3D12_CLEAR_VALUE clear_depth_value = {};
|
||||
clear_depth_value.DepthStencil.Depth = depthClear;
|
||||
|
||||
DXGI_FORMAT dxgi_format = get_depth_stencil_typeless_surface_format(surfaceDepthFormat);
|
||||
clear_depth_value.Format = get_depth_stencil_surface_clear_format(surfaceDepthFormat);
|
||||
|
||||
ComPtr<ID3D12Resource> new_depth_stencil;
|
||||
device->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)width, (UINT)height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL),
|
||||
D3D12_RESOURCE_STATE_DEPTH_WRITE,
|
||||
&clear_depth_value,
|
||||
IID_PPV_ARGS(new_depth_stencil.GetAddressOf())
|
||||
);
|
||||
depth_stencil_storage[address] = new_depth_stencil;
|
||||
std::wstring name = L"ds_@" + std::to_wstring(address);
|
||||
new_depth_stencil->SetName(name.c_str());
|
||||
|
||||
return new_depth_stencil.Get();
|
||||
}
|
||||
|
||||
void render_targets::init(ID3D12Device *device)//, u8 surfaceDepthFormat, size_t width, size_t height, float clearColor[4], float clearDepth)
|
||||
{
|
||||
memset(bound_render_targets_address, 0, 4 * sizeof(u32));
|
||||
memset(bound_render_targets, 0, 4 * sizeof(ID3D12Resource*));
|
||||
bound_depth_stencil = nullptr;
|
||||
bound_depth_stencil_address = 0;
|
||||
g_descriptor_stride_rtv = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
}
|
||||
|
||||
@@ -366,47 +240,32 @@ namespace
|
||||
size_t download_to_readback_buffer(
|
||||
ID3D12Device *device,
|
||||
ID3D12GraphicsCommandList * command_list,
|
||||
data_heap<ID3D12Resource, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT> &readback_heap,
|
||||
data_heap &readback_heap,
|
||||
ID3D12Resource * color_surface,
|
||||
int color_surface_format
|
||||
rsx::surface_color_format color_surface_format
|
||||
)
|
||||
{
|
||||
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(color_surface_format);
|
||||
size_t row_pitch;
|
||||
switch (color_surface_format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_R5G6B5:
|
||||
row_pitch = align(clip_w * 2, 256);
|
||||
break;
|
||||
case CELL_GCM_SURFACE_A8R8G8B8:
|
||||
row_pitch = align(clip_w * 4, 256);
|
||||
break;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16:
|
||||
row_pitch = align(clip_w * 8, 256);
|
||||
break;
|
||||
}
|
||||
size_t row_pitch = get_aligned_pitch(color_surface_format, clip_w);
|
||||
|
||||
size_t buffer_size = row_pitch * clip_h;
|
||||
assert(readback_heap.can_alloc(buffer_size));
|
||||
size_t heap_offset = readback_heap.alloc(buffer_size);
|
||||
size_t heap_offset = readback_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(color_surface, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_heap.m_heap, { heap_offset, { dxgi_format, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_heap.get_heap(), { heap_offset, { dxgi_format, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(color_surface, 0), nullptr);
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(color_surface, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET));
|
||||
return heap_offset;
|
||||
}
|
||||
|
||||
void copy_readback_buffer_to_dest(void *dest, data_heap<ID3D12Resource, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT> &readback_heap, size_t offset_in_heap, size_t dst_pitch, size_t src_pitch, size_t height)
|
||||
void copy_readback_buffer_to_dest(void *dest, data_heap &readback_heap, size_t offset_in_heap, size_t dst_pitch, size_t src_pitch, size_t height)
|
||||
{
|
||||
void *buffer;
|
||||
// TODO: Use exact range
|
||||
CHECK_HRESULT(readback_heap.m_heap->Map(0, nullptr, &buffer));
|
||||
void *mapped_buffer = (char*)buffer + offset_in_heap;
|
||||
void *mapped_buffer = readback_heap.map<void>(offset_in_heap);
|
||||
for (unsigned row = 0; row < height; row++)
|
||||
{
|
||||
u32 *casted_dest = (u32*)((char*)dest + row * dst_pitch);
|
||||
@@ -414,7 +273,7 @@ namespace
|
||||
for (unsigned col = 0; col < src_pitch / 4; col++)
|
||||
*casted_dest++ = se_storage<u32>::swap(*casted_src++);
|
||||
}
|
||||
readback_heap.m_heap->Unmap(0, nullptr);
|
||||
readback_heap.unmap();
|
||||
}
|
||||
|
||||
void wait_for_command_queue(ID3D12Device *device, ID3D12CommandQueue *command_queue)
|
||||
@@ -429,6 +288,8 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
{
|
||||
// Add all buffer write
|
||||
@@ -474,13 +335,11 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
if (m_context_dma_z && rpcs3::state.config.rsx.opengl.write_depth_buffer)
|
||||
{
|
||||
size_t uav_size = clip_w * clip_h * 2;
|
||||
assert(m_uav_heap.can_alloc(uav_size));
|
||||
size_t heap_offset = m_uav_heap.alloc(uav_size);
|
||||
|
||||
CHECK_HRESULT(
|
||||
m_device->CreatePlacedResource(
|
||||
m_uav_heap.m_heap,
|
||||
heap_offset,
|
||||
m_device->CreateCommittedResource(
|
||||
&D3D12_HEAP_PROPERTIES{D3D12_HEAP_TYPE_DEFAULT},
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8_UNORM, clip_w, clip_h, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS),
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
nullptr,
|
||||
@@ -497,31 +356,31 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
shader_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
shader_resource_view_desc.Texture2D.MipLevels = 1;
|
||||
shader_resource_view_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
m_device->CreateShaderResourceView(m_rtts.bound_depth_stencil, &shader_resource_view_desc,
|
||||
m_device->CreateShaderResourceView(std::get<1>(m_rtts.m_bound_depth_stencil), &shader_resource_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(descriptor_heap->GetCPUDescriptorHandleForHeapStart()));
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
|
||||
uav_desc.Format = DXGI_FORMAT_R8_UNORM;
|
||||
uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
m_device->CreateUnorderedAccessView(depth_format_conversion_buffer.Get(), nullptr, &uav_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(1, g_descriptor_stride_srv_cbv_uav));
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(1, m_descriptor_stride_srv_cbv_uav));
|
||||
|
||||
// Convert
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
|
||||
get_current_resource_storage().command_list->SetPipelineState(m_convertPSO);
|
||||
get_current_resource_storage().command_list->SetComputeRootSignature(m_convertRootSignature);
|
||||
get_current_resource_storage().command_list->SetPipelineState(m_convert_pso);
|
||||
get_current_resource_storage().command_list->SetComputeRootSignature(m_convert_root_signature);
|
||||
get_current_resource_storage().command_list->SetDescriptorHeaps(1, descriptor_heap.GetAddressOf());
|
||||
get_current_resource_storage().command_list->SetComputeRootDescriptorTable(0, descriptor_heap->GetGPUDescriptorHandleForHeapStart());
|
||||
get_current_resource_storage().command_list->Dispatch(clip_w / 8, clip_h / 8, 1);
|
||||
|
||||
D3D12_RESOURCE_BARRIER barriers[] =
|
||||
{
|
||||
CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE),
|
||||
CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE),
|
||||
CD3DX12_RESOURCE_BARRIER::UAV(depth_format_conversion_buffer.Get()),
|
||||
};
|
||||
get_current_resource_storage().command_list->ResourceBarrier(2, barriers);
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(depth_format_conversion_buffer.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.m_heap, { depth_buffer_offset_in_heap,{ DXGI_FORMAT_R8_UNORM, (UINT)clip_w, (UINT)clip_h, 1, (UINT)depth_row_pitch } }), 0, 0, 0,
|
||||
get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.get_heap(), { depth_buffer_offset_in_heap,{ DXGI_FORMAT_R8_UNORM, (UINT)clip_w, (UINT)clip_h, 1, (UINT)depth_row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(depth_format_conversion_buffer.Get(), 0), nullptr);
|
||||
|
||||
invalidate_address(address_z);
|
||||
@@ -532,11 +391,11 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
size_t color_buffer_offset_in_heap[4];
|
||||
if (rpcs3::state.config.rsx.opengl.write_color_buffers)
|
||||
{
|
||||
for (u8 i : get_rtt_indexes(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
for (u8 i : get_rtt_indexes(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
|
||||
{
|
||||
if (!address_color[i])
|
||||
continue;
|
||||
color_buffer_offset_in_heap[i] = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, m_rtts.bound_render_targets[i], m_surface.color_format);
|
||||
color_buffer_offset_in_heap[i] = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, std::get<1>(m_rtts.m_bound_render_targets[i]), m_surface.color_format);
|
||||
invalidate_address(address_color[i]);
|
||||
need_transfer = true;
|
||||
}
|
||||
@@ -555,10 +414,7 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
{
|
||||
auto ptr = vm::base(address_z);
|
||||
char *depth_buffer = (char*)ptr;
|
||||
void *buffer;
|
||||
// TODO: Use exact range
|
||||
CHECK_HRESULT(m_readback_resources.m_heap->Map(0, nullptr, &buffer));
|
||||
unsigned char *mapped_buffer = (unsigned char*)buffer + depth_buffer_offset_in_heap;
|
||||
u8 *mapped_buffer = m_readback_resources.map<u8>(depth_buffer_offset_in_heap);
|
||||
|
||||
for (unsigned row = 0; row < (unsigned)clip_h; row++)
|
||||
{
|
||||
@@ -571,28 +427,14 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
depth_buffer[4 * (row * clip_w + i) + 3] = c;
|
||||
}
|
||||
}
|
||||
m_readback_resources.m_heap->Unmap(0, nullptr);
|
||||
}
|
||||
|
||||
size_t srcPitch, dstPitch;
|
||||
switch (m_surface.color_format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_R5G6B5:
|
||||
srcPitch = align(clip_w * 2, 256);
|
||||
dstPitch = clip_w * 2;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_A8R8G8B8:
|
||||
srcPitch = align(clip_w * 4, 256);
|
||||
dstPitch = clip_w * 4;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16:
|
||||
srcPitch = align(clip_w * 8, 256);
|
||||
dstPitch = clip_w * 8;
|
||||
break;
|
||||
m_readback_resources.unmap();
|
||||
}
|
||||
|
||||
if (rpcs3::state.config.rsx.opengl.write_color_buffers)
|
||||
{
|
||||
size_t srcPitch = get_aligned_pitch(m_surface.color_format, clip_w);
|
||||
size_t dstPitch = get_packed_pitch(m_surface.color_format, clip_w);
|
||||
|
||||
void *dest_buffer[] =
|
||||
{
|
||||
vm::base(address_color[0]),
|
||||
@@ -601,7 +443,7 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
vm::base(address_color[3]),
|
||||
};
|
||||
|
||||
for (u8 i : get_rtt_indexes(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
|
||||
for (u8 i : get_rtt_indexes(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
|
||||
{
|
||||
if (!address_color[i])
|
||||
continue;
|
||||
@@ -611,111 +453,21 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
}
|
||||
|
||||
|
||||
void D3D12GSRender::copy_render_targets_to_memory(void *buffer, u8 rtt)
|
||||
std::array<std::vector<gsl::byte>, 4> D3D12GSRender::copy_render_targets_to_memory()
|
||||
{
|
||||
size_t heap_offset = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, m_rtts.bound_render_targets[rtt], m_surface.color_format);
|
||||
|
||||
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
|
||||
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
|
||||
get_current_resource_storage().set_new_command_list();
|
||||
|
||||
wait_for_command_queue(m_device.Get(), m_command_queue.Get());
|
||||
m_readback_resources.m_get_pos = m_readback_resources.get_current_put_pos_minus_one();
|
||||
|
||||
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
size_t srcPitch, dstPitch;
|
||||
switch (m_surface.color_format)
|
||||
{
|
||||
case CELL_GCM_SURFACE_R5G6B5:
|
||||
srcPitch = align(clip_w * 2, 256);
|
||||
dstPitch = clip_w * 2;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_A8R8G8B8:
|
||||
srcPitch = align(clip_w * 4, 256);
|
||||
dstPitch = clip_w * 4;
|
||||
break;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16:
|
||||
srcPitch = align(clip_w * 8, 256);
|
||||
dstPitch = clip_w * 8;
|
||||
break;
|
||||
}
|
||||
copy_readback_buffer_to_dest(buffer, m_readback_resources, heap_offset, srcPitch, dstPitch, clip_h);
|
||||
rsx::surface_info surface = {};
|
||||
surface.unpack(rsx::method_registers[NV4097_SET_SURFACE_FORMAT]);
|
||||
return m_rtts.get_render_targets_data(surface.color_format, clip_w, clip_h, m_device.Get(), m_command_queue.Get(), m_readback_resources, get_current_resource_storage());
|
||||
}
|
||||
|
||||
void D3D12GSRender::copy_depth_buffer_to_memory(void *buffer)
|
||||
std::array<std::vector<gsl::byte>, 2> D3D12GSRender::copy_depth_stencil_buffer_to_memory()
|
||||
{
|
||||
unsigned clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
unsigned clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
|
||||
size_t row_pitch = align(clip_w * 4, 256);
|
||||
|
||||
size_t buffer_size = row_pitch * clip_h;
|
||||
assert(m_readback_resources.can_alloc(buffer_size));
|
||||
size_t heap_offset = m_readback_resources.alloc(buffer_size);
|
||||
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.m_heap, { heap_offset,{ DXGI_FORMAT_R32_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(m_rtts.bound_depth_stencil, 0), nullptr);
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
|
||||
|
||||
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
|
||||
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
|
||||
get_current_resource_storage().set_new_command_list();
|
||||
|
||||
wait_for_command_queue(m_device.Get(), m_command_queue.Get());
|
||||
m_readback_resources.m_get_pos = m_readback_resources.get_current_put_pos_minus_one();
|
||||
|
||||
void *temp_buffer;
|
||||
CHECK_HRESULT(m_readback_resources.m_heap->Map(0, nullptr, &temp_buffer));
|
||||
void *mapped_buffer = (char*)temp_buffer + heap_offset;
|
||||
for (unsigned row = 0; row < clip_h; row++)
|
||||
{
|
||||
u32 *casted_dest = (u32*)((char*)buffer + row * clip_w * 4);
|
||||
u32 *casted_src = (u32*)((char*)mapped_buffer + row * row_pitch);
|
||||
for (unsigned col = 0; col < row_pitch / 4; col++)
|
||||
*casted_dest++ = *casted_src++;
|
||||
}
|
||||
m_readback_resources.m_heap->Unmap(0, nullptr);
|
||||
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
rsx::surface_info surface = {};
|
||||
surface.unpack(rsx::method_registers[NV4097_SET_SURFACE_FORMAT]);
|
||||
return m_rtts.get_depth_stencil_data(surface.depth_format, clip_w, clip_h, m_device.Get(), m_command_queue.Get(), m_readback_resources, get_current_resource_storage());
|
||||
}
|
||||
|
||||
|
||||
void D3D12GSRender::copy_stencil_buffer_to_memory(void *buffer)
|
||||
{
|
||||
unsigned clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
unsigned clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
|
||||
size_t row_pitch = align(clip_w * 4, 256);
|
||||
|
||||
size_t buffer_size = row_pitch * clip_h;
|
||||
assert(m_readback_resources.can_alloc(buffer_size));
|
||||
size_t heap_offset = m_readback_resources.alloc(buffer_size);
|
||||
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.m_heap, { heap_offset, { DXGI_FORMAT_R8_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(m_rtts.bound_depth_stencil, 1), nullptr);
|
||||
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
|
||||
|
||||
CHECK_HRESULT(get_current_resource_storage().command_list->Close());
|
||||
m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf());
|
||||
get_current_resource_storage().set_new_command_list();
|
||||
|
||||
wait_for_command_queue(m_device.Get(), m_command_queue.Get());
|
||||
m_readback_resources.m_get_pos = m_readback_resources.get_current_put_pos_minus_one();
|
||||
|
||||
void *temp_buffer;
|
||||
CHECK_HRESULT(m_readback_resources.m_heap->Map(0, nullptr, &temp_buffer));
|
||||
void *mapped_buffer = (char*)temp_buffer + heap_offset;
|
||||
for (unsigned row = 0; row < clip_h; row++)
|
||||
{
|
||||
char *casted_dest = (char*)buffer + row * clip_w;
|
||||
char *casted_src = (char*)mapped_buffer + row * row_pitch;
|
||||
for (unsigned col = 0; col < row_pitch; col++)
|
||||
*casted_dest++ = *casted_src++;
|
||||
}
|
||||
m_readback_resources.m_heap->Unmap(0, nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,31 +1,267 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <d3d12.h>
|
||||
#include "d3dx12.h"
|
||||
|
||||
struct render_targets
|
||||
#include "D3D12Formats.h"
|
||||
#include "D3D12MemoryHelpers.h"
|
||||
#include "../Common/surface_store.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
|
||||
struct render_target_traits
|
||||
{
|
||||
using surface_storage_type = ComPtr<ID3D12Resource>;
|
||||
using surface_type = ID3D12Resource*;
|
||||
using command_list_type = gsl::not_null<ID3D12GraphicsCommandList*>;
|
||||
using download_buffer_object = std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE>; // heap offset, size, last_put_pos, fence, handle
|
||||
|
||||
static
|
||||
ComPtr<ID3D12Resource> create_new_surface(
|
||||
u32 address,
|
||||
surface_color_format color_format, size_t width, size_t height,
|
||||
gsl::not_null<ID3D12Device*> device, const std::array<float, 4> &clear_color, float, u8)
|
||||
{
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(color_format);
|
||||
ComPtr<ID3D12Resource> rtt;
|
||||
LOG_WARNING(RSX, "Creating RTT");
|
||||
|
||||
D3D12_CLEAR_VALUE clear_color_value = {};
|
||||
clear_color_value.Format = dxgi_format;
|
||||
clear_color_value.Color[0] = clear_color[0];
|
||||
clear_color_value.Color[1] = clear_color[1];
|
||||
clear_color_value.Color[2] = clear_color[2];
|
||||
clear_color_value.Color[3] = clear_color[3];
|
||||
|
||||
device->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)width, (UINT)height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET),
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||
&clear_color_value,
|
||||
IID_PPV_ARGS(rtt.GetAddressOf())
|
||||
);
|
||||
|
||||
std::wstring name = L"rtt_@" + std::to_wstring(address);
|
||||
rtt->SetName(name.c_str());
|
||||
|
||||
return rtt;
|
||||
}
|
||||
|
||||
static
|
||||
void prepare_rtt_for_drawing(
|
||||
gsl::not_null<ID3D12GraphicsCommandList*> command_list,
|
||||
ID3D12Resource* rtt)
|
||||
{
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rtt, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET));
|
||||
}
|
||||
|
||||
static
|
||||
void prepare_rtt_for_sampling(
|
||||
gsl::not_null<ID3D12GraphicsCommandList*> command_list,
|
||||
ID3D12Resource* rtt)
|
||||
{
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rtt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
}
|
||||
|
||||
static
|
||||
ComPtr<ID3D12Resource> create_new_surface(
|
||||
u32 address,
|
||||
surface_depth_format surfaceDepthFormat, size_t width, size_t height,
|
||||
gsl::not_null<ID3D12Device*> device, const std::array<float, 4>& , float clear_depth, u8 clear_stencil)
|
||||
{
|
||||
D3D12_CLEAR_VALUE clear_depth_value = {};
|
||||
clear_depth_value.DepthStencil.Depth = clear_depth;
|
||||
clear_depth_value.DepthStencil.Stencil = clear_stencil;
|
||||
|
||||
DXGI_FORMAT dxgi_format = get_depth_stencil_typeless_surface_format(surfaceDepthFormat);
|
||||
clear_depth_value.Format = get_depth_stencil_surface_clear_format(surfaceDepthFormat);
|
||||
|
||||
ComPtr<ID3D12Resource> new_depth_stencil;
|
||||
device->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)width, (UINT)height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL),
|
||||
D3D12_RESOURCE_STATE_DEPTH_WRITE,
|
||||
&clear_depth_value,
|
||||
IID_PPV_ARGS(new_depth_stencil.GetAddressOf())
|
||||
);
|
||||
std::wstring name = L"ds_@" + std::to_wstring(address);
|
||||
new_depth_stencil->SetName(name.c_str());
|
||||
|
||||
return new_depth_stencil;
|
||||
}
|
||||
|
||||
static
|
||||
void prepare_ds_for_drawing(
|
||||
gsl::not_null<ID3D12GraphicsCommandList*> command_list,
|
||||
ID3D12Resource* ds)
|
||||
{
|
||||
// set the resource as depth write
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE));
|
||||
}
|
||||
|
||||
static
|
||||
void prepare_ds_for_sampling(
|
||||
gsl::not_null<ID3D12GraphicsCommandList*> command_list,
|
||||
ID3D12Resource* ds)
|
||||
{
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
bool rtt_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_color_format surface_color_format, size_t width, size_t height)
|
||||
{
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(surface_color_format);
|
||||
return rtt->GetDesc().Format == dxgi_format && rtt->GetDesc().Width == width && rtt->GetDesc().Height == height;
|
||||
}
|
||||
|
||||
static
|
||||
bool ds_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_depth_format surface_depth_stencil_format, size_t width, size_t height)
|
||||
{
|
||||
//TODO: Check format
|
||||
return rtt->GetDesc().Width == width && rtt->GetDesc().Height == height;
|
||||
}
|
||||
|
||||
static
|
||||
std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE> issue_download_command(
|
||||
gsl::not_null<ID3D12Resource*> rtt,
|
||||
surface_color_format color_format, size_t width, size_t height,
|
||||
gsl::not_null<ID3D12Device*> device, gsl::not_null<ID3D12CommandQueue*> command_queue, data_heap &readback_heap, resource_storage &res_store
|
||||
)
|
||||
{
|
||||
ID3D12GraphicsCommandList* command_list = res_store.command_list.Get();
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(color_format);
|
||||
size_t row_pitch = rsx::utility::get_aligned_pitch(color_format, gsl::narrow<u32>(width));
|
||||
|
||||
size_t buffer_size = row_pitch * height;
|
||||
size_t heap_offset = readback_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rtt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_heap.get_heap(), { heap_offset,{ dxgi_format, (UINT)width, (UINT)height, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(rtt, 0), nullptr);
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rtt, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET));
|
||||
|
||||
CHECK_HRESULT(command_list->Close());
|
||||
command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)res_store.command_list.GetAddressOf());
|
||||
res_store.set_new_command_list();
|
||||
|
||||
ComPtr<ID3D12Fence> fence;
|
||||
CHECK_HRESULT(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.GetAddressOf())));
|
||||
HANDLE handle = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
|
||||
fence->SetEventOnCompletion(1, handle);
|
||||
command_queue->Signal(fence.Get(), 1);
|
||||
|
||||
return std::make_tuple(heap_offset, buffer_size, readback_heap.get_current_put_pos_minus_one(), fence, handle);
|
||||
}
|
||||
|
||||
static
|
||||
std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE> issue_depth_download_command(
|
||||
gsl::not_null<ID3D12Resource*> ds,
|
||||
surface_depth_format depth_format, size_t width, size_t height,
|
||||
gsl::not_null<ID3D12Device*> device, gsl::not_null<ID3D12CommandQueue*> command_queue, data_heap &readback_heap, resource_storage &res_store
|
||||
)
|
||||
{
|
||||
ID3D12GraphicsCommandList* command_list = res_store.command_list.Get();
|
||||
DXGI_FORMAT dxgi_format = (depth_format == surface_depth_format::z24s8) ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R16_TYPELESS;
|
||||
|
||||
size_t row_pitch = align(width * 4, 256);
|
||||
size_t buffer_size = row_pitch * height;
|
||||
size_t heap_offset = readback_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_heap.get_heap(), { heap_offset,{ dxgi_format, (UINT)width, (UINT)height, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(ds, 0), nullptr);
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
|
||||
|
||||
CHECK_HRESULT(command_list->Close());
|
||||
command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)res_store.command_list.GetAddressOf());
|
||||
res_store.set_new_command_list();
|
||||
|
||||
ComPtr<ID3D12Fence> fence;
|
||||
CHECK_HRESULT(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.GetAddressOf())));
|
||||
HANDLE handle = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
|
||||
fence->SetEventOnCompletion(1, handle);
|
||||
command_queue->Signal(fence.Get(), 1);
|
||||
|
||||
return std::make_tuple(heap_offset, buffer_size, readback_heap.get_current_put_pos_minus_one(), fence, handle);
|
||||
}
|
||||
|
||||
static
|
||||
std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE> issue_stencil_download_command(
|
||||
gsl::not_null<ID3D12Resource*> stencil,
|
||||
size_t width, size_t height,
|
||||
gsl::not_null<ID3D12Device*> device, gsl::not_null<ID3D12CommandQueue*> command_queue, data_heap &readback_heap, resource_storage &res_store
|
||||
)
|
||||
{
|
||||
ID3D12GraphicsCommandList* command_list = res_store.command_list.Get();
|
||||
|
||||
size_t row_pitch = align(width, 256);
|
||||
size_t buffer_size = row_pitch * height;
|
||||
size_t heap_offset = readback_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
|
||||
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_heap.get_heap(), { heap_offset,{ DXGI_FORMAT_R8_TYPELESS, (UINT)width, (UINT)height, 1, (UINT)row_pitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(stencil, 1), nullptr);
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(stencil, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
|
||||
|
||||
CHECK_HRESULT(command_list->Close());
|
||||
command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)res_store.command_list.GetAddressOf());
|
||||
res_store.set_new_command_list();
|
||||
|
||||
ComPtr<ID3D12Fence> fence;
|
||||
CHECK_HRESULT(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.GetAddressOf())));
|
||||
HANDLE handle = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
|
||||
fence->SetEventOnCompletion(1, handle);
|
||||
command_queue->Signal(fence.Get(), 1);
|
||||
|
||||
return std::make_tuple(heap_offset, buffer_size, readback_heap.get_current_put_pos_minus_one(), fence, handle);
|
||||
}
|
||||
|
||||
static
|
||||
gsl::span<const gsl::byte> map_downloaded_buffer(const std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE> &sync_data,
|
||||
gsl::not_null<ID3D12Device*> device, gsl::not_null<ID3D12CommandQueue*> command_queue, data_heap &readback_heap, resource_storage &res_store)
|
||||
{
|
||||
size_t offset;
|
||||
size_t buffer_size;
|
||||
size_t current_put_pos_minus_one;
|
||||
HANDLE handle;
|
||||
std::tie(offset, buffer_size, current_put_pos_minus_one, std::ignore, handle) = sync_data;
|
||||
WaitForSingleObjectEx(handle, INFINITE, FALSE);
|
||||
CloseHandle(handle);
|
||||
|
||||
readback_heap.m_get_pos = current_put_pos_minus_one;
|
||||
const gsl::byte *mapped_buffer = readback_heap.map<const gsl::byte>(CD3DX12_RANGE(offset, offset + buffer_size));
|
||||
return { mapped_buffer , gsl::narrow<int>(buffer_size) };
|
||||
}
|
||||
|
||||
static
|
||||
void unmap_downloaded_buffer(const std::tuple<size_t, size_t, size_t, ComPtr<ID3D12Fence>, HANDLE> &sync_data,
|
||||
gsl::not_null<ID3D12Device*> device, gsl::not_null<ID3D12CommandQueue*> command_queue, data_heap &readback_heap, resource_storage &res_store)
|
||||
{
|
||||
readback_heap.unmap();
|
||||
}
|
||||
|
||||
static ID3D12Resource* get(const ComPtr<ID3D12Resource> &in)
|
||||
{
|
||||
return in.Get();
|
||||
}
|
||||
};
|
||||
|
||||
struct render_targets : public rsx::surface_store<render_target_traits>
|
||||
{
|
||||
INT g_descriptor_stride_rtv;
|
||||
std::unordered_map<u32, ComPtr<ID3D12Resource> > render_targets_storage;
|
||||
ID3D12Resource *bound_render_targets[4];
|
||||
u32 bound_render_targets_address[4];
|
||||
std::unordered_map<u32, ComPtr<ID3D12Resource> > depth_stencil_storage;
|
||||
ID3D12Resource *bound_depth_stencil;
|
||||
u32 bound_depth_stencil_address;
|
||||
|
||||
size_t bind_render_targets(ID3D12Device *, u32 color_format, D3D12_CPU_DESCRIPTOR_HANDLE);
|
||||
size_t bind_depth_stencil(ID3D12Device *, u32 depth_format, D3D12_CPU_DESCRIPTOR_HANDLE);
|
||||
|
||||
/**
|
||||
* If render target already exists at address, issue state change operation on cmdList.
|
||||
* Otherwise create one with width, height, clearColor info.
|
||||
* returns the corresponding render target resource.
|
||||
*/
|
||||
ID3D12Resource *bind_address_as_render_targets(ID3D12Device *device, ID3D12GraphicsCommandList *cmdList, u32 address,
|
||||
size_t width, size_t height, u8 surfaceColorFormat, const std::array<float, 4> &clearColor, ComPtr<ID3D12Resource> &dirtyDS);
|
||||
|
||||
ID3D12Resource *bind_address_as_depth_stencil(ID3D12Device *device, ID3D12GraphicsCommandList *cmdList, u32 address,
|
||||
size_t width, size_t height, u8 surfaceDepthFormat, float depthClear, u8 stencilClear, ComPtr<ID3D12Resource> &dirtyDS);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE current_rtts_handle;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE current_ds_handle;
|
||||
|
||||
void init(ID3D12Device *device);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -40,6 +40,31 @@ D3D12_SAMPLER_DESC get_sampler_desc(const rsx::texture &texture)
|
||||
return samplerDesc;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
CD3DX12_RESOURCE_DESC get_texture_description(const rsx::texture &texture)
|
||||
{
|
||||
const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
DXGI_FORMAT dxgi_format = get_texture_format(format);
|
||||
|
||||
if (texture.dimension() == 1) // 1D texture or cubemap
|
||||
{
|
||||
return CD3DX12_RESOURCE_DESC::Tex1D(dxgi_format, texture.width(), 1, texture.mipmap());
|
||||
}
|
||||
else if (texture.dimension() == 2) // 2D texture or cubemap
|
||||
{
|
||||
// if (texture.depth() < 2);
|
||||
size_t depth = (texture.cubemap()) ? 6 : 1;
|
||||
return CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, texture.width(), texture.height(), (UINT)depth, texture.mipmap());
|
||||
}
|
||||
else if (texture.dimension() == 3) // 3d texture
|
||||
{
|
||||
return CD3DX12_RESOURCE_DESC::Tex3D(dxgi_format, texture.width(), texture.height(), texture.depth(), texture.mipmap());
|
||||
}
|
||||
throw EXCEPTION("Unknow texture dimension");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a texture residing in default heap and generate uploads commands in commandList,
|
||||
@@ -49,41 +74,32 @@ ComPtr<ID3D12Resource> upload_single_texture(
|
||||
const rsx::texture &texture,
|
||||
ID3D12Device *device,
|
||||
ID3D12GraphicsCommandList *command_list,
|
||||
data_heap<ID3D12Resource, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT> &texture_buffer_heap)
|
||||
data_heap &texture_buffer_heap)
|
||||
{
|
||||
size_t w = texture.width(), h = texture.height();
|
||||
size_t depth = texture.depth();
|
||||
if (depth == 0) depth = 1;
|
||||
if (texture.cubemap()) depth *= 6;
|
||||
|
||||
const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
DXGI_FORMAT dxgi_format = get_texture_format(format);
|
||||
|
||||
size_t buffer_size = get_placed_texture_storage_size(texture, 256);
|
||||
assert(texture_buffer_heap.can_alloc(buffer_size));
|
||||
size_t heap_offset = texture_buffer_heap.alloc(buffer_size);
|
||||
size_t heap_offset = texture_buffer_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
void *buffer;
|
||||
CHECK_HRESULT(texture_buffer_heap.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), &buffer));
|
||||
void *mapped_buffer = (char*)buffer + heap_offset;
|
||||
void *mapped_buffer = texture_buffer_heap.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
std::vector<MipmapLevelInfo> mipInfos = upload_placed_texture(texture, 256, mapped_buffer);
|
||||
texture_buffer_heap.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
texture_buffer_heap.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
ComPtr<ID3D12Resource> result;
|
||||
CHECK_HRESULT(device->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)w, (UINT)h, (UINT)depth, texture.mipmap()),
|
||||
&get_texture_description(texture),
|
||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(result.GetAddressOf())
|
||||
));
|
||||
|
||||
const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
DXGI_FORMAT dxgi_format = get_texture_format(format);
|
||||
size_t mip_level = 0;
|
||||
for (const MipmapLevelInfo mli : mipInfos)
|
||||
{
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(result.Get(), (UINT)mip_level), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.m_heap, { heap_offset + mli.offset, { dxgi_format, (UINT)mli.width, (UINT)mli.height, 1, (UINT)mli.rowPitch } }), nullptr);
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset, { dxgi_format, (UINT)mli.width, (UINT)mli.height, (UINT)mli.depth, (UINT)mli.rowPitch } }), nullptr);
|
||||
mip_level++;
|
||||
}
|
||||
|
||||
@@ -97,7 +113,7 @@ ComPtr<ID3D12Resource> upload_single_texture(
|
||||
void update_existing_texture(
|
||||
const rsx::texture &texture,
|
||||
ID3D12GraphicsCommandList *command_list,
|
||||
data_heap<ID3D12Resource, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT> &texture_buffer_heap,
|
||||
data_heap &texture_buffer_heap,
|
||||
ID3D12Resource *existing_texture)
|
||||
{
|
||||
size_t w = texture.width(), h = texture.height();
|
||||
@@ -106,34 +122,63 @@ void update_existing_texture(
|
||||
DXGI_FORMAT dxgi_format = get_texture_format(format);
|
||||
|
||||
size_t buffer_size = get_placed_texture_storage_size(texture, 256);
|
||||
assert(texture_buffer_heap.can_alloc(buffer_size));
|
||||
size_t heap_offset = texture_buffer_heap.alloc(buffer_size);
|
||||
size_t heap_offset = texture_buffer_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
|
||||
|
||||
void *buffer;
|
||||
CHECK_HRESULT(texture_buffer_heap.m_heap->Map(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size), &buffer));
|
||||
void *mapped_buffer = (char*)buffer + heap_offset;
|
||||
void *mapped_buffer = texture_buffer_heap.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
std::vector<MipmapLevelInfo> mipInfos = upload_placed_texture(texture, 256, mapped_buffer);
|
||||
texture_buffer_heap.m_heap->Unmap(0, &CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
texture_buffer_heap.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existing_texture, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COPY_DEST));
|
||||
size_t miplevel = 0;
|
||||
for (const MipmapLevelInfo mli : mipInfos)
|
||||
{
|
||||
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(existing_texture, (UINT)miplevel), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.m_heap, { heap_offset + mli.offset,{ dxgi_format, (UINT)mli.width, (UINT)mli.height, 1, (UINT)mli.rowPitch } }), nullptr);
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset,{ dxgi_format, (UINT)mli.width, (UINT)mli.height, (UINT)mli.depth, (UINT)mli.rowPitch } }), nullptr);
|
||||
miplevel++;
|
||||
}
|
||||
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existing_texture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
}
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC get_srv_descriptor_with_dimensions(const rsx::texture &tex)
|
||||
{
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shared_resource_view_desc = {};
|
||||
if (tex.dimension() == 1)
|
||||
{
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
|
||||
shared_resource_view_desc.Texture1D.MipLevels = tex.mipmap();
|
||||
return shared_resource_view_desc;
|
||||
}
|
||||
if (tex.dimension() == 2)
|
||||
{
|
||||
if (tex.cubemap())
|
||||
{
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||
shared_resource_view_desc.TextureCube.MipLevels = tex.mipmap();
|
||||
return shared_resource_view_desc;
|
||||
}
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
shared_resource_view_desc.Texture2D.MipLevels = tex.mipmap();
|
||||
return shared_resource_view_desc;
|
||||
}
|
||||
if (tex.dimension() == 3)
|
||||
{
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
|
||||
shared_resource_view_desc.Texture3D.MipLevels = tex.mipmap();
|
||||
return shared_resource_view_desc;
|
||||
}
|
||||
throw EXCEPTION("Wrong texture dimension %d", tex.dimension());
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_list, size_t descriptor_index, size_t texture_count)
|
||||
void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_list, size_t texture_count)
|
||||
{
|
||||
size_t used_texture = 0;
|
||||
|
||||
for (u32 i = 0; i < rsx::limits::textures_count; ++i)
|
||||
for (u32 i = 0; i < 16; ++i)
|
||||
{
|
||||
if (!m_textures_dirty[i])
|
||||
continue;
|
||||
m_textures_dirty[i] = false;
|
||||
|
||||
if (!textures[i].enabled())
|
||||
{
|
||||
// Now fill remaining texture slots with dummy texture/sampler
|
||||
@@ -147,21 +192,14 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0);
|
||||
m_device->CreateShaderResourceView(m_dummy_texture, &shader_resource_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)descriptor_index + (INT)used_texture, g_descriptor_stride_srv_cbv_uav)
|
||||
);
|
||||
m_current_shader_resources[i] = std::make_tuple(m_dummy_texture, shader_resource_view_desc);
|
||||
|
||||
D3D12_SAMPLER_DESC sampler_desc = {};
|
||||
sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
sampler_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
m_device->CreateSampler(&sampler_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().sampler_descriptor_heap[get_current_resource_storage().sampler_descriptors_heap_index]->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)get_current_resource_storage().current_sampler_index + (INT)used_texture, g_descriptor_stride_samplers)
|
||||
);
|
||||
used_texture++;
|
||||
m_current_samplers[i] = sampler_desc;
|
||||
continue;
|
||||
}
|
||||
size_t w = textures[i].width(), h = textures[i].height();
|
||||
@@ -173,25 +211,22 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_
|
||||
bool is_swizzled = !(textures[i].format() & CELL_GCM_TEXTURE_LN);
|
||||
|
||||
ID3D12Resource *vram_texture;
|
||||
std::unordered_map<u32, ComPtr<ID3D12Resource> >::const_iterator ItRTT = m_rtts.render_targets_storage.find(texaddr);
|
||||
std::unordered_map<u32, ComPtr<ID3D12Resource> >::const_iterator ItDS = m_rtts.depth_stencil_storage.find(texaddr);
|
||||
std::pair<texture_entry, ComPtr<ID3D12Resource> > *cached_texture = m_texture_cache.find_data_if_available(texaddr);
|
||||
bool is_render_target = false, is_depth_stencil_texture = false;
|
||||
if (ItRTT != m_rtts.render_targets_storage.end())
|
||||
|
||||
if (vram_texture = m_rtts.get_texture_from_render_target_if_applicable(texaddr))
|
||||
{
|
||||
vram_texture = ItRTT->second.Get();
|
||||
is_render_target = true;
|
||||
}
|
||||
else if (ItDS != m_rtts.depth_stencil_storage.end())
|
||||
else if (vram_texture = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr))
|
||||
{
|
||||
vram_texture = ItDS->second.Get();
|
||||
is_depth_stencil_texture = true;
|
||||
}
|
||||
else if (cached_texture != nullptr && (cached_texture->first == texture_entry(format, w, h, textures[i].mipmap())))
|
||||
else if (cached_texture != nullptr && (cached_texture->first == texture_entry(format, w, h, textures[i].depth(), textures[i].mipmap())))
|
||||
{
|
||||
if (cached_texture->first.m_is_dirty)
|
||||
{
|
||||
update_existing_texture(textures[i], command_list, m_texture_upload_data, cached_texture->second.Get());
|
||||
update_existing_texture(textures[i], command_list, m_buffer_data, cached_texture->second.Get());
|
||||
m_texture_cache.protect_data(texaddr, texaddr, get_texture_size(textures[i]));
|
||||
}
|
||||
vram_texture = cached_texture->second.Get();
|
||||
@@ -200,24 +235,14 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_
|
||||
{
|
||||
if (cached_texture != nullptr)
|
||||
get_current_resource_storage().dirty_textures.push_back(m_texture_cache.remove_from_cache(texaddr));
|
||||
ComPtr<ID3D12Resource> tex = upload_single_texture(textures[i], m_device.Get(), command_list, m_texture_upload_data);
|
||||
ComPtr<ID3D12Resource> tex = upload_single_texture(textures[i], m_device.Get(), command_list, m_buffer_data);
|
||||
std::wstring name = L"texture_@" + std::to_wstring(texaddr);
|
||||
tex->SetName(name.c_str());
|
||||
vram_texture = tex.Get();
|
||||
m_texture_cache.store_and_protect_data(texaddr, texaddr, get_texture_size(textures[i]), format, w, h, textures[i].mipmap(), tex);
|
||||
m_texture_cache.store_and_protect_data(texaddr, texaddr, get_texture_size(textures[i]), format, w, h, textures[i].depth(), textures[i].mipmap(), tex);
|
||||
}
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shared_resource_view_desc = {};
|
||||
if (textures[i].cubemap())
|
||||
{
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||
shared_resource_view_desc.TextureCube.MipLevels = textures[i].mipmap();
|
||||
}
|
||||
else
|
||||
{
|
||||
shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
shared_resource_view_desc.Texture2D.MipLevels = textures[i].mipmap();
|
||||
}
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shared_resource_view_desc = get_srv_descriptor_with_dimensions(textures[i]);
|
||||
shared_resource_view_desc.Format = get_texture_format(format);
|
||||
|
||||
switch (format)
|
||||
@@ -327,9 +352,7 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_
|
||||
break;
|
||||
}
|
||||
|
||||
m_device->CreateShaderResourceView(vram_texture, &shared_resource_view_desc,
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((UINT)descriptor_index + (UINT)used_texture, g_descriptor_stride_srv_cbv_uav));
|
||||
m_current_shader_resources[i] = std::make_tuple(vram_texture, shared_resource_view_desc);
|
||||
|
||||
if (get_current_resource_storage().current_sampler_index + 16 > 2048)
|
||||
{
|
||||
@@ -343,13 +366,7 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_
|
||||
};
|
||||
command_list->SetDescriptorHeaps(2, descriptors);
|
||||
}
|
||||
m_device->CreateSampler(&get_sampler_desc(textures[i]),
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().sampler_descriptor_heap[get_current_resource_storage().sampler_descriptors_heap_index]->GetCPUDescriptorHandleForHeapStart())
|
||||
.Offset((UINT)get_current_resource_storage().current_sampler_index + (UINT)used_texture, g_descriptor_stride_samplers));
|
||||
|
||||
used_texture++;
|
||||
m_current_samplers[i] = get_sampler_desc(textures[i]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -28,12 +28,7 @@ std::pair<ID3DBlob *, ID3DBlob *> compileF32toU8CS()
|
||||
|
||||
ID3DBlob *bytecode;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
|
||||
HRESULT hr = wrapD3DCompile(shaderCode, strlen(shaderCode), "test", nullptr, nullptr, "main", "cs_5_0", 0, 0, &bytecode, errorBlob.GetAddressOf());
|
||||
if (hr != S_OK)
|
||||
{
|
||||
const char *tmp = (const char*)errorBlob->GetBufferPointer();
|
||||
LOG_ERROR(RSX, tmp);
|
||||
}
|
||||
CHECK_HRESULT(wrapD3DCompile(shaderCode, strlen(shaderCode), "test", nullptr, nullptr, "main", "cs_5_0", 0, 0, &bytecode, errorBlob.GetAddressOf()));
|
||||
CD3DX12_DESCRIPTOR_RANGE descriptorRange[] =
|
||||
{
|
||||
// Textures
|
||||
@@ -47,18 +42,12 @@ std::pair<ID3DBlob *, ID3DBlob *> compileF32toU8CS()
|
||||
|
||||
ID3DBlob *rootSignatureBlob;
|
||||
|
||||
hr = wrapD3D12SerializeRootSignature(&CD3DX12_ROOT_SIGNATURE_DESC(1, &RP), D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob);
|
||||
if (hr != S_OK)
|
||||
{
|
||||
const char *tmp = (const char*)errorBlob->GetBufferPointer();
|
||||
LOG_ERROR(RSX, tmp);
|
||||
}
|
||||
|
||||
CHECK_HRESULT(wrapD3D12SerializeRootSignature(&CD3DX12_ROOT_SIGNATURE_DESC(1, &RP), D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob));
|
||||
return std::make_pair(bytecode, rootSignatureBlob);
|
||||
}
|
||||
|
||||
|
||||
void D3D12GSRender::Shader::Init(ID3D12Device *device, ID3D12CommandQueue *gfxcommandqueue)
|
||||
void D3D12GSRender::shader::init(ID3D12Device *device, ID3D12CommandQueue *gfx_command_queue)
|
||||
{
|
||||
const char *fsCode = STRINGIFY(
|
||||
Texture2D InputTexture : register(t0); \n
|
||||
@@ -78,12 +67,7 @@ void D3D12GSRender::Shader::Init(ID3D12Device *device, ID3D12CommandQueue *gfxco
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> fsBytecode;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
|
||||
HRESULT hr = wrapD3DCompile(fsCode, strlen(fsCode), "test", nullptr, nullptr, "main", "ps_5_0", 0, 0, &fsBytecode, errorBlob.GetAddressOf());
|
||||
if (hr != S_OK)
|
||||
{
|
||||
const char *tmp = (const char*)errorBlob->GetBufferPointer();
|
||||
LOG_ERROR(RSX, tmp);
|
||||
}
|
||||
CHECK_HRESULT(wrapD3DCompile(fsCode, strlen(fsCode), "test", nullptr, nullptr, "main", "ps_5_0", 0, 0, &fsBytecode, errorBlob.GetAddressOf()));
|
||||
|
||||
const char *vsCode = STRINGIFY(
|
||||
struct VertexInput \n
|
||||
@@ -108,12 +92,7 @@ void D3D12GSRender::Shader::Init(ID3D12Device *device, ID3D12CommandQueue *gfxco
|
||||
);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> vsBytecode;
|
||||
hr = wrapD3DCompile(vsCode, strlen(vsCode), "test", nullptr, nullptr, "main", "vs_5_0", 0, 0, &vsBytecode, errorBlob.GetAddressOf());
|
||||
if (hr != S_OK)
|
||||
{
|
||||
const char *tmp = (const char*)errorBlob->GetBufferPointer();
|
||||
LOG_ERROR(RSX, tmp);
|
||||
}
|
||||
CHECK_HRESULT(wrapD3DCompile(vsCode, strlen(vsCode), "test", nullptr, nullptr, "main", "vs_5_0", 0, 0, &vsBytecode, errorBlob.GetAddressOf()));
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
|
||||
psoDesc.PS.BytecodeLength = fsBytecode->GetBufferSize();
|
||||
@@ -163,28 +142,22 @@ void D3D12GSRender::Shader::Init(ID3D12Device *device, ID3D12CommandQueue *gfxco
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> rootSignatureBlob;
|
||||
|
||||
hr = wrapD3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob);
|
||||
if (hr != S_OK)
|
||||
{
|
||||
const char *tmp = (const char*)errorBlob->GetBufferPointer();
|
||||
LOG_ERROR(RSX, tmp);
|
||||
}
|
||||
CHECK_HRESULT(wrapD3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob));
|
||||
CHECK_HRESULT(device->CreateRootSignature(0, rootSignatureBlob->GetBufferPointer(), rootSignatureBlob->GetBufferSize(), IID_PPV_ARGS(&root_signature)));
|
||||
|
||||
hr = device->CreateRootSignature(0, rootSignatureBlob->GetBufferPointer(), rootSignatureBlob->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature));
|
||||
|
||||
psoDesc.pRootSignature = m_rootSignature;
|
||||
psoDesc.pRootSignature = root_signature;
|
||||
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||
|
||||
CHECK_HRESULT(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_PSO)));
|
||||
CHECK_HRESULT(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pso)));
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC textureHeapDesc = { D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV , 2, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
|
||||
CHECK_HRESULT(
|
||||
device->CreateDescriptorHeap(&textureHeapDesc, IID_PPV_ARGS(&m_textureDescriptorHeap))
|
||||
device->CreateDescriptorHeap(&textureHeapDesc, IID_PPV_ARGS(&texture_descriptor_heap))
|
||||
);
|
||||
D3D12_DESCRIPTOR_HEAP_DESC samplerHeapDesc = { D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER , 2, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
|
||||
CHECK_HRESULT(
|
||||
device->CreateDescriptorHeap(&samplerHeapDesc, IID_PPV_ARGS(&m_samplerDescriptorHeap))
|
||||
device->CreateDescriptorHeap(&samplerHeapDesc, IID_PPV_ARGS(&sampler_descriptor_heap))
|
||||
);
|
||||
|
||||
ComPtr<ID3D12Fence> fence;
|
||||
@@ -224,37 +197,37 @@ void D3D12GSRender::Shader::Init(ID3D12Device *device, ID3D12CommandQueue *gfxco
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(16 * sizeof(float)),
|
||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&m_vertexBuffer)
|
||||
IID_PPV_ARGS(&vertex_buffer)
|
||||
));
|
||||
|
||||
D3D12_SUBRESOURCE_DATA vertexData = { reinterpret_cast<BYTE*>(quadVertex), 16 * sizeof(float), 1 };
|
||||
|
||||
UpdateSubresources(cmdList.Get(), m_vertexBuffer, intermediateBuffer.Get(), 0, 0, 1, &vertexData);
|
||||
cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));
|
||||
UpdateSubresources(cmdList.Get(), vertex_buffer, intermediateBuffer.Get(), 0, 0, 1, &vertexData);
|
||||
cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(vertex_buffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));
|
||||
CHECK_HRESULT(cmdList->Close());
|
||||
|
||||
gfxcommandqueue->ExecuteCommandLists(1, CommandListCast(cmdList.GetAddressOf()));
|
||||
gfx_command_queue->ExecuteCommandLists(1, CommandListCast(cmdList.GetAddressOf()));
|
||||
|
||||
// Now wait until upload has completed
|
||||
gfxcommandqueue->Signal(fence.Get(), 1);
|
||||
gfx_command_queue->Signal(fence.Get(), 1);
|
||||
WaitForSingleObjectEx(handle, INFINITE, FALSE);
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
void D3D12GSRender::initConvertShader()
|
||||
void D3D12GSRender::init_convert_shader()
|
||||
{
|
||||
const auto &p = compileF32toU8CS();
|
||||
CHECK_HRESULT(
|
||||
m_device->CreateRootSignature(0, p.second->GetBufferPointer(), p.second->GetBufferSize(), IID_PPV_ARGS(&m_convertRootSignature))
|
||||
m_device->CreateRootSignature(0, p.second->GetBufferPointer(), p.second->GetBufferSize(), IID_PPV_ARGS(&m_convert_root_signature))
|
||||
);
|
||||
|
||||
D3D12_COMPUTE_PIPELINE_STATE_DESC computePipelineStateDesc = {};
|
||||
computePipelineStateDesc.CS.BytecodeLength = p.first->GetBufferSize();
|
||||
computePipelineStateDesc.CS.pShaderBytecode = p.first->GetBufferPointer();
|
||||
computePipelineStateDesc.pRootSignature = m_convertRootSignature;
|
||||
computePipelineStateDesc.pRootSignature = m_convert_root_signature;
|
||||
|
||||
CHECK_HRESULT(
|
||||
m_device->CreateComputePipelineState(&computePipelineStateDesc, IID_PPV_ARGS(&m_convertPSO))
|
||||
m_device->CreateComputePipelineState(&computePipelineStateDesc, IID_PPV_ARGS(&m_convert_pso))
|
||||
);
|
||||
|
||||
p.first->Release();
|
||||
|
||||
@@ -33,39 +33,43 @@ void D3D12VertexProgramDecompiler::insertHeader(std::stringstream &OS)
|
||||
OS << " float4x4 scaleOffsetMat;" << std::endl;
|
||||
OS << " int isAlphaTested;" << std::endl;
|
||||
OS << " float alphaRef;" << std::endl;
|
||||
OS << " int tex0_is_unorm;" << std::endl;
|
||||
OS << " int tex1_is_unorm;" << std::endl;
|
||||
OS << " int tex2_is_unorm;" << std::endl;
|
||||
OS << " int tex3_is_unorm;" << std::endl;
|
||||
OS << " int tex4_is_unorm;" << std::endl;
|
||||
OS << " int tex5_is_unorm;" << std::endl;
|
||||
OS << " int tex6_is_unorm;" << std::endl;
|
||||
OS << " int tex7_is_unorm;" << std::endl;
|
||||
OS << " int tex8_is_unorm;" << std::endl;
|
||||
OS << " int tex9_is_unorm;" << std::endl;
|
||||
OS << " int tex10_is_unorm;" << std::endl;
|
||||
OS << " int tex11_is_unorm;" << std::endl;
|
||||
OS << " int tex12_is_unorm;" << std::endl;
|
||||
OS << " int tex13_is_unorm;" << std::endl;
|
||||
OS << " int tex14_is_unorm;" << std::endl;
|
||||
OS << " int tex15_is_unorm;" << std::endl;
|
||||
OS << "};" << std::endl;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool declare_input(std::stringstream & OS, const std::tuple<size_t, std::string> &attribute, const std::vector<rsx_vertex_input> &inputs, size_t reg)
|
||||
{
|
||||
for (const auto &real_input : inputs)
|
||||
{
|
||||
if (static_cast<size_t>(real_input.location) != std::get<0>(attribute))
|
||||
continue;
|
||||
OS << "Buffer<float4> " << std::get<1>(attribute) << "_buffer : register(t" << reg++ << ");\n";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12VertexProgramDecompiler::insertInputs(std::stringstream & OS, const std::vector<ParamType>& inputs)
|
||||
{
|
||||
OS << "struct VertexInput" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
std::vector<std::tuple<size_t, std::string>> input_data;
|
||||
for (const ParamType PT : inputs)
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
OS << " " << PT.type << " " << PI.name << ": TEXCOORD" << PI.location << ";" << std::endl;
|
||||
input_slots.push_back(PI.location);
|
||||
input_data.push_back(std::make_tuple(PI.location, PI.name));
|
||||
}
|
||||
}
|
||||
OS << "};" << std::endl;
|
||||
|
||||
std::sort(input_data.begin(), input_data.end());
|
||||
|
||||
size_t t_register = 0;
|
||||
for (const auto &attribute : input_data)
|
||||
{
|
||||
if (declare_input(OS, attribute, rsx_vertex_program.rsx_vertex_inputs, t_register))
|
||||
t_register++;
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12VertexProgramDecompiler::insertConstants(std::stringstream & OS, const std::vector<ParamType> & constants)
|
||||
@@ -140,9 +144,41 @@ static const reg_info reg_table[] =
|
||||
{ "tc8", true, "dst_reg15", "", false },
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
void add_input(std::stringstream & OS, const ParamItem &PI, const std::vector<rsx_vertex_input> &inputs)
|
||||
{
|
||||
for (const auto &real_input : inputs)
|
||||
{
|
||||
if (real_input.location != PI.location)
|
||||
continue;
|
||||
if (!real_input.is_array)
|
||||
{
|
||||
OS << " float4 " << PI.name << " = " << PI.name << "_buffer[0];\n";
|
||||
return;
|
||||
}
|
||||
if (real_input.frequency > 1)
|
||||
{
|
||||
if (real_input.is_modulo)
|
||||
{
|
||||
OS << " float4 " << PI.name << " = " << PI.name << "_buffer[vertex_id % " << real_input.frequency << "];\n";
|
||||
return;
|
||||
}
|
||||
OS << " float4 " << PI.name << " = " << PI.name << "_buffer[vertex_id / " << real_input.frequency << "];\n";
|
||||
return;
|
||||
}
|
||||
OS << " float4 " << PI.name << " = " << PI.name << "_buffer[vertex_id];\n";
|
||||
return;
|
||||
}
|
||||
OS << " float4 " << PI.name << " = float4(0., 0., 0., 1.);\n";
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12VertexProgramDecompiler::insertMainStart(std::stringstream & OS)
|
||||
{
|
||||
OS << "PixelInput main(VertexInput In)" << std::endl;
|
||||
insert_d3d12_legacy_function(OS);
|
||||
|
||||
OS << "PixelInput main(uint vertex_id : SV_VertexID)" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
|
||||
// Declare inside main function
|
||||
@@ -162,7 +198,9 @@ void D3D12VertexProgramDecompiler::insertMainStart(std::stringstream & OS)
|
||||
for (const ParamType PT : m_parr.params[PF_PARAM_IN])
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
|
||||
{
|
||||
add_input(OS, PI, rsx_vertex_program.rsx_vertex_inputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,8 +219,8 @@ void D3D12VertexProgramDecompiler::insertMainEnd(std::stringstream & OS)
|
||||
OS << "}" << std::endl;
|
||||
}
|
||||
|
||||
D3D12VertexProgramDecompiler::D3D12VertexProgramDecompiler(std::vector<u32>& data) :
|
||||
VertexProgramDecompiler(data)
|
||||
D3D12VertexProgramDecompiler::D3D12VertexProgramDecompiler(const RSXVertexProgram &prog) :
|
||||
VertexProgramDecompiler(prog), rsx_vertex_program(prog)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,8 @@ protected:
|
||||
virtual void insertOutputs(std::stringstream &OS, const std::vector<ParamType> &outputs);
|
||||
virtual void insertMainStart(std::stringstream &OS);
|
||||
virtual void insertMainEnd(std::stringstream &OS);
|
||||
|
||||
const RSXVertexProgram &rsx_vertex_program;
|
||||
public:
|
||||
std::vector<size_t> input_slots;
|
||||
D3D12VertexProgramDecompiler(std::vector<u32>& data);
|
||||
D3D12VertexProgramDecompiler(const RSXVertexProgram &prog);
|
||||
};
|
||||
|
||||
+271
-50
@@ -719,6 +719,156 @@ namespace
|
||||
};
|
||||
}
|
||||
|
||||
rsx::vertex_base_type rsx::to_vertex_base_type(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case 1: return rsx::vertex_base_type::s1;
|
||||
case 2: return rsx::vertex_base_type::f;
|
||||
case 3: return rsx::vertex_base_type::sf;
|
||||
case 4: return rsx::vertex_base_type::ub;
|
||||
case 5: return rsx::vertex_base_type::s32k;
|
||||
case 6: return rsx::vertex_base_type::cmp;
|
||||
case 7: return rsx::vertex_base_type::ub256;
|
||||
}
|
||||
throw new EXCEPTION("Unknow vertex base type %d", in);
|
||||
}
|
||||
|
||||
rsx::index_array_type rsx::to_index_array_type(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case 0: return rsx::index_array_type::u32;
|
||||
case 1: return rsx::index_array_type::u16;
|
||||
}
|
||||
throw new EXCEPTION("Unknown index array type %d", in);
|
||||
}
|
||||
|
||||
rsx::primitive_type rsx::to_primitive_type(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case 1: return rsx::primitive_type::points;
|
||||
case 2: return rsx::primitive_type::lines;
|
||||
case 3: return rsx::primitive_type::line_loop;
|
||||
case 4: return rsx::primitive_type::line_strip;
|
||||
case 5: return rsx::primitive_type::triangles;
|
||||
case 6: return rsx::primitive_type::triangle_strip;
|
||||
case 7: return rsx::primitive_type::triangle_fan;
|
||||
case 8: return rsx::primitive_type::quads;
|
||||
case 9: return rsx::primitive_type::quad_strip;
|
||||
case 10: return rsx::primitive_type::polygon;
|
||||
}
|
||||
throw new EXCEPTION("Unknow primitive type %d", in);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_GCM_WINDOW_ORIGIN_TOP = 0,
|
||||
CELL_GCM_WINDOW_ORIGIN_BOTTOM = 1,
|
||||
CELL_GCM_WINDOW_PIXEL_CENTER_HALF = 0,
|
||||
CELL_GCM_WINDOW_PIXEL_CENTER_INTEGER = 1,
|
||||
};
|
||||
|
||||
rsx::window_origin rsx::to_window_origin(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_WINDOW_ORIGIN_TOP: return rsx::window_origin::top;
|
||||
case CELL_GCM_WINDOW_ORIGIN_BOTTOM: return rsx::window_origin::bottom;
|
||||
}
|
||||
throw EXCEPTION("Unknow window origin modifier %x", in);
|
||||
}
|
||||
|
||||
rsx::window_pixel_center rsx::to_window_pixel_center(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_WINDOW_PIXEL_CENTER_HALF: return rsx::window_pixel_center::half;
|
||||
case CELL_GCM_WINDOW_PIXEL_CENTER_INTEGER: return rsx::window_pixel_center::integer;
|
||||
}
|
||||
throw EXCEPTION("Unknow window pixel center %x", in);
|
||||
}
|
||||
|
||||
rsx::comparaison_function rsx::to_comparaison_function(u16 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_NEVER: return rsx::comparaison_function::never;
|
||||
case CELL_GCM_LESS: return rsx::comparaison_function::less;
|
||||
case CELL_GCM_EQUAL: return rsx::comparaison_function::equal;
|
||||
case CELL_GCM_LEQUAL: return rsx::comparaison_function::less_or_equal;
|
||||
case CELL_GCM_GREATER: return rsx::comparaison_function::greater;
|
||||
case CELL_GCM_NOTEQUAL: return rsx::comparaison_function::not_equal;
|
||||
case CELL_GCM_GEQUAL: return rsx::comparaison_function::greater_or_equal;
|
||||
case CELL_GCM_ALWAYS: return rsx::comparaison_function::always;
|
||||
}
|
||||
throw EXCEPTION("Wrong comparaison function %x", in);
|
||||
}
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
// Surface Target
|
||||
CELL_GCM_SURFACE_TARGET_NONE = 0,
|
||||
CELL_GCM_SURFACE_TARGET_0 = 1,
|
||||
CELL_GCM_SURFACE_TARGET_1 = 2,
|
||||
CELL_GCM_SURFACE_TARGET_MRT1 = 0x13,
|
||||
CELL_GCM_SURFACE_TARGET_MRT2 = 0x17,
|
||||
CELL_GCM_SURFACE_TARGET_MRT3 = 0x1f,
|
||||
|
||||
// Surface Depth
|
||||
CELL_GCM_SURFACE_Z16 = 1,
|
||||
CELL_GCM_SURFACE_Z24S8 = 2,
|
||||
|
||||
// Surface Antialias
|
||||
CELL_GCM_SURFACE_CENTER_1 = 0,
|
||||
CELL_GCM_SURFACE_DIAGONAL_CENTERED_2 = 3,
|
||||
CELL_GCM_SURFACE_SQUARE_CENTERED_4 = 4,
|
||||
CELL_GCM_SURFACE_SQUARE_ROTATED_4 = 5,
|
||||
|
||||
// Surface format
|
||||
CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5 = 1,
|
||||
CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5 = 2,
|
||||
CELL_GCM_SURFACE_R5G6B5 = 3,
|
||||
CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8 = 4,
|
||||
CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8 = 5,
|
||||
CELL_GCM_SURFACE_A8R8G8B8 = 8,
|
||||
CELL_GCM_SURFACE_B8 = 9,
|
||||
CELL_GCM_SURFACE_G8B8 = 10,
|
||||
CELL_GCM_SURFACE_F_W16Z16Y16X16 = 11,
|
||||
CELL_GCM_SURFACE_F_W32Z32Y32X32 = 12,
|
||||
CELL_GCM_SURFACE_F_X32 = 13,
|
||||
CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8 = 14,
|
||||
CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8 = 15,
|
||||
CELL_GCM_SURFACE_A8B8G8R8 = 16,
|
||||
|
||||
};
|
||||
|
||||
rsx::surface_target rsx::to_surface_target(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE: return rsx::surface_target::none;
|
||||
case CELL_GCM_SURFACE_TARGET_0: return rsx::surface_target::surface_a;
|
||||
case CELL_GCM_SURFACE_TARGET_1: return rsx::surface_target::surface_b;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1: return rsx::surface_target::surfaces_a_b;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2: return rsx::surface_target::surfaces_a_b_c;
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3: return rsx::surface_target::surfaces_a_b_c_d;
|
||||
}
|
||||
throw EXCEPTION("Unknow surface target %x", in);
|
||||
}
|
||||
|
||||
rsx::surface_depth_format rsx::to_surface_depth_format(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return rsx::surface_depth_format::z16;
|
||||
case CELL_GCM_SURFACE_Z24S8: return rsx::surface_depth_format::z24s8;
|
||||
}
|
||||
throw EXCEPTION("Unknow surface depth format %x", in);
|
||||
}
|
||||
|
||||
std::string rsx::get_method_name(const u32 id)
|
||||
{
|
||||
auto found = methods.find(id);
|
||||
@@ -730,6 +880,40 @@ std::string rsx::get_method_name(const u32 id)
|
||||
return fmt::format("unknown/illegal method [0x%08x]", id);
|
||||
}
|
||||
|
||||
rsx::surface_antialiasing rsx::to_surface_antialiasing(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_SURFACE_CENTER_1: return rsx::surface_antialiasing::center_1_sample;
|
||||
case CELL_GCM_SURFACE_DIAGONAL_CENTERED_2: return rsx::surface_antialiasing::diagonal_centered_2_samples;
|
||||
case CELL_GCM_SURFACE_SQUARE_CENTERED_4: return rsx::surface_antialiasing::square_centered_4_samples;
|
||||
case CELL_GCM_SURFACE_SQUARE_ROTATED_4: return rsx::surface_antialiasing::square_rotated_4_samples;
|
||||
}
|
||||
throw EXCEPTION("unknow surface antialiasing format %x", in);
|
||||
}
|
||||
|
||||
rsx::surface_color_format rsx::to_surface_color_format(u8 in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5: return rsx::surface_color_format::x1r5g5b5_z1r5g5b5;
|
||||
case CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5: return rsx::surface_color_format::x1r5g5b5_o1r5g5b5;
|
||||
case CELL_GCM_SURFACE_R5G6B5: return rsx::surface_color_format::r5g6b5;
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8: return rsx::surface_color_format::x8r8g8b8_z8r8g8b8;
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8: return rsx::surface_color_format::x8r8g8b8_o8r8g8b8;
|
||||
case CELL_GCM_SURFACE_A8R8G8B8: return rsx::surface_color_format::a8r8g8b8;
|
||||
case CELL_GCM_SURFACE_B8: return rsx::surface_color_format::b8;
|
||||
case CELL_GCM_SURFACE_G8B8: return rsx::surface_color_format::g8b8;
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16: return rsx::surface_color_format::w16z16y16x16;
|
||||
case CELL_GCM_SURFACE_F_W32Z32Y32X32: return rsx::surface_color_format::w32z32y32x32;
|
||||
case CELL_GCM_SURFACE_F_X32: return rsx::surface_color_format::x32;
|
||||
case CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8: return rsx::surface_color_format::x8b8g8r8_z8b8g8r8;
|
||||
case CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8: return rsx::surface_color_format::x8b8g8r8_o8b8g8r8;
|
||||
case CELL_GCM_SURFACE_A8B8G8R8: return rsx::surface_color_format::a8b8g8r8;
|
||||
}
|
||||
throw EXCEPTION("unknow surface color format %x", in);
|
||||
}
|
||||
|
||||
// Various parameter pretty printing function
|
||||
namespace
|
||||
{
|
||||
@@ -813,18 +997,18 @@ namespace
|
||||
|
||||
std::string get_primitive_mode(u8 draw_mode)
|
||||
{
|
||||
switch (draw_mode)
|
||||
switch (rsx::to_primitive_type(draw_mode))
|
||||
{
|
||||
case CELL_GCM_PRIMITIVE_POINTS: return "Points";
|
||||
case CELL_GCM_PRIMITIVE_LINES: return "Lines";
|
||||
case CELL_GCM_PRIMITIVE_LINE_LOOP: return "Line_loop";
|
||||
case CELL_GCM_PRIMITIVE_LINE_STRIP: return "Line_strip";
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLES: return "Triangles";
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP: return "Triangle_strip";
|
||||
case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: return "Triangle_fan";
|
||||
case CELL_GCM_PRIMITIVE_QUADS: return "Quads";
|
||||
case CELL_GCM_PRIMITIVE_QUAD_STRIP: return "Quad_strip";
|
||||
case CELL_GCM_PRIMITIVE_POLYGON: return "Polygon";
|
||||
case rsx::primitive_type::points: return "Points";
|
||||
case rsx::primitive_type::lines: return "Lines";
|
||||
case rsx::primitive_type::line_loop: return "Line_loop";
|
||||
case rsx::primitive_type::line_strip: return "Line_strip";
|
||||
case rsx::primitive_type::triangles: return "Triangles";
|
||||
case rsx::primitive_type::triangle_strip: return "Triangle_strip";
|
||||
case rsx::primitive_type::triangle_fan: return "Triangle_fan";
|
||||
case rsx::primitive_type::quads: return "Quads";
|
||||
case rsx::primitive_type::quad_strip: return "Quad_strip";
|
||||
case rsx::primitive_type::polygon: return "Polygon";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
@@ -849,46 +1033,58 @@ namespace
|
||||
|
||||
std::string depth_stencil_surface_format(u32 format)
|
||||
{
|
||||
switch (format)
|
||||
switch (rsx::to_surface_depth_format(format))
|
||||
{
|
||||
case CELL_GCM_SURFACE_Z16: return "CELL_GCM_SURFACE_Z16";
|
||||
case CELL_GCM_SURFACE_Z24S8: return "CELL_GCM_SURFACE_Z24S8";
|
||||
case rsx::surface_depth_format::z16: return "CELL_GCM_SURFACE_Z16";
|
||||
case rsx::surface_depth_format::z24s8: return "CELL_GCM_SURFACE_Z24S8";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
|
||||
std::string color_surface_format(u32 format)
|
||||
std::string surface_antialiasing(u8 format)
|
||||
{
|
||||
switch (format)
|
||||
switch (rsx::to_surface_antialiasing(format))
|
||||
{
|
||||
case CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5: return "CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5";
|
||||
case CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5: return "CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5";
|
||||
case CELL_GCM_SURFACE_R5G6B5: return "CELL_GCM_SURFACE_R5G6B5";
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8: return "CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8";
|
||||
case CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8: return "CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8";
|
||||
case CELL_GCM_SURFACE_A8R8G8B8: return "CELL_GCM_SURFACE_A8R8G8B8";
|
||||
case CELL_GCM_SURFACE_B8: return "CELL_GCM_SURFACE_B8";
|
||||
case CELL_GCM_SURFACE_G8B8: return "CELL_GCM_SURFACE_G8B8";
|
||||
case CELL_GCM_SURFACE_F_W16Z16Y16X16: return "CELL_GCM_SURFACE_F_W16Z16Y16X16";
|
||||
case CELL_GCM_SURFACE_F_W32Z32Y32X32: return "CELL_GCM_SURFACE_F_W32Z32Y32X32";
|
||||
case CELL_GCM_SURFACE_F_X32: return "CELL_GCM_SURFACE_F_X32";
|
||||
case CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8: return "CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8";
|
||||
case CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8: return "CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8";
|
||||
case CELL_GCM_SURFACE_A8B8G8R8: return "CELL_GCM_SURFACE_A8B8G8R8";
|
||||
case rsx::surface_antialiasing::center_1_sample: return "1 sample centered";
|
||||
case rsx::surface_antialiasing::diagonal_centered_2_samples: return "2 samples diagonal centered";
|
||||
case rsx::surface_antialiasing::square_centered_4_samples: return "4 samples square centered";
|
||||
case rsx::surface_antialiasing::square_rotated_4_samples: return "4 samples diagonal rotated";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
|
||||
std::string surface_color_format(u32 format)
|
||||
{
|
||||
switch (rsx::to_surface_color_format(format))
|
||||
{
|
||||
case rsx::surface_color_format::x1r5g5b5_z1r5g5b5: return "CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5";
|
||||
case rsx::surface_color_format::x1r5g5b5_o1r5g5b5: return "CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5";
|
||||
case rsx::surface_color_format::r5g6b5 : return "CELL_GCM_SURFACE_R5G6B5";
|
||||
case rsx::surface_color_format::x8r8g8b8_z8r8g8b8: return "CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8";
|
||||
case rsx::surface_color_format::x8r8g8b8_o8r8g8b8: return "CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8";
|
||||
case rsx::surface_color_format::a8r8g8b8: return "CELL_GCM_SURFACE_A8R8G8B8";
|
||||
case rsx::surface_color_format::b8: return "CELL_GCM_SURFACE_B8";
|
||||
case rsx::surface_color_format::g8b8: return "CELL_GCM_SURFACE_G8B8";
|
||||
case rsx::surface_color_format::w16z16y16x16: return "CELL_GCM_SURFACE_F_W16Z16Y16X16";
|
||||
case rsx::surface_color_format::w32z32y32x32: return "CELL_GCM_SURFACE_F_W32Z32Y32X32";
|
||||
case rsx::surface_color_format::x32: return "CELL_GCM_SURFACE_F_X32";
|
||||
case rsx::surface_color_format::x8b8g8r8_z8b8g8r8: return "CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8";
|
||||
case rsx::surface_color_format::x8b8g8r8_o8b8g8r8: return "CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8";
|
||||
case rsx::surface_color_format::a8b8g8r8: return "CELL_GCM_SURFACE_A8B8G8R8";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
|
||||
std::string surface_target(u32 target)
|
||||
{
|
||||
switch (target)
|
||||
switch (rsx::to_surface_target(target))
|
||||
{
|
||||
case CELL_GCM_SURFACE_TARGET_NONE: return "none";
|
||||
case CELL_GCM_SURFACE_TARGET_0: return "surface A";
|
||||
case CELL_GCM_SURFACE_TARGET_1: return "surface B";
|
||||
case CELL_GCM_SURFACE_TARGET_MRT1: return "surfaces A and B";
|
||||
case CELL_GCM_SURFACE_TARGET_MRT2: return "surfaces A, B and C";
|
||||
case CELL_GCM_SURFACE_TARGET_MRT3: return "surfaces A,B, C and D";
|
||||
case rsx::surface_target::none: return "none";
|
||||
case rsx::surface_target::surface_a: return "surface A";
|
||||
case rsx::surface_target::surface_b: return "surface B";
|
||||
case rsx::surface_target::surfaces_a_b: return "surfaces A and B";
|
||||
case rsx::surface_target::surfaces_a_b_c: return "surfaces A, B and C";
|
||||
case rsx::surface_target::surfaces_a_b_c_d: return "surfaces A,B, C and D";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
@@ -926,17 +1122,16 @@ namespace
|
||||
|
||||
std::string get_vertex_attribute_format(u8 type)
|
||||
{
|
||||
switch (type)
|
||||
switch (rsx::to_vertex_base_type(type))
|
||||
{
|
||||
case CELL_GCM_VERTEX_S1: return "Short";
|
||||
case CELL_GCM_VERTEX_F: return "Float";
|
||||
case CELL_GCM_VERTEX_SF: return "Half float";
|
||||
case CELL_GCM_VERTEX_UB: return "Unsigned byte";
|
||||
case CELL_GCM_VERTEX_S32K: return "Signed int";
|
||||
case CELL_GCM_VERTEX_CMP: return "CMP";
|
||||
case CELL_GCM_VERTEX_UB256: return "UB256";
|
||||
case rsx::vertex_base_type::s1: return "Short";
|
||||
case rsx::vertex_base_type::f: return "Float";
|
||||
case rsx::vertex_base_type::sf: return "Half float";
|
||||
case rsx::vertex_base_type::ub: return "Unsigned byte";
|
||||
case rsx::vertex_base_type::s32k: return "Signed int";
|
||||
case rsx::vertex_base_type::cmp: return "CMP";
|
||||
case rsx::vertex_base_type::ub256: return "UB256";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
|
||||
std::string unpack_vertex_format(u32 arg)
|
||||
@@ -953,10 +1148,10 @@ namespace
|
||||
|
||||
std::string index_type(u16 arg)
|
||||
{
|
||||
switch (arg)
|
||||
switch (rsx::to_index_array_type(arg))
|
||||
{
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: return "unsigned short";
|
||||
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: return "unsigned int";
|
||||
case rsx::index_array_type::u16: return "unsigned short";
|
||||
case rsx::index_array_type::u32: return "unsigned int";
|
||||
}
|
||||
return "Error";
|
||||
}
|
||||
@@ -1227,6 +1422,31 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string origin_mode(u32 origin)
|
||||
{
|
||||
switch (rsx::to_window_origin(origin))
|
||||
{
|
||||
case rsx::window_origin::bottom: return "bottom";
|
||||
case rsx::window_origin::top: return "top";
|
||||
}
|
||||
throw EXCEPTION("Wrong origin mode");
|
||||
}
|
||||
|
||||
std::string pixel_center_mode(u32 in)
|
||||
{
|
||||
switch (rsx::to_window_pixel_center(in))
|
||||
{
|
||||
case rsx::window_pixel_center::half: return "half";
|
||||
case rsx::window_pixel_center::integer: return "integer";
|
||||
}
|
||||
throw EXCEPTION("Wrong origin mode");
|
||||
}
|
||||
|
||||
std::string shader_window(u32 arg)
|
||||
{
|
||||
return "Viewport: height = " + std::to_string(arg & 0xFFF) + " origin = " + origin_mode((arg >> 12) & 0xF) + " pixel center = " + pixel_center_mode((arg >> 16) & 0xF);
|
||||
}
|
||||
|
||||
#define OPCODE_RANGE_1(opcode, increment, index, printing_function) \
|
||||
{ (opcode) + (index) * (increment), [](u32 arg) -> std::string { return (printing_function)((index), arg); } },
|
||||
|
||||
@@ -1292,7 +1512,7 @@ namespace
|
||||
{ NV4097_SET_SURFACE_PITCH_Z, [](u32 arg) -> std::string { return "Surface Zeta: Pitch = " + std::to_string(arg); } },
|
||||
{ NV4097_SET_SURFACE_ZETA_OFFSET, [](u32 arg) -> std::string { return "Surface Zeta: Offset = " + ptr_to_string(arg); } },
|
||||
{ NV4097_SET_CONTEXT_DMA_ZETA, [](u32 arg) -> std::string { return "Surface Zeta: DMA mode = " + dma_mode(arg);} },
|
||||
{ NV4097_SET_SURFACE_FORMAT, [](u32 arg) -> std::string { return "Surface: Color format = " + color_surface_format(arg & 0x1F) + " DepthStencil format = " + depth_stencil_surface_format((arg >> 5) & 0x7) + " Anti aliasing =" + std::to_string((arg >> 12) & 0x7); } },
|
||||
{ NV4097_SET_SURFACE_FORMAT, [](u32 arg) -> std::string { return "Surface: Color format = " + surface_color_format(arg & 0x1F) + " DepthStencil format = " + depth_stencil_surface_format((arg >> 5) & 0x7) + " Anti aliasing =" + surface_antialiasing((arg >> 12) & 0x7); } },
|
||||
{ NV4097_SET_SURFACE_CLIP_HORIZONTAL, [](u32 arg) -> std::string { return "Surface: clip x = " + std::to_string(arg & 0xFFFF) + " width = " + std::to_string(arg >> 16); } },
|
||||
{ NV4097_SET_SURFACE_CLIP_VERTICAL, [](u32 arg) -> std::string { return "Surface: clip y = " + std::to_string(arg & 0xFFFF) + " height = " + std::to_string(arg >> 16); } },
|
||||
{ NV4097_SET_SURFACE_COLOR_TARGET, [](u32 arg) -> std::string { return "Surface: Targets " + surface_target(arg); } },
|
||||
@@ -1325,6 +1545,7 @@ namespace
|
||||
{ NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK, vertex_output_mask },
|
||||
{ NV4097_SET_SHADER_CONTROL, shader_control },
|
||||
{ NV4097_SET_ANTI_ALIASING_CONTROL, anti_aliasing_control },
|
||||
{ NV4097_SET_SHADER_WINDOW, shader_window },
|
||||
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT, [](u32 arg) -> std::string { return "Vertex array 0: " + unpack_vertex_format(arg); } },
|
||||
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 1, [](u32 arg) -> std::string { return "Vertex array 1: " + unpack_vertex_format(arg); } },
|
||||
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 2, [](u32 arg) -> std::string { return "Vertex array 2: " + unpack_vertex_format(arg); } },
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user