Compare commits

..

6 Commits

Author SHA1 Message Date
Zangetsu38 a1a337358a Debug DX12 2016-01-17 01:27:59 +01:00
Zangetsu38 9eadd8b136 d3d12: Update minidx12 SDK on build 10.586. 2016-01-16 19:37:48 +01:00
Zangetsu38 35fb767ae3 Update LLVM with release_37 2016-01-16 19:37:48 +01:00
Zangetsu38 80eb88d0af Fix Xaudio2 for Windows 8 and Windows 10. 2016-01-16 19:37:48 +01:00
Zangetsu38 3a85c68232 Some Change in Gui. 2016-01-16 19:37:48 +01:00
Vincent Lejeune 489cfd6f7e d3d12/gl: Use r1 as depth output.
The "Output_from_h0" flag seems to concern color output.
There might be another flag for depth from half float value.
2016-01-16 19:37:48 +01:00
33 changed files with 588 additions and 1129 deletions
+2
View File
@@ -686,8 +686,10 @@ u64 fs::file::read(void* buffer, u64 count) const
switch (DWORD error = GetLastError())
{
case ERROR_INVALID_HANDLE: errno = EBADF; break;
default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error);
}
return -1;
}
return nread;
+1 -1
View File
@@ -63,7 +63,7 @@
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<TreatWarningAsError>false</TreatWarningAsError>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
@@ -340,7 +340,7 @@ 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.xxxx)"); return true;
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); 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;
@@ -376,7 +376,7 @@ 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.xxxx)"); return true;
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); 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;
+8 -12
View File
@@ -3,14 +3,14 @@
using namespace program_hash_util;
size_t vertex_program_hash::operator()(const RSXVertexProgram &program) const
size_t vertex_program_hash::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.data();
const qword *instbuffer = (const qword*)program.data();
size_t instIndex = 0;
bool end = false;
for (unsigned i = 0; i < program.data.size() / 4; i++)
for (unsigned i = 0; i < program.size() / 4; i++)
{
const qword inst = instbuffer[instIndex];
hash ^= inst.dword[0];
@@ -22,17 +22,13 @@ size_t vertex_program_hash::operator()(const RSXVertexProgram &program) const
return hash;
}
bool vertex_program_compare::operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const
bool vertex_program_compare::operator()(const std::vector<u32> &binary1, const std::vector<u32> &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();
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.data.size() / 4; i++)
for (unsigned i = 0; i < binary1.size() / 4; i++)
{
const qword& inst1 = instBuffer1[instIndex];
const qword& inst2 = instBuffer2[instIndex];
+7 -7
View File
@@ -23,12 +23,12 @@ namespace program_hash_util
struct vertex_program_hash
{
size_t operator()(const RSXVertexProgram &program) const;
size_t operator()(const std::vector<u32> &program) const;
};
struct vertex_program_compare
{
bool operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const;
bool operator()(const std::vector<u32> &binary1, const std::vector<u32> &binary2) const;
};
struct fragment_program_utils
@@ -75,7 +75,7 @@ class program_state_cache
using vertex_program_type = typename backend_traits::vertex_program_type;
using fragment_program_type = typename backend_traits::fragment_program_type;
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_vertex_program = std::unordered_map<std::vector<u32>, vertex_program_type, program_hash_util::vertex_program_hash, program_hash_util::vertex_program_compare> ;
using binary_to_fragment_program = std::unordered_map<void *, fragment_program_type, program_hash_util::fragment_program_hash, program_hash_util::fragment_program_compare>;
@@ -115,13 +115,13 @@ private:
/// bool here to inform that the program was preexisting.
std::tuple<const vertex_program_type&, bool> search_vertex_program(const RSXVertexProgram& rsx_vp)
{
const auto& I = m_vertex_shader_cache.find(rsx_vp);
const auto& I = m_vertex_shader_cache.find(rsx_vp.data);
if (I != m_vertex_shader_cache.end())
{
return std::forward_as_tuple(I->second, true);
}
LOG_NOTICE(RSX, "VP not found in buffer!");
vertex_program_type& new_shader = m_vertex_shader_cache[rsx_vp];
vertex_program_type& new_shader = m_vertex_shader_cache[rsx_vp.data];
backend_traits::recompile_vertex_program(rsx_vp, new_shader, m_next_id++);
return std::forward_as_tuple(new_shader, false);
@@ -151,8 +151,8 @@ public:
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())
auto I = m_vertex_shader_cache.find(rsx_vp.data);
if (I == m_vertex_shader_cache.end())
return I->second;
throw new EXCEPTION("Trying to get unknow transform program");
}
-66
View File
@@ -1,66 +0,0 @@
#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");
}
}
}
-348
View File
@@ -1,348 +0,0 @@
#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 surface_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, surface_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, surface_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 surface_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, surface_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, surface_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 surface_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, surface_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(surface_color_format, gsl::narrow<u32>(width));
size_t dst_pitch = utility::get_packed_pitch(surface_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 (surface_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 surface_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), surface_depth_format, width, height, std::forward<Args&&>(args)...);
if (surface_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 (surface_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 (surface_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 (surface_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;
}
};
}
+58 -68
View File
@@ -9,18 +9,15 @@
#include "../rsx_methods.h"
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)
std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges)
{
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));
std::vector<D3D12_VERTEX_BUFFER_VIEW> vertex_buffer_views;
m_IASet.clear();
size_t input_slot = 0;
size_t vertex_count = 0;
size_t offset_in_vertex_buffers_buffer = 0;
for (const auto &pair : vertex_ranges)
vertex_count += pair.second;
@@ -37,9 +34,9 @@ std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> D3D12GSRender::upload_vertex_attrib
// Active vertex array
const rsx::data_array_format_info &info = vertex_arrays_info[index];
size_t element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
size_t buffer_size = element_size * vertex_count;
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
size_t buffer_size = element_size * vertex_count;
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
@@ -50,51 +47,25 @@ std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> D3D12GSRender::upload_vertex_attrib
}
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size);
UINT component_mapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
switch (info.size)
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view =
{
case 1:
component_mapping = 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,
);
break;
case 2:
component_mapping = 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,
);
break;
case 3:
component_mapping = 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,
);
break;
}
D3D12_SHADER_RESOURCE_VIEW_DESC vertex_buffer_view = {
get_vertex_attribute_format(info.type, info.size),
D3D12_SRV_DIMENSION_BUFFER,
component_mapping
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
(UINT)buffer_size,
(UINT)element_size
};
vertex_buffer_view.Buffer.FirstElement = offset_in_vertex_buffers_buffer / element_size;
vertex_buffer_view.Buffer.NumElements = buffer_size / element_size;
vertex_buffer_views.push_back(vertex_buffer_view);
offset_in_vertex_buffers_buffer = (offset_in_vertex_buffers_buffer + buffer_size + 191) / 192; // 192 is multiple of 2, 4, 6, 8, 12, 16, 24, 32, 48, 64
offset_in_vertex_buffers_buffer *= 192;
m_timers.m_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)
{
@@ -103,31 +74,34 @@ std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> D3D12GSRender::upload_vertex_attrib
const std::vector<u8> &data = register_vertex_data[index];
size_t element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
size_t buffer_size = data.size();
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
size_t buffer_size = data.size();
size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
memcpy(mapped_buffer, data.data(), data.size());
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size);
D3D12_SHADER_RESOURCE_VIEW_DESC vertex_buffer_view = {
get_vertex_attribute_format(info.type, info.size),
D3D12_SRV_DIMENSION_BUFFER,
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view = {
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
(UINT)buffer_size,
(UINT)element_size
};
vertex_buffer_view.Buffer.FirstElement = offset_in_vertex_buffers_buffer / element_size;
vertex_buffer_view.Buffer.NumElements = buffer_size / element_size;
vertex_buffer_views.push_back(vertex_buffer_view);
offset_in_vertex_buffers_buffer = (offset_in_vertex_buffers_buffer + buffer_size + 191) / 192; // 192 is multiple of 2, 4, 6, 8, 12, 16, 24, 32, 48, 64
offset_in_vertex_buffers_buffer *= 192;
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);
}
}
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;
}
@@ -216,7 +190,7 @@ void D3D12GSRender::upload_and_bind_fragment_shader_constants(size_t descriptor_
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)
{
@@ -225,6 +199,16 @@ std::tuple<D3D12_VERTEX_BUFFER_VIEW, size_t> D3D12GSRender::upload_inlined_verte
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_on_host(info.type, info.size);
}
@@ -274,11 +258,11 @@ 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, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
std::tuple<bool, size_t> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
{
if (draw_command == Draw_command::draw_command_inlined_array)
{
/* size_t vertex_count;
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);
@@ -290,25 +274,28 @@ std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>> D3D12GSRe
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);
}
if (draw_command == Draw_command::draw_command_array)
{
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertex_buffer_views = upload_vertex_attributes(first_count_commands);
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 : first_count_commands)
vertex_count += pair.second;
return std::make_tuple(false, vertex_count, upload_vertex_attributes(first_count_commands, command_list));
return std::make_tuple(false, vertex_count);
}
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(first_count_commands);
command_list->IASetIndexBuffer(&index_buffer_view);
return std::make_tuple(true, index_count, upload_vertex_attributes(first_count_commands, command_list));
return std::make_tuple(true, index_count);
}
assert(draw_command == Draw_command::draw_command_indexed);
@@ -350,7 +337,10 @@ std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>> D3D12GSRe
m_timers.m_buffer_upload_size += buffer_size;
command_list->IASetIndexBuffer(&index_buffer_view);
return std::make_tuple(true, index_count, upload_vertex_attributes({ std::make_pair(0, max_index + 1) }, command_list));
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertex_buffer_views = upload_vertex_attributes({ std::make_pair(min_index, max_index + 1) });
command_list->IASetVertexBuffers(0, (UINT)vertex_buffer_views.size(), vertex_buffer_views.data());
return std::make_tuple(true, index_count);
}
#endif
@@ -123,7 +123,7 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS)
for (ParamItem PI : PT.items)
{
size_t textureIndex = atoi(PI.name.data() + 3);
OS << "Texture2D " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
OS << "Texture2D " << PI.name << " : register(t" << textureIndex << ");" << std::endl;
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
}
}
@@ -132,7 +132,7 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS)
for (ParamItem PI : PT.items)
{
size_t textureIndex = atoi(PI.name.data() + 3);
OS << "TextureCube " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
OS << "TextureCube " << PI.name << " : register(t" << textureIndex << ");" << std::endl;
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
}
}
+34 -65
View File
@@ -143,43 +143,33 @@ D3D12GSRender::D3D12GSRender()
m_device->CreateRenderTargetView(m_backbuffer[1].Get(), &renter_target_view_desc, m_backbuffer_descriptor_heap[1]->GetCPUDescriptorHandleForHeapStart());
// Common root signatures
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...
for (unsigned texture_count = 0; texture_count < 17; texture_count++)
{
for (unsigned texture_count = 0; texture_count < 17; texture_count++)
CD3DX12_DESCRIPTOR_RANGE descriptorRange[] =
{
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];
size_t 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]);
// 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]);
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));
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));
m_device->CreateRootSignature(0,
rootSignatureBlob->GetBufferPointer(),
rootSignatureBlob->GetBufferSize(),
IID_PPV_ARGS(m_root_signatures[texture_count][vertex_buffer_count].GetAddressOf()));
}
m_device->CreateRootSignature(0,
rootSignatureBlob->GetBufferPointer(),
rootSignatureBlob->GetBufferSize(),
IID_PPV_ARGS(m_root_signatures[texture_count].GetAddressOf()));
}
m_per_frame_storage[0].init(m_device.Get());
@@ -204,17 +194,6 @@ D3D12GSRender::D3D12GSRender()
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);
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();
}
@@ -271,14 +250,9 @@ void D3D12GSRender::end()
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::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::tie(indexed_draw, vertex_count) = upload_and_set_vertex_index_data(get_current_resource_storage().command_list.Get());
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();
@@ -288,23 +262,16 @@ void D3D12GSRender::end()
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();
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->SetGraphicsRootSignature(m_root_signatures[std::get<2>(m_current_pso)].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 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++, g_descriptor_stride_srv_cbv_uav));
}
size_t currentDescriptorIndex = get_current_resource_storage().descriptors_heap_index;
// Constants
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);
upload_and_bind_scale_offset_matrix(currentDescriptorIndex);
upload_and_bind_vertex_shader_constants(currentDescriptorIndex + 1);
upload_and_bind_fragment_shader_constants(currentDescriptorIndex + 2);
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();
@@ -314,7 +281,8 @@ void D3D12GSRender::end()
std::chrono::time_point<std::chrono::system_clock> texture_duration_start = std::chrono::system_clock::now();
if (std::get<2>(m_current_pso) > 0)
{
upload_and_bind_textures(get_current_resource_storage().command_list.Get(), currentDescriptorIndex + 3 + vertex_buffer_count, std::get<2>(m_current_pso) > 0);
upload_and_bind_textures(get_current_resource_storage().command_list.Get(), currentDescriptorIndex + 3, std::get<2>(m_current_pso) > 0);
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
CD3DX12_GPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetGPUDescriptorHandleForHeapStart())
@@ -326,15 +294,16 @@ void D3D12GSRender::end()
);
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;
get_current_resource_storage().descriptors_heap_index += std::get<2>(m_current_pso) + 3;
}
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)
);
get_current_resource_storage().descriptors_heap_index += 3 + vertex_buffer_count;
get_current_resource_storage().descriptors_heap_index += 3;
}
std::chrono::time_point<std::chrono::system_clock> texture_duration_end = std::chrono::system_clock::now();
+17 -9
View File
@@ -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][17]; // indexed by [texture count][vertex count]
ComPtr<ID3D12RootSignature> m_root_signatures[17];
// TODO: Use a tree structure to parse more efficiently
data_cache m_texture_cache;
@@ -67,7 +67,7 @@ private:
RSXVertexProgram vertex_program;
RSXFragmentProgram fragment_program;
PipelineStateObjectCache m_pso_cache;
std::tuple<ComPtr<ID3D12PipelineState>, size_t, size_t> m_current_pso;
std::tuple<ComPtr<ID3D12PipelineState>, std::vector<size_t>, size_t> m_current_pso;
struct
{
@@ -115,9 +115,10 @@ private:
// Textures, constants, index and vertex buffers storage
data_heap m_buffer_data;
data_heap m_readback_resources;
ComPtr<ID3D12Resource> m_vertex_buffer_data;
rsx::render_targets m_rtts;
render_targets m_rtts;
std::vector<D3D12_INPUT_ELEMENT_DESC> m_IASet;
INT g_descriptor_stride_srv_cbv_uav;
INT g_descriptor_stride_dsv;
@@ -126,6 +127,13 @@ private:
// Used to fill unused texture slot
ID3D12Resource *m_dummy_texture;
// Store previous fbo addresses to detect RTT config changes.
std::array<u32, 4> m_previous_color_address = {};
u32 m_previous_address_z = 0;
u32 m_previous_target = 0;
u32 m_previous_clip_horizontal = 0;
u32 m_previous_clip_vertical = 0;
public:
D3D12GSRender();
virtual ~D3D12GSRender();
@@ -142,15 +150,14 @@ 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, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> > upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list);
std::tuple<bool, size_t> upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list);
/**
* 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_SHADER_RESOURCE_VIEW_DESC> upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges,
gsl::not_null<ID3D12GraphicsCommandList*> command_list);
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();
@@ -193,7 +200,8 @@ protected:
virtual void end() override;
virtual void flip(int 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 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::pair<std::string, std::string> get_programs() const override;
};
+3 -3
View File
@@ -70,7 +70,7 @@ public:
template<int Alignement>
size_t alloc(size_t size)
{
if (!can_alloc<Alignement>(size)) LOG_ERROR (RSX, "Working buffer not big enough");
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)
@@ -138,12 +138,12 @@ struct texture_entry
texture_entry() : m_format(0), m_width(0), m_height(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), m_mipmap(m)
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)
{}
bool operator==(const texture_entry &other)
{
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height && m_mipmap == other.m_mipmap);
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height);
}
};
+1 -36
View File
@@ -52,42 +52,6 @@ void D3D12GSRender::load_program()
if (d3.end)
break;
}
vertex_program.output_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK];
u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK];
u32 modulo_mask = rsx::method_registers[NV4097_SET_FREQUENCY_DIVIDER_OPERATION];
vertex_program.rsx_vertex_inputs.clear();
for (u8 index = 0; index < rsx::limits::vertex_count; ++index)
{
bool enabled = !!(input_mask & (1 << index));
if (!enabled)
continue;
if (vertex_arrays_info[index].size > 0)
{
vertex_program.rsx_vertex_inputs.push_back(
{
index,
vertex_arrays_info[index].size,
vertex_arrays_info[index].frequency,
!!((modulo_mask >> index) & 0x1),
true
}
);
}
else if (register_vertex_info[index].size > 0)
{
vertex_program.rsx_vertex_inputs.push_back(
{
index,
register_vertex_info[index].size,
register_vertex_info[index].frequency,
!!((modulo_mask >> index) & 0x1),
false
}
);
}
}
u32 shader_program = rsx::method_registers[NV4097_SET_SHADER_PROGRAM];
fragment_program.offset = shader_program & ~0x3;
@@ -287,6 +251,7 @@ void 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])
{
Index_array_type index_type = to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4);
+48 -8
View File
@@ -10,6 +10,7 @@ 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;
@@ -18,6 +19,23 @@ 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)))
@@ -75,7 +93,7 @@ public:
ComPtr<ID3DBlob> bytecode;
// For debugging
std::string content;
size_t vertex_shader_input_count;
std::vector<size_t> vertex_shader_inputs;
std::vector<size_t> FragmentConstantOffsetCache;
size_t m_textureCount;
@@ -100,11 +118,29 @@ 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
{
using vertex_program_type = Shader;
using fragment_program_type = Shader;
using pipeline_storage_type = std::tuple<ComPtr<ID3D12PipelineState>, size_t, size_t>;
using pipeline_storage_type = std::tuple<ComPtr<ID3D12PipelineState>, std::vector<size_t>, size_t>;
using pipeline_properties = D3D12PipelineProperties;
static
@@ -140,15 +176,15 @@ struct D3D12Traits
D3D12VertexProgramDecompiler VS(RSXVP);
std::string shaderCode = VS.Decompile();
vertexProgramData.Compile(shaderCode, Shader::SHADER_TYPE::SHADER_TYPE_VERTEX);
vertexProgramData.vertex_shader_input_count = RSXVP.rsx_vertex_inputs.size();
vertexProgramData.vertex_shader_inputs = VS.input_slots;
fs::file(fs::get_config_dir() + "/hlsl/VertexProgram" + std::to_string(ID) + ".hlsl", fom::rewrite).write(shaderCode);
vertexProgramData.id = (u32)ID;
}
static
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)
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> root_signatures)
{
std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> result = {};
D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {};
@@ -163,7 +199,7 @@ struct D3D12Traits
graphicPipelineStateDesc.PS.BytecodeLength = fragmentProgramData.bytecode->GetBufferSize();
graphicPipelineStateDesc.PS.pShaderBytecode = fragmentProgramData.bytecode->GetBufferPointer();
graphicPipelineStateDesc.pRootSignature = root_signatures[fragmentProgramData.m_textureCount][vertexProgramData.vertex_shader_input_count].Get();
graphicPipelineStateDesc.pRootSignature = root_signatures[fragmentProgramData.m_textureCount].Get();
graphicPipelineStateDesc.BlendState = pipelineProperties.Blend;
graphicPipelineStateDesc.DepthStencilState = pipelineProperties.DepthStencil;
@@ -175,6 +211,10 @@ 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;
@@ -186,7 +226,7 @@ struct D3D12Traits
std::wstring name = L"PSO_" + std::to_wstring(vertexProgramData.id) + L"_" + std::to_wstring(fragmentProgramData.id);
pso->SetName(name.c_str());
return std::make_tuple(pso, vertexProgramData.vertex_shader_input_count, fragmentProgramData.m_textureCount);
return std::make_tuple(pso, vertexProgramData.vertex_shader_inputs, fragmentProgramData.m_textureCount);
}
};
+124 -19
View File
@@ -171,23 +171,58 @@ void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlis
{
// check if something has changed
u32 surface_format = rsx::method_registers[NV4097_SET_SURFACE_FORMAT];
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
std::array<u32, 4> 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);
u32 clip_h_reg = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL];
u32 clip_v_reg = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL];
u32 target_reg = rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET];
// Exit early if there is no rtt changes
if (!m_rtts_dirty)
if (m_previous_color_address == address_color &&
m_previous_address_z == address_z &&
m_surface.format == surface_format &&
m_previous_clip_horizontal == clip_h_reg &&
m_previous_clip_vertical == clip_v_reg &&
m_previous_target == target_reg)
return;
m_rtts_dirty = false;
m_previous_color_address = address_color;
m_previous_address_z = address_z;
m_previous_target = target_reg;
m_previous_clip_horizontal = clip_h_reg;
m_previous_clip_vertical = clip_v_reg;
if (m_surface.format != surface_format)
m_surface.unpack(surface_format);
std::array<float, 4> clear_color = get_clear_color(rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE]);
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],
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);
m_rtts.prepare_render_target(copycmdlist, surface_format, clip_h_reg, clip_v_reg, to_surface_target(target_reg), address_color, address_z, m_device.Get(), clear_color, 1.f, 0);
// write descriptors
DXGI_FORMAT dxgi_format = get_color_surface_format(m_surface.color_format);
@@ -226,7 +261,7 @@ void D3D12GSRender::set_rtt_and_ds(ID3D12GraphicsCommandList *command_list)
command_list->OMSetRenderTargets((UINT)num_rtt, &m_rtts.current_rtts_handle, true, ds_handle);
}
void rsx::render_targets::init(ID3D12Device *device)
void render_targets::init(ID3D12Device *device)
{
g_descriptor_stride_rtv = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
}
@@ -453,21 +488,91 @@ void D3D12GSRender::copy_render_target_to_dma_location()
}
std::array<std::vector<gsl::byte>, 4> D3D12GSRender::copy_render_targets_to_memory()
void D3D12GSRender::copy_render_targets_to_memory(void *buffer, u8 rtt)
{
size_t heap_offset = 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[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;
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());
size_t srcPitch = get_aligned_pitch(m_surface.color_format, clip_w);
size_t dstPitch = get_packed_pitch(m_surface.color_format, clip_w);
copy_readback_buffer_to_dest(buffer, m_readback_resources, heap_offset, srcPitch, dstPitch, clip_h);
}
std::array<std::vector<gsl::byte>, 2> D3D12GSRender::copy_depth_stencil_buffer_to_memory()
void D3D12GSRender::copy_depth_buffer_to_memory(void *buffer)
{
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());
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;
size_t heap_offset = m_readback_resources.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
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_COPY_SOURCE));
get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.get_heap(), { heap_offset,{ DXGI_FORMAT_R32_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0,
&CD3DX12_TEXTURE_COPY_LOCATION(std::get<1>(m_rtts.m_bound_depth_stencil), 0), nullptr);
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_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 *mapped_buffer = m_readback_resources.map<void>(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.unmap();
}
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;
size_t heap_offset = m_readback_resources.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
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_COPY_SOURCE));
get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.get_heap(), { heap_offset, { DXGI_FORMAT_R8_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0,
&CD3DX12_TEXTURE_COPY_LOCATION(std::get<1>(m_rtts.m_bound_depth_stencil), 1), nullptr);
get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_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 *mapped_buffer = m_readback_resources.map<void>(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.unmap();
}
#endif
+162 -131
View File
@@ -5,18 +5,177 @@
#include "d3dx12.h"
#include "D3D12Formats.h"
#include "D3D12MemoryHelpers.h"
#include "../Common/surface_store.h"
#include <gsl.h>
namespace rsx
{
namespace
{
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");
}
}
template<typename Traits>
struct surface_store
{
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;
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 surface_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, surface_color_format, width, height))
{
Traits::prepare_rtt_for_drawing(command_list, rtt.Get());
return rtt.Get();
}
invalidated_resources.push_back(std::move(rtt));
m_render_targets_storage.erase(address);
}
m_render_targets_storage[address] = Traits::create_new_surface(address, surface_color_format, width, height, std::forward<Args>(extra_params)...);
return m_render_targets_storage[address].Get();
}
template <typename ...Args>
gsl::not_null<surface_type> bind_address_as_depth_stencil(
command_list_type command_list,
u32 address,
Surface_depth_format surface_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, surface_depth_format, width, height))
{
Traits::prepare_ds_for_drawing(command_list, ds.Get());
return ds.Get();
}
invalidated_resources.push_back(std::move(ds));
m_depth_stencil_storage.erase(address);
}
m_depth_stencil_storage[address] = Traits::create_new_surface(address, surface_depth_format, width, height, std::forward<Args>(extra_params)...);
return m_depth_stencil_storage[address].Get();
}
public:
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;
rsx::surface_info surface = {};
surface.unpack(set_surface_format_reg);
// 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 : 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], surface.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, surface.depth_format, clip_width, clip_height, std::forward<Args>(extra_params)...));
}
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 It->second.Get();
return surface_type();
}
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 It->second.Get();
return surface_type();
}
};
}
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(
@@ -125,133 +284,6 @@ struct render_target_traits
//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>
@@ -264,4 +296,3 @@ struct render_targets : public rsx::surface_store<render_target_traits>
void init(ID3D12Device *device);
};
}
@@ -52,40 +52,20 @@ void D3D12VertexProgramDecompiler::insertHeader(std::stringstream &OS)
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 << "Texture1D<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)
{
std::vector<std::tuple<size_t, std::string>> input_data;
OS << "struct VertexInput" << std::endl;
OS << "{" << std::endl;
for (const ParamType PT : inputs)
{
for (const ParamItem &PI : PT.items)
{
input_data.push_back(std::make_tuple(PI.location, PI.name));
OS << " " << PT.type << " " << PI.name << ": TEXCOORD" << PI.location << ";" << std::endl;
input_slots.push_back(PI.location);
}
}
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)
@@ -160,39 +140,9 @@ 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.Load(0);\n";
return;
}
if (real_input.frequency > 1)
{
if (real_input.is_modulo)
{
OS << " float4 " << PI.name << " = " << PI.name << "_buffer.Load(vertex_id % " << real_input.frequency << ");\n";
return;
}
OS << " float4 " << PI.name << " = " << PI.name << "_buffer.Load(vertex_id / " << real_input.frequency << ");\n";
return;
}
OS << " float4 " << PI.name << " = " << PI.name << "_buffer.Load(vertex_id);\n";
return;
}
OS << " float4 " << PI.name << " = float4(0., 0., 0., 1.);\n";
}
}
void D3D12VertexProgramDecompiler::insertMainStart(std::stringstream & OS)
{
OS << "PixelInput main(uint vertex_id : SV_VertexID)" << std::endl;
OS << "PixelInput main(VertexInput In)" << std::endl;
OS << "{" << std::endl;
// Declare inside main function
@@ -212,9 +162,7 @@ void D3D12VertexProgramDecompiler::insertMainStart(std::stringstream & OS)
for (const ParamType PT : m_parr.params[PF_PARAM_IN])
{
for (const ParamItem &PI : PT.items)
{
add_input(OS, PI, rsx_vertex_program.rsx_vertex_inputs);
}
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
}
}
@@ -234,7 +182,7 @@ void D3D12VertexProgramDecompiler::insertMainEnd(std::stringstream & OS)
}
D3D12VertexProgramDecompiler::D3D12VertexProgramDecompiler(const RSXVertexProgram &prog) :
VertexProgramDecompiler(prog), rsx_vertex_program(prog)
VertexProgramDecompiler(prog)
{
}
#endif
@@ -18,8 +18,7 @@ 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(const RSXVertexProgram &prog);
};
-36
View File
@@ -753,42 +753,6 @@ bool GLGSRender::load_program()
if (d3.end)
break;
}
vertex_program.output_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK];
u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK];
u32 modulo_mask = rsx::method_registers[NV4097_SET_FREQUENCY_DIVIDER_OPERATION];
vertex_program.rsx_vertex_inputs.clear();
for (u8 index = 0; index < rsx::limits::vertex_count; ++index)
{
bool enabled = !!(input_mask & (1 << index));
if (!enabled)
continue;
if (vertex_arrays_info[index].size > 0)
{
vertex_program.rsx_vertex_inputs.push_back(
{
index,
vertex_arrays_info[index].size,
vertex_arrays_info[index].frequency,
!!((modulo_mask >> index) & 0x1),
true
}
);
}
else if (register_vertex_info[index].size > 0)
{
vertex_program.rsx_vertex_inputs.push_back(
{
index,
register_vertex_info[index].size,
register_vertex_info[index].frequency,
!!((modulo_mask >> index) & 0x1),
false
}
);
}
}
RSXFragmentProgram fragment_program;
u32 shader_program = rsx::method_registers[NV4097_SET_SHADER_PROGRAM];
+38 -43
View File
@@ -276,14 +276,44 @@ namespace rsx
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]);
draw_state.width = clip_w;
draw_state.height = clip_h;
draw_state.surface_color_format = surface.color_format;
draw_state.color_buffer = std::move(copy_render_targets_to_memory());
draw_state.surface_depth_format = surface.depth_format;
draw_state.depth_stencil = std::move(copy_depth_stencil_buffer_to_memory());
size_t pitch = clip_w * 4;
std::vector<size_t> color_index_to_record;
switch (to_surface_target(method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))
{
case Surface_target::surface_a:
color_index_to_record = { 0 };
break;
case Surface_target::surface_b:
color_index_to_record = { 1 };
break;
case Surface_target::surfaces_a_b:
color_index_to_record = { 0, 1 };
break;
case Surface_target::surfaces_a_b_c:
color_index_to_record = { 0, 1, 2 };
break;
case Surface_target::surfaces_a_b_c_d:
color_index_to_record = { 0, 1, 2, 3 };
break;
}
for (size_t i : color_index_to_record)
{
draw_state.color_buffer[i].width = clip_w;
draw_state.color_buffer[i].height = clip_h;
draw_state.color_buffer[i].data.resize(pitch * clip_h);
copy_render_targets_to_memory(draw_state.color_buffer[i].data.data(), i);
}
if (get_address(method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], method_registers[NV4097_SET_CONTEXT_DMA_ZETA]))
{
draw_state.depth.width = clip_w;
draw_state.depth.height = clip_h;
draw_state.depth.data.resize(clip_w * clip_h * 4);
copy_depth_buffer_to_memory(draw_state.depth.data.data());
draw_state.stencil.width = clip_w;
draw_state.stencil.height = clip_h;
draw_state.stencil.data.resize(clip_w * clip_h * 4);
copy_stencil_buffer_to_memory(draw_state.stencil.data.data());
}
draw_state.programs = get_programs();
draw_state.name = name;
frame_debug.draw_calls.push_back(draw_state);
@@ -301,10 +331,7 @@ namespace rsx
if (capture_current_frame)
{
for (const auto &first_count : first_count_commands)
vertex_draw_count += first_count.second;
capture_frame("Draw " + std::to_string(vertex_draw_count));
vertex_draw_count = 0;
}
}
@@ -507,38 +534,6 @@ namespace rsx
return get_system_time() * 1000;
}
std::array<u32, 4> thread::get_color_surface_addresses() const
{
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 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]
};
return
{
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 thread::get_zeta_surface_address() const
{
u32 m_context_dma_z = rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA];
u32 offset_zeta = rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET];
return rsx::get_address(offset_zeta, m_context_dma_z);
}
void thread::reset()
{
//setup method registers
+17 -17
View File
@@ -15,16 +15,19 @@ extern u64 get_system_time();
struct frame_capture_data
{
struct buffer
{
std::vector<u8> data;
size_t width = 0, height = 0;
};
struct draw_state
{
std::string name;
std::pair<std::string, std::string> programs;
size_t width = 0, height = 0;
Surface_color_format surface_color_format;
std::array<std::vector<gsl::byte>, 4> color_buffer;
Surface_depth_format surface_depth_format;
std::array<std::vector<gsl::byte>, 2> depth_stencil;
buffer color_buffer[4];
buffer depth;
buffer stencil;
};
std::vector<std::pair<u32, u32> > command_queue;
std::vector<draw_state> draw_calls;
@@ -287,11 +290,6 @@ namespace rsx
bool draw_inline_vertex_array;
std::vector<u32> inline_vertex_array;
bool m_rtts_dirty;
protected:
std::array<u32, 4> get_color_surface_addresses() const;
u32 get_zeta_surface_address() const;
public:
u32 draw_array_count;
u32 draw_array_first;
@@ -349,17 +347,19 @@ namespace rsx
* Copy rtt values to buffer.
* TODO: It's more efficient to combine multiple call of this function into one.
*/
virtual std::array<std::vector<gsl::byte>, 4> copy_render_targets_to_memory() {
return std::array<std::vector<gsl::byte>, 4>();
};
virtual void copy_render_targets_to_memory(void *buffer, u8 rtt) {};
/**
* Copy depth and stencil content to buffers.
* Copy depth content to buffer.
* TODO: It's more efficient to combine multiple call of this function into one.
*/
virtual std::array<std::vector<gsl::byte>, 2> copy_depth_stencil_buffer_to_memory() {
return std::array<std::vector<gsl::byte>, 2>();
};
virtual void copy_depth_buffer_to_memory(void *buffer) {};
/**
* Copy stencil content to buffer.
* TODO: It's more efficient to combine multiple call of this function into one.
*/
virtual void copy_stencil_buffer_to_memory(void *buffer) {};
virtual std::pair<std::string, std::string> get_programs() const { return std::make_pair("", ""); };
public:
-16
View File
@@ -190,23 +190,7 @@ static const std::string rsx_vp_vec_op_names[] =
"SEQ", "SFL", "SGT", "SLE", "SNE", "STR", "SSG", "NULL", "NULL", "TXL"
};
struct rsx_vertex_input
{
u8 location; // between 0 and 15
u8 size; // between 1 and 4
u16 frequency;
bool is_modulo; // either modulo frequency or divide frequency
bool is_array; // false if "reg value"
bool operator==(const rsx_vertex_input other) const
{
return location == other.location && size == other.size && frequency == other.frequency && is_modulo == other.is_modulo && is_array == other.is_array;
}
};
struct RSXVertexProgram
{
std::vector<u32> data;
std::vector<rsx_vertex_input> rsx_vertex_inputs;
u32 output_mask;
};
-28
View File
@@ -282,11 +282,6 @@ namespace rsx
break;
}
}
force_inline void set_surface_dirty_bit(thread* rsx, u32)
{
rsx->m_rtts_dirty = true;
}
}
namespace nv308a
@@ -791,16 +786,6 @@ namespace rsx
bind<NV406E_SEMAPHORE_ACQUIRE, nv406e::semaphore_acquire>();
bind<NV406E_SEMAPHORE_RELEASE, nv406e::semaphore_release>();
/*
// Store previous fbo addresses to detect RTT config changes.
std::array<u32, 4> m_previous_color_address = {};
u32 m_previous_address_z = 0;
u32 m_previous_target = 0;
u32 m_previous_clip_horizontal = 0;
u32 m_previous_clip_vertical = 0;
*/
// NV4097
bind<NV4097_TEXTURE_READ_SEMAPHORE_RELEASE, nv4097::texture_read_semaphore_release>();
bind<NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE, nv4097::back_end_write_semaphore_release>();
@@ -821,19 +806,6 @@ namespace rsx
bind_range<NV4097_SET_TRANSFORM_PROGRAM + 3, 4, 128, nv4097::set_transform_program>();
bind_cpu_only<NV4097_GET_REPORT, nv4097::get_report>();
bind_cpu_only<NV4097_CLEAR_REPORT_VALUE, nv4097::clear_report_value>();
bind<NV4097_SET_SURFACE_CLIP_HORIZONTAL, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_SURFACE_CLIP_VERTICAL, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_SURFACE_COLOR_AOFFSET, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_SURFACE_COLOR_BOFFSET, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_SURFACE_COLOR_COFFSET, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_SURFACE_COLOR_DOFFSET, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_SURFACE_ZETA_OFFSET, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_CONTEXT_DMA_COLOR_A, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_CONTEXT_DMA_COLOR_B, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_CONTEXT_DMA_COLOR_C, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_CONTEXT_DMA_COLOR_D, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_CONTEXT_DMA_ZETA, nv4097::set_surface_dirty_bit>();
bind<NV4097_SET_SURFACE_FORMAT, nv4097::set_surface_dirty_bit>();
//NV308A
bind_range<NV308A_COLOR, 1, 256, nv308a::color>();
+1 -1
View File
@@ -40,7 +40,7 @@ namespace rsx
u32 y_mask = 0xAAAAAAAA;
// We have to limit the masks to the lower of the two dimensions to allow for non-square textures
u32 limit_mask = (log2width < log2height) ? log2width : log2height;
u16 limit_mask = (log2width < log2height) ? log2width : log2height;
// double the limit mask to account for bits in both x and y
limit_mask = 1 << (limit_mask << 1);
+1 -3
View File
@@ -40,7 +40,6 @@ AudioDecoder::AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr<CellAdecCbMsg>
switch (type)
{
case CELL_ADEC_TYPE_LPCM_PAMF:
case CELL_ADEC_TYPE_AC3:
case CELL_ADEC_TYPE_ATRACX:
case CELL_ADEC_TYPE_ATRACX_2CH:
case CELL_ADEC_TYPE_ATRACX_6CH:
@@ -479,7 +478,6 @@ bool adecCheckType(s32 type)
switch (type)
{
case CELL_ADEC_TYPE_LPCM_PAMF: cellAdec.notice("adecCheckType(): LPCM pamf"); break;
case CELL_ADEC_TYPE_AC3: cellAdec.notice("adecCheckType(): AC3"); break;
case CELL_ADEC_TYPE_ATRACX: cellAdec.notice("adecCheckType(): ATRAC3plus"); break;
case CELL_ADEC_TYPE_ATRACX_2CH: cellAdec.notice("adecCheckType(): ATRAC3plus 2ch"); break;
case CELL_ADEC_TYPE_ATRACX_6CH: cellAdec.notice("adecCheckType(): ATRAC3plus 6ch"); break;
@@ -487,6 +485,7 @@ bool adecCheckType(s32 type)
case CELL_ADEC_TYPE_MP3: cellAdec.notice("adecCheckType(): MP3"); break;
case CELL_ADEC_TYPE_MPEG_L2: cellAdec.notice("adecCheckType(): Mpeg L2"); break;
case CELL_ADEC_TYPE_AC3:
case CELL_ADEC_TYPE_ATRAC3:
case CELL_ADEC_TYPE_CELP:
case CELL_ADEC_TYPE_M4AAC:
@@ -596,7 +595,6 @@ s32 cellAdecStartSeq(u32 handle, u32 param)
switch (adec->type)
{
case CELL_ADEC_TYPE_LPCM_PAMF:
case CELL_ADEC_TYPE_AC3:
case CELL_ADEC_TYPE_ATRACX:
case CELL_ADEC_TYPE_ATRACX_2CH:
case CELL_ADEC_TYPE_ATRACX_6CH:
+1 -2
View File
@@ -1039,8 +1039,7 @@ s32 cellFsChangeFileSizeByFdWithoutAllocation()
s32 cellFsSetDiscReadRetrySetting()
{
UNIMPLEMENTED_FUNC(cellFs);
return CELL_OK;
throw EXCEPTION("");
}
s32 cellFsRegisterConversionCallback()
+1 -1
View File
@@ -425,7 +425,7 @@ s32 sceNpBasicGetEvent(vm::ptr<s32> event, vm::ptr<SceNpUserInfo> from, vm::ptr<
// TODO: Check for other error and pass other events
*event = SCE_NP_BASIC_EVENT_OFFLINE;
return -1;
return CELL_OK;
}
s32 sceNpCommerceCreateCtx()
+5 -10
View File
@@ -235,8 +235,7 @@ s32 sceNpMatching2SetSignalingOptParam()
s32 sceNpMatching2RegisterContextCallback()
{
UNIMPLEMENTED_FUNC(sceNp2);
return CELL_OK;
throw EXCEPTION("");
}
s32 sceNpMatching2SendRoomChatMessage()
@@ -276,8 +275,7 @@ s32 sceNpMatching2GrantRoomOwner()
s32 sceNpMatching2CreateContext()
{
UNIMPLEMENTED_FUNC(sceNp2);
return CELL_OK;
throw EXCEPTION("");
}
s32 sceNpMatching2GetSignalingOptParamLocal()
@@ -327,14 +325,12 @@ s32 sceNpMatching2DeleteServerContext()
s32 sceNpMatching2SetDefaultRequestOptParam()
{
UNIMPLEMENTED_FUNC(sceNp2);
return CELL_OK;
throw EXCEPTION("");
}
s32 sceNpMatching2RegisterRoomEventCallback()
{
UNIMPLEMENTED_FUNC(sceNp2);
return CELL_OK;
throw EXCEPTION("");
}
s32 sceNpMatching2GetRoomPasswordLocal()
@@ -384,8 +380,7 @@ s32 sceNpMatching2SetLobbyMemberDataInternal()
s32 sceNpMatching2RegisterRoomMessageCallback()
{
UNIMPLEMENTED_FUNC(sceNp2);
return CELL_OK;
throw EXCEPTION("");
}
+1 -2
View File
@@ -193,8 +193,7 @@ s32 _sys_memchr()
s32 _sys_memmove()
{
UNIMPLEMENTED_FUNC(sys_libc);
return CELL_OK;
return CELL_OK; //throw EXCEPTION("");
}
s64 _sys_strlen(vm::cptr<char> str)
+45 -121
View File
@@ -251,8 +251,8 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
p_buffer_colorB->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
p_buffer_colorC->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
p_buffer_colorD->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
p_buffer_depth->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
p_buffer_stencil->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
//p_buffer_depth->Bind(wxEVT_BUTTON, &RSXDebugger::OnClickBuffer, this);
//p_buffer_stencil->Bind(wxEVT_BUTTON, &RSXDebugger::OnClickBuffer, this);
p_buffer_tex->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
m_list_captured_draw_calls->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickDrawCalls, this);
@@ -364,8 +364,6 @@ void RSXDebugger::OnClickBuffer(wxMouseEvent& event)
if (event.GetId() == p_buffer_colorB->GetId()) display_buffer(this, buffer_img[1]);
if (event.GetId() == p_buffer_colorC->GetId()) display_buffer(this, buffer_img[2]);
if (event.GetId() == p_buffer_colorD->GetId()) display_buffer(this, buffer_img[3]);
if (event.GetId() == p_buffer_depth->GetId()) display_buffer(this, depth_img);
if (event.GetId() == p_buffer_stencil->GetId()) display_buffer(this, stencil_img);
if (event.GetId() == p_buffer_tex->GetId())
{
u8 location = render.textures[m_cur_texture].location();
@@ -382,74 +380,18 @@ void RSXDebugger::OnClickBuffer(wxMouseEvent& event)
namespace
{
std::array<u8, 3> get_value(gsl::span<const gsl::byte> orig_buffer, Surface_color_format format, size_t idx)
{
switch (format)
{
case Surface_color_format::b8:
{
u8 value = gsl::as_span<const u8>(orig_buffer)[idx];
return{ value, value, value };
}
case Surface_color_format::x32:
{
be_t<u32> stored_val = gsl::as_span<const be_t<u32>>(orig_buffer)[idx];
u32 swapped_val = stored_val;
f32 float_val = (f32&)swapped_val;
u8 val = float_val * 255.f;
return{ val, val, val };
}
case Surface_color_format::a8b8g8r8:
case Surface_color_format::x8b8g8r8_o8b8g8r8:
case Surface_color_format::x8b8g8r8_z8b8g8r8:
{
auto ptr = gsl::as_span<const u8>(orig_buffer);
return{ ptr[1 + idx * 4], ptr[2 + idx * 4], ptr[3 + idx * 4] };
}
case Surface_color_format::a8r8g8b8:
case Surface_color_format::x8r8g8b8_o8r8g8b8:
case Surface_color_format::x8r8g8b8_z8r8g8b8:
{
auto ptr = gsl::as_span<const u8>(orig_buffer);
return{ ptr[3 + idx * 4], ptr[2 + idx * 4], ptr[1 + idx * 4] };
}
case Surface_color_format::w16z16y16x16:
{
auto ptr = gsl::as_span<const u16>(orig_buffer);
f16 h0 = f16(ptr[4 * idx]);
f16 h1 = f16(ptr[4 * idx + 1]);
f16 h2 = f16(ptr[4 * idx + 2]);
f32 f0 = float(h0);
f32 f1 = float(h1);
f32 f2 = float(h2);
u8 val0 = f0 * 255.;
u8 val1 = f1 * 255.;
u8 val2 = f2 * 255.;
return{ val0, val1, val2 };
}
case Surface_color_format::g8b8:
case Surface_color_format::r5g6b5:
case Surface_color_format::x1r5g5b5_o1r5g5b5:
case Surface_color_format::x1r5g5b5_z1r5g5b5:
case Surface_color_format::w32z32y32x32:
throw EXCEPTION("Unsupported format for display");
}
}
/**
* Return a new buffer that can be passed to wxImage ctor.
* The pointer seems to be freed by wxImage.
*/
u8* convert_to_wximage_buffer(Surface_color_format format, gsl::span<const gsl::byte> orig_buffer, size_t width, size_t height) noexcept
u8* convert_to_wximage_buffer(u8 *orig_buffer, size_t width, size_t height) noexcept
{
unsigned char* buffer = (unsigned char*)malloc(width * height * 3);
for (u32 i = 0; i < width * height; i++)
{
const auto &colors = get_value(orig_buffer, format, i);
buffer[0 + i * 3] = colors[0];
buffer[1 + i * 3] = colors[1];
buffer[2 + i * 3] = colors[2];
buffer[0 + i * 3] = orig_buffer[3 + i * 4];
buffer[1 + i * 3] = orig_buffer[2 + i * 4];
buffer[2 + i * 3] = orig_buffer[1 + i * 4];
}
return buffer;
}
@@ -459,8 +401,6 @@ void RSXDebugger::OnClickDrawCalls(wxMouseEvent& event)
{
size_t draw_id = m_list_captured_draw_calls->GetFirstSelected();
const auto& draw_call = frame_debug.draw_calls[draw_id];
wxPanel* p_buffers[] =
{
p_buffer_colorA,
@@ -469,14 +409,13 @@ void RSXDebugger::OnClickDrawCalls(wxMouseEvent& event)
p_buffer_colorD,
};
size_t width = draw_call.width;
size_t height = draw_call.height;
for (size_t i = 0; i < 4; i++)
{
if (width && height && !draw_call.color_buffer[i].empty())
size_t width = frame_debug.draw_calls[draw_id].color_buffer[i].width, height = frame_debug.draw_calls[draw_id].color_buffer[i].height;
if (width && height)
{
buffer_img[i] = wxImage(width, height, convert_to_wximage_buffer(draw_call.surface_color_format, draw_call.color_buffer[i], width, height));
unsigned char *orig_buffer = frame_debug.draw_calls[draw_id].color_buffer[i].data.data();
buffer_img[i] = wxImage(width, height, convert_to_wximage_buffer(orig_buffer, width, height));
wxClientDC dc_canvas(p_buffers[i]);
if (buffer_img[i].IsOk())
@@ -486,71 +425,56 @@ void RSXDebugger::OnClickDrawCalls(wxMouseEvent& event)
// Buffer Z
{
if (width && height && !draw_call.depth_stencil[0].empty())
size_t width = frame_debug.draw_calls[draw_id].depth.width, height = frame_debug.draw_calls[draw_id].depth.height;
if (width && height)
{
gsl::span<const gsl::byte> orig_buffer = draw_call.depth_stencil[0];
unsigned char *buffer = (unsigned char *)malloc(width * height * 3);
if (draw_call.surface_depth_format == Surface_depth_format::z24s8)
{
for (u32 row = 0; row < height; row++)
{
for (u32 col = 0; col < width; col++)
{
u32 depth_val = gsl::as_span<const u32>(orig_buffer)[row * width + col];
u8 displayed_depth_val = 255 * depth_val / 0xFFFFFF;
buffer[3 * col + 0 + width * row * 3] = displayed_depth_val;
buffer[3 * col + 1 + width * row * 3] = displayed_depth_val;
buffer[3 * col + 2 + width * row * 3] = displayed_depth_val;
}
}
}
else
{
for (u32 row = 0; row < height; row++)
{
for (u32 col = 0; col < width; col++)
{
u16 depth_val = gsl::as_span<const u16>(orig_buffer)[row * width + col];
u8 displayed_depth_val = 255 * depth_val / 0xFFFF;
buffer[3 * col + 0 + width * row * 3] = displayed_depth_val;
buffer[3 * col + 1 + width * row * 3] = displayed_depth_val;
buffer[3 * col + 2 + width * row * 3] = displayed_depth_val;
}
}
}
depth_img = wxImage(width, height, buffer);
wxClientDC dc_canvas(p_buffer_depth);
if (depth_img.IsOk())
dc_canvas.DrawBitmap(depth_img.Scale(m_panel_width, m_panel_height), 0, 0, false);
}
}
// Buffer S
{
if (width && height && !draw_call.depth_stencil[1].empty())
{
gsl::span<const gsl::byte> orig_buffer = draw_call.depth_stencil[1];
u32 *orig_buffer = (u32*)frame_debug.draw_calls[draw_id].depth.data.data();
unsigned char *buffer = (unsigned char *)malloc(width * height * 3);
for (u32 row = 0; row < height; row++)
{
for (u32 col = 0; col < width; col++)
{
u8 stencil_val = gsl::as_span<const u8>(orig_buffer)[row * width + col];
u32 depth_val = orig_buffer[row * width + col];
u8 displayed_depth_val = 255 * depth_val / 0xFFFFFF;
buffer[3 * col + 0 + width * row * 3] = displayed_depth_val;
buffer[3 * col + 1 + width * row * 3] = displayed_depth_val;
buffer[3 * col + 2 + width * row * 3] = displayed_depth_val;
}
}
wxImage img(width, height, buffer);
wxClientDC dc_canvas(p_buffer_depth);
if (img.IsOk())
dc_canvas.DrawBitmap(img.Scale(m_panel_width, m_panel_height), 0, 0, false);
}
}
// Buffer S
{
size_t width = frame_debug.draw_calls[draw_id].stencil.width, height = frame_debug.draw_calls[draw_id].stencil.height;
if (width && height)
{
u8 *orig_buffer = frame_debug.draw_calls[draw_id].stencil.data.data();
unsigned char *buffer = (unsigned char *)malloc(width * height * 3);
for (u32 row = 0; row < height; row++)
{
for (u32 col = 0; col < width; col++)
{
u32 stencil_val = orig_buffer[row * width + col];
buffer[3 * col + 0 + width * row * 3] = stencil_val;
buffer[3 * col + 1 + width * row * 3] = stencil_val;
buffer[3 * col + 2 + width * row * 3] = stencil_val;
}
}
stencil_img = wxImage(width, height, buffer);
wxImage img(width, height, buffer);
wxClientDC dc_canvas(p_buffer_stencil);
if (stencil_img.IsOk())
dc_canvas.DrawBitmap(stencil_img.Scale(m_panel_width, m_panel_height), 0, 0, false);
if (img.IsOk())
dc_canvas.DrawBitmap(img.Scale(m_panel_width, m_panel_height), 0, 0, false);
}
}
-2
View File
@@ -29,8 +29,6 @@ class RSXDebugger : public wxDialog
wxPanel* p_buffer_tex;
wxImage buffer_img[4];
wxImage depth_img;
wxImage stencil_img;
wxTextCtrl* m_text_transform_program;
wxTextCtrl *m_text_shader_program;
-2
View File
@@ -87,7 +87,6 @@
<ClCompile Include="Emu\RSX\Common\FragmentProgramDecompiler.cpp" />
<ClCompile Include="Emu\RSX\Common\ProgramStateCache.cpp" />
<ClCompile Include="Emu\RSX\Common\ShaderParam.cpp" />
<ClCompile Include="Emu\RSX\Common\surface_store.cpp" />
<ClCompile Include="Emu\RSX\Common\TextureUtils.cpp" />
<ClCompile Include="Emu\RSX\Common\VertexProgramDecompiler.cpp" />
<ClCompile Include="Emu\RSX\GCM.cpp" />
@@ -517,7 +516,6 @@
<ClInclude Include="Emu\RSX\Common\FragmentProgramDecompiler.h" />
<ClInclude Include="Emu\RSX\Common\ProgramStateCache.h" />
<ClInclude Include="Emu\RSX\Common\ShaderParam.h" />
<ClInclude Include="Emu\RSX\Common\surface_store.h" />
<ClInclude Include="Emu\RSX\Common\TextureUtils.h" />
<ClInclude Include="Emu\RSX\Common\VertexProgramDecompiler.h" />
<ClInclude Include="Emu\RSX\GCM.h" />
-6
View File
@@ -936,9 +936,6 @@
<ClCompile Include="Emu\RSX\Common\ProgramStateCache.cpp">
<Filter>Emu\GPU\RSX\Common</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\Common\surface_store.cpp">
<Filter>Emu\GPU\RSX\Common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">
@@ -1791,8 +1788,5 @@
<ClInclude Include="..\stblib\stb_image.c">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="Emu\RSX\Common\surface_store.h">
<Filter>Emu\GPU\RSX\Common</Filter>
</ClInclude>
</ItemGroup>
</Project>