Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ae6ff4449e | |||
| f47540b48c | |||
| e12fbae17c | |||
| 2399107fdf | |||
| 97c848c521 | |||
| 7706dcb7cd | |||
| 29791bcacf | |||
| eb6f737895 | |||
| 560b363ad2 | |||
| 1883310ea3 | |||
| 14791630f9 | |||
| b9914a8aab | |||
| 435838e89c | |||
| 19cc11cf91 | |||
| 9820a2a7c3 | |||
| 5641a2ce70 | |||
| d0ec3f33e7 | |||
| 9f7caf90e3 | |||
| f453194e32 | |||
| 440c637b1f | |||
| d95809a069 | |||
| 6aac972bda | |||
| 233689a6bc | |||
| 92c17c35ec | |||
| 73a4555c9d | |||
| d9f4b4b600 | |||
| 3d765e26bf | |||
| bb3950804f | |||
| 0b1da09106 | |||
| df3fddc026 | |||
| 1ce49b60d9 | |||
| 8b5b23e6c0 |
@@ -686,10 +686,8 @@ 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;
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatWarningAsError>false</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)"); return true;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1.xxxx)"); return true;
|
||||
// Note: DIVSQ is not IEEE compliant. divsq(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix).
|
||||
// sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven.
|
||||
case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, $1)"); return true;
|
||||
@@ -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)"); return true;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1.xxxx)"); return true;
|
||||
// Note: DIVSQ is not IEEE compliant. sqrt(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix).
|
||||
// sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven.
|
||||
case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, sqrt($1).xxxx)"); return true;
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
|
||||
using namespace program_hash_util;
|
||||
|
||||
size_t vertex_program_hash::operator()(const std::vector<u32> &program) const
|
||||
size_t vertex_program_hash::operator()(const RSXVertexProgram &program) const
|
||||
{
|
||||
// 64-bit Fowler/Noll/Vo FNV-1a hash code
|
||||
size_t hash = 0xCBF29CE484222325ULL;
|
||||
const qword *instbuffer = (const qword*)program.data();
|
||||
const qword *instbuffer = (const qword*)program.data.data();
|
||||
size_t instIndex = 0;
|
||||
bool end = false;
|
||||
for (unsigned i = 0; i < program.size() / 4; i++)
|
||||
for (unsigned i = 0; i < program.data.size() / 4; i++)
|
||||
{
|
||||
const qword inst = instbuffer[instIndex];
|
||||
hash ^= inst.dword[0];
|
||||
@@ -22,13 +22,17 @@ size_t vertex_program_hash::operator()(const std::vector<u32> &program) const
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool vertex_program_compare::operator()(const std::vector<u32> &binary1, const std::vector<u32> &binary2) const
|
||||
bool vertex_program_compare::operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &binary2) const
|
||||
{
|
||||
if (binary1.size() != binary2.size()) return false;
|
||||
const qword *instBuffer1 = (const qword*)binary1.data();
|
||||
const qword *instBuffer2 = (const qword*)binary2.data();
|
||||
if (binary1.output_mask != binary2.output_mask)
|
||||
return false;
|
||||
if (binary1.rsx_vertex_inputs != binary2.rsx_vertex_inputs)
|
||||
return false;
|
||||
if (binary1.data.size() != binary2.data.size()) return false;
|
||||
const qword *instBuffer1 = (const qword*)binary1.data.data();
|
||||
const qword *instBuffer2 = (const qword*)binary2.data.data();
|
||||
size_t instIndex = 0;
|
||||
for (unsigned i = 0; i < binary1.size() / 4; i++)
|
||||
for (unsigned i = 0; i < binary1.data.size() / 4; i++)
|
||||
{
|
||||
const qword& inst1 = instBuffer1[instIndex];
|
||||
const qword& inst2 = instBuffer2[instIndex];
|
||||
|
||||
@@ -23,12 +23,12 @@ namespace program_hash_util
|
||||
|
||||
struct vertex_program_hash
|
||||
{
|
||||
size_t operator()(const std::vector<u32> &program) const;
|
||||
size_t operator()(const RSXVertexProgram &program) const;
|
||||
};
|
||||
|
||||
struct vertex_program_compare
|
||||
{
|
||||
bool operator()(const std::vector<u32> &binary1, const std::vector<u32> &binary2) const;
|
||||
bool operator()(const RSXVertexProgram &binary1, const RSXVertexProgram &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<std::vector<u32>, vertex_program_type, program_hash_util::vertex_program_hash, program_hash_util::vertex_program_compare> ;
|
||||
using binary_to_vertex_program = std::unordered_map<RSXVertexProgram, vertex_program_type, program_hash_util::vertex_program_hash, program_hash_util::vertex_program_compare> ;
|
||||
using binary_to_fragment_program = std::unordered_map<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.data);
|
||||
const auto& I = m_vertex_shader_cache.find(rsx_vp);
|
||||
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.data];
|
||||
vertex_program_type& new_shader = m_vertex_shader_cache[rsx_vp];
|
||||
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.data);
|
||||
if (I == m_vertex_shader_cache.end())
|
||||
auto I = m_vertex_shader_cache.find(rsx_vp);
|
||||
if (I != m_vertex_shader_cache.end())
|
||||
return I->second;
|
||||
throw new EXCEPTION("Trying to get unknow transform program");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "stdafx.h"
|
||||
#include "surface_store.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
std::vector<u8> get_rtt_indexes(Surface_target color_target)
|
||||
{
|
||||
switch (color_target)
|
||||
{
|
||||
case Surface_target::none: return{};
|
||||
case Surface_target::surface_a: return{ 0 };
|
||||
case Surface_target::surface_b: return{ 1 };
|
||||
case Surface_target::surfaces_a_b: return{ 0, 1 };
|
||||
case Surface_target::surfaces_a_b_c: return{ 0, 1, 2 };
|
||||
case Surface_target::surfaces_a_b_c_d: return{ 0, 1, 2, 3 };
|
||||
}
|
||||
throw EXCEPTION("Wrong color_target");
|
||||
}
|
||||
|
||||
size_t get_aligned_pitch(Surface_color_format format, u32 width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case Surface_color_format::b8: return align(width, 256);
|
||||
case Surface_color_format::g8b8:
|
||||
case Surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case Surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case Surface_color_format::r5g6b5: return align(width * 2, 256);
|
||||
case Surface_color_format::a8b8g8r8:
|
||||
case Surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case Surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case Surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case Surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case Surface_color_format::x32:
|
||||
case Surface_color_format::a8r8g8b8: return align(width * 4, 256);
|
||||
case Surface_color_format::w16z16y16x16: return align(width * 8, 256);
|
||||
case Surface_color_format::w32z32y32x32: return align(width * 16, 256);
|
||||
}
|
||||
throw EXCEPTION("Unknow color surface format");
|
||||
}
|
||||
|
||||
size_t get_packed_pitch(Surface_color_format format, u32 width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case Surface_color_format::b8: return width;
|
||||
case Surface_color_format::g8b8:
|
||||
case Surface_color_format::x1r5g5b5_o1r5g5b5:
|
||||
case Surface_color_format::x1r5g5b5_z1r5g5b5:
|
||||
case Surface_color_format::r5g6b5: return width * 2;
|
||||
case Surface_color_format::a8b8g8r8:
|
||||
case Surface_color_format::x8b8g8r8_o8b8g8r8:
|
||||
case Surface_color_format::x8b8g8r8_z8b8g8r8:
|
||||
case Surface_color_format::x8r8g8b8_o8r8g8b8:
|
||||
case Surface_color_format::x8r8g8b8_z8r8g8b8:
|
||||
case Surface_color_format::x32:
|
||||
case Surface_color_format::a8r8g8b8: return width * 4;
|
||||
case Surface_color_format::w16z16y16x16: return width * 8;
|
||||
case Surface_color_format::w32z32y32x32: return width * 16;
|
||||
}
|
||||
throw EXCEPTION("Unknow color surface format");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
#pragma once
|
||||
|
||||
#include <gsl.h>
|
||||
#include "../GCM.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
std::vector<u8> get_rtt_indexes(Surface_target color_target);
|
||||
size_t get_aligned_pitch(Surface_color_format format, u32 width);
|
||||
size_t get_packed_pitch(Surface_color_format format, u32 width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for surface (ie color and depth stencil render target) management.
|
||||
* It handles surface creation and storage. Backend should only retrieve pointer to surface.
|
||||
* It provides 2 methods get_texture_from_*_if_applicable that should be used when an app
|
||||
* wants to sample a previous surface.
|
||||
* Please note that the backend is still responsible for creating framebuffer/descriptors
|
||||
* and need to inform surface_store everytime surface format/size/addresses change.
|
||||
*
|
||||
* Since it's a template it requires a trait with the followings:
|
||||
* - type surface_storage_type which is a structure containing texture.
|
||||
* - type surface_type which is a pointer to storage_type or a reference.
|
||||
* - type command_list_type that can be void for backend without command list
|
||||
* - type download_buffer_object used by issue_download_command and map_downloaded_buffer functions to handle sync
|
||||
*
|
||||
* - a member function static surface_type(const surface_storage_type&) that returns underlying surface pointer from a storage type.
|
||||
* - 2 member functions static surface_storage_type create_new_surface(u32 address, Surface_color_format/Surface_depth_format format, size_t width, size_t height,...)
|
||||
* used to create a new surface_storage_type holding surface from passed parameters.
|
||||
* - a member function static prepare_rtt_for_drawing(command_list, surface_type) that makes a sampleable surface a color render target one.
|
||||
* - a member function static prepare_rtt_for_drawing(command_list, surface_type) that makes a render target surface a sampleable one.
|
||||
* - a member function static prepare_ds_for_drawing that does the same for depth stencil surface.
|
||||
* - a member function static prepare_ds_for_sampling that does the same for depth stencil surface.
|
||||
* - a member function static bool rtt_has_format_width_height(const surface_storage_type&, Surface_color_format surface_color_format, size_t width, size_t height)
|
||||
* that checks if the given surface has the given format and size
|
||||
* - a member function static bool ds_has_format_width_height that does the same for ds
|
||||
* - a member function static download_buffer_object issue_download_command(surface_type, Surface_color_format color_format, size_t width, size_t height,...)
|
||||
* that generates command to download the given surface to some mappable buffer.
|
||||
* - a member function static issue_depth_download_command that does the same for depth surface
|
||||
* - a member function static issue_stencil_download_command that does the same for stencil surface
|
||||
* - a member function gsl::span<const gsl::byte> map_downloaded_buffer(download_buffer_object, ...) that maps a download_buffer_object
|
||||
* - a member function static unmap_downloaded_buffer that unmaps it.
|
||||
*/
|
||||
template<typename Traits>
|
||||
struct surface_store
|
||||
{
|
||||
template<typename T, typename U>
|
||||
void copy_pitched_src_to_dst(gsl::span<T> dest, gsl::span<const U> src, size_t src_pitch_in_bytes, size_t width, size_t height)
|
||||
{
|
||||
for (int row = 0; row < height; row++)
|
||||
{
|
||||
for (unsigned col = 0; col < width; col++)
|
||||
dest[col] = src[col];
|
||||
src = src.subspan(src_pitch_in_bytes / sizeof(U));
|
||||
dest = dest.subspan(width);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using surface_storage_type = typename Traits::surface_storage_type;
|
||||
using surface_type = typename Traits::surface_type;
|
||||
using command_list_type = typename Traits::command_list_type;
|
||||
using download_buffer_object = typename Traits::download_buffer_object;
|
||||
|
||||
std::unordered_map<u32, surface_storage_type> m_render_targets_storage = {};
|
||||
std::unordered_map<u32, surface_storage_type> m_depth_stencil_storage = {};
|
||||
|
||||
public:
|
||||
std::array<std::tuple<u32, surface_type>, 4> m_bound_render_targets = {};
|
||||
std::tuple<u32, surface_type> m_bound_depth_stencil = {};
|
||||
|
||||
std::list<surface_storage_type> invalidated_resources;
|
||||
|
||||
surface_store() = default;
|
||||
~surface_store() = default;
|
||||
surface_store(const surface_store&) = delete;
|
||||
private:
|
||||
/**
|
||||
* If render target already exists at address, issue state change operation on cmdList.
|
||||
* Otherwise create one with width, height, clearColor info.
|
||||
* returns the corresponding render target resource.
|
||||
*/
|
||||
template <typename ...Args>
|
||||
gsl::not_null<surface_type> bind_address_as_render_targets(
|
||||
command_list_type command_list,
|
||||
u32 address,
|
||||
Surface_color_format 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -9,15 +9,18 @@
|
||||
#include "../rsx_methods.h"
|
||||
|
||||
|
||||
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> 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> vertex_buffer_views;
|
||||
|
||||
m_IASet.clear();
|
||||
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));
|
||||
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;
|
||||
|
||||
@@ -34,9 +37,9 @@ std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(co
|
||||
// Active vertex array
|
||||
const rsx::data_array_format_info &info = vertex_arrays_info[index];
|
||||
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
|
||||
size_t 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));
|
||||
@@ -47,25 +50,51 @@ std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(co
|
||||
}
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view =
|
||||
command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size);
|
||||
|
||||
UINT component_mapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
switch (info.size)
|
||||
{
|
||||
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size,
|
||||
(UINT)element_size
|
||||
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
|
||||
};
|
||||
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)
|
||||
{
|
||||
@@ -74,34 +103,31 @@ std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::upload_vertex_attributes(co
|
||||
|
||||
const std::vector<u8> &data = register_vertex_data[index];
|
||||
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size);
|
||||
|
||||
size_t 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));
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view = {
|
||||
m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset,
|
||||
(UINT)buffer_size,
|
||||
(UINT)element_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
|
||||
};
|
||||
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);
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -190,7 +216,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)
|
||||
{
|
||||
@@ -199,16 +225,6 @@ 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);
|
||||
}
|
||||
|
||||
@@ -258,11 +274,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> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
|
||||
std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list)
|
||||
{
|
||||
if (draw_command == Draw_command::draw_command_inlined_array)
|
||||
{
|
||||
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);
|
||||
@@ -274,28 +290,25 @@ std::tuple<bool, size_t> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12G
|
||||
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);
|
||||
return std::make_tuple(false, vertex_count, upload_vertex_attributes(first_count_commands, command_list));
|
||||
}
|
||||
|
||||
D3D12_INDEX_BUFFER_VIEW index_buffer_view;
|
||||
size_t index_count;
|
||||
std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array(first_count_commands);
|
||||
command_list->IASetIndexBuffer(&index_buffer_view);
|
||||
return std::make_tuple(true, index_count);
|
||||
return std::make_tuple(true, index_count, upload_vertex_attributes(first_count_commands, command_list));
|
||||
}
|
||||
|
||||
assert(draw_command == Draw_command::draw_command_indexed);
|
||||
@@ -337,10 +350,7 @@ std::tuple<bool, size_t> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12G
|
||||
m_timers.m_buffer_upload_size += buffer_size;
|
||||
command_list->IASetIndexBuffer(&index_buffer_view);
|
||||
|
||||
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertex_buffer_views = upload_vertex_attributes({ std::make_pair(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);
|
||||
return std::make_tuple(true, index_count, upload_vertex_attributes({ std::make_pair(0, max_index + 1) }, command_list));
|
||||
}
|
||||
|
||||
#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 << ");" << std::endl;
|
||||
OS << "Texture2D " << PI.name << " : register(t" << textureIndex + 16 << ");" << 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 << ");" << std::endl;
|
||||
OS << "TextureCube " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl;
|
||||
OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,33 +143,43 @@ D3D12GSRender::D3D12GSRender()
|
||||
m_device->CreateRenderTargetView(m_backbuffer[1].Get(), &renter_target_view_desc, m_backbuffer_descriptor_heap[1]->GetCPUDescriptorHandleForHeapStart());
|
||||
|
||||
// Common root signatures
|
||||
for (unsigned texture_count = 0; texture_count < 17; texture_count++)
|
||||
for (int vertex_buffer_count = 0; vertex_buffer_count < 17; vertex_buffer_count++) // Some app (naruto ultimate ninja storm 2) uses a shader without inputs...
|
||||
{
|
||||
CD3DX12_DESCRIPTOR_RANGE descriptorRange[] =
|
||||
for (unsigned texture_count = 0; texture_count < 17; texture_count++)
|
||||
{
|
||||
// Scale Offset data
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0),
|
||||
// Constants
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 2, 1),
|
||||
// Textures
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture_count, 0),
|
||||
// Samplers
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, texture_count, 0),
|
||||
};
|
||||
CD3DX12_ROOT_PARAMETER RP[2];
|
||||
RP[0].InitAsDescriptorTable((texture_count > 0) ? 3 : 2, &descriptorRange[0]);
|
||||
RP[1].InitAsDescriptorTable(1, &descriptorRange[3]);
|
||||
CD3DX12_DESCRIPTOR_RANGE descriptorRange[] =
|
||||
{
|
||||
// Vertex buffer
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, vertex_buffer_count, 0),
|
||||
// Scale Offset data
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0),
|
||||
// Constants
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 2, 1),
|
||||
// Textures
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, texture_count, 16),
|
||||
// Samplers
|
||||
CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, texture_count, 0),
|
||||
};
|
||||
CD3DX12_ROOT_PARAMETER RP[2];
|
||||
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]);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> rootSignatureBlob;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
|
||||
CHECK_HRESULT(wrapD3D12SerializeRootSignature(
|
||||
&CD3DX12_ROOT_SIGNATURE_DESC((texture_count > 0) ? 2 : 1, RP, 0, 0, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT),
|
||||
D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob));
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> rootSignatureBlob;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
|
||||
CHECK_HRESULT(wrapD3D12SerializeRootSignature(
|
||||
&CD3DX12_ROOT_SIGNATURE_DESC((texture_count > 0) ? 2 : 1, RP, 0, 0),
|
||||
D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob));
|
||||
|
||||
m_device->CreateRootSignature(0,
|
||||
rootSignatureBlob->GetBufferPointer(),
|
||||
rootSignatureBlob->GetBufferSize(),
|
||||
IID_PPV_ARGS(m_root_signatures[texture_count].GetAddressOf()));
|
||||
m_device->CreateRootSignature(0,
|
||||
rootSignatureBlob->GetBufferPointer(),
|
||||
rootSignatureBlob->GetBufferSize(),
|
||||
IID_PPV_ARGS(m_root_signatures[texture_count][vertex_buffer_count].GetAddressOf()));
|
||||
}
|
||||
}
|
||||
|
||||
m_per_frame_storage[0].init(m_device.Get());
|
||||
@@ -194,6 +204,17 @@ 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();
|
||||
}
|
||||
@@ -250,9 +271,14 @@ 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::tie(indexed_draw, vertex_count) = upload_and_set_vertex_index_data(get_current_resource_storage().command_list.Get());
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_views;
|
||||
std::tie(indexed_draw, vertex_count, vertex_buffer_views) = upload_and_set_vertex_index_data(get_current_resource_storage().command_list.Get());
|
||||
|
||||
size_t vertex_buffer_count = vertex_buffer_views.size();
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> vertex_index_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_vertex_index_duration += std::chrono::duration_cast<std::chrono::microseconds>(vertex_index_duration_end - vertex_index_duration_start).count();
|
||||
@@ -262,16 +288,23 @@ 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)].Get());
|
||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_root_signatures[std::get<2>(m_current_pso)][vertex_buffer_count].Get());
|
||||
get_current_resource_storage().command_list->OMSetStencilRef(rsx::method_registers[NV4097_SET_STENCIL_FUNC_REF]);
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> constants_duration_start = std::chrono::system_clock::now();
|
||||
|
||||
size_t currentDescriptorIndex = get_current_resource_storage().descriptors_heap_index;
|
||||
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));
|
||||
}
|
||||
|
||||
// Constants
|
||||
upload_and_bind_scale_offset_matrix(currentDescriptorIndex);
|
||||
upload_and_bind_vertex_shader_constants(currentDescriptorIndex + 1);
|
||||
upload_and_bind_fragment_shader_constants(currentDescriptorIndex + 2);
|
||||
upload_and_bind_scale_offset_matrix(currentDescriptorIndex + vertex_buffer_count);
|
||||
upload_and_bind_vertex_shader_constants(currentDescriptorIndex + 1 + vertex_buffer_count);
|
||||
upload_and_bind_fragment_shader_constants(currentDescriptorIndex + 2 + vertex_buffer_count);
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> constants_duration_end = std::chrono::system_clock::now();
|
||||
m_timers.m_constants_duration += std::chrono::duration_cast<std::chrono::microseconds>(constants_duration_end - constants_duration_start).count();
|
||||
@@ -281,8 +314,7 @@ 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, 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);
|
||||
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetGPUDescriptorHandleForHeapStart())
|
||||
@@ -294,16 +326,15 @@ 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;
|
||||
get_current_resource_storage().descriptors_heap_index += std::get<2>(m_current_pso) + 3 + vertex_buffer_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
get_current_resource_storage().command_list->SetDescriptorHeaps(1, get_current_resource_storage().descriptors_heap.GetAddressOf());
|
||||
get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0,
|
||||
CD3DX12_GPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetGPUDescriptorHandleForHeapStart())
|
||||
.Offset((INT)currentDescriptorIndex, g_descriptor_stride_srv_cbv_uav)
|
||||
);
|
||||
get_current_resource_storage().descriptors_heap_index += 3;
|
||||
get_current_resource_storage().descriptors_heap_index += 3 + vertex_buffer_count;
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> texture_duration_end = std::chrono::system_clock::now();
|
||||
|
||||
@@ -56,7 +56,7 @@ private:
|
||||
ComPtr<ID3D12Resource> m_backbuffer[2];
|
||||
ComPtr<ID3D12DescriptorHeap> m_backbuffer_descriptor_heap[2];
|
||||
// m_rootSignatures[N] is RS with N texture/sample
|
||||
ComPtr<ID3D12RootSignature> m_root_signatures[17];
|
||||
ComPtr<ID3D12RootSignature> m_root_signatures[17][17]; // indexed by [texture count][vertex count]
|
||||
|
||||
// TODO: Use a tree structure to parse more efficiently
|
||||
data_cache m_texture_cache;
|
||||
@@ -67,7 +67,7 @@ private:
|
||||
RSXVertexProgram vertex_program;
|
||||
RSXFragmentProgram fragment_program;
|
||||
PipelineStateObjectCache m_pso_cache;
|
||||
std::tuple<ComPtr<ID3D12PipelineState>, std::vector<size_t>, size_t> m_current_pso;
|
||||
std::tuple<ComPtr<ID3D12PipelineState>, size_t, size_t> m_current_pso;
|
||||
|
||||
struct
|
||||
{
|
||||
@@ -115,10 +115,9 @@ private:
|
||||
// Textures, constants, index and vertex buffers storage
|
||||
data_heap m_buffer_data;
|
||||
data_heap m_readback_resources;
|
||||
ComPtr<ID3D12Resource> m_vertex_buffer_data;
|
||||
|
||||
render_targets m_rtts;
|
||||
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> m_IASet;
|
||||
rsx::render_targets m_rtts;
|
||||
|
||||
INT g_descriptor_stride_srv_cbv_uav;
|
||||
INT g_descriptor_stride_dsv;
|
||||
@@ -127,13 +126,6 @@ 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();
|
||||
@@ -150,14 +142,15 @@ private:
|
||||
* Non native primitive type are emulated by index buffers expansion.
|
||||
* Returns whether the draw call is indexed or not and the vertex count to draw.
|
||||
*/
|
||||
std::tuple<bool, size_t> upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list);
|
||||
std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> > upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list);
|
||||
|
||||
/**
|
||||
* Upload all enabled vertex attributes for vertex in ranges described by vertex_ranges.
|
||||
* A range in vertex_range is a pair whose first element is the index of the beginning of the
|
||||
* range, and whose second element is the number of vertex in this range.
|
||||
*/
|
||||
std::vector<D3D12_VERTEX_BUFFER_VIEW> upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges);
|
||||
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> upload_vertex_attributes(const std::vector<std::pair<u32, u32> > &vertex_ranges,
|
||||
gsl::not_null<ID3D12GraphicsCommandList*> command_list);
|
||||
|
||||
std::tuple<D3D12_VERTEX_BUFFER_VIEW, size_t> upload_inlined_vertex_array();
|
||||
|
||||
@@ -200,8 +193,7 @@ protected:
|
||||
virtual void end() override;
|
||||
virtual void flip(int buffer) override;
|
||||
|
||||
virtual void copy_render_targets_to_memory(void *buffer, u8 rtt) override;
|
||||
virtual void copy_depth_buffer_to_memory(void *buffer) override;
|
||||
virtual void copy_stencil_buffer_to_memory(void *buffer) override;
|
||||
virtual std::array<std::vector<gsl::byte>, 4> copy_render_targets_to_memory() override;
|
||||
virtual std::array<std::vector<gsl::byte>, 2> copy_depth_stencil_buffer_to_memory() override;
|
||||
virtual std::pair<std::string, std::string> get_programs() const override;
|
||||
};
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
template<int Alignement>
|
||||
size_t alloc(size_t size)
|
||||
{
|
||||
if (!can_alloc<Alignement>(size)) throw EXCEPTION("Working buffer not big enough");
|
||||
if (!can_alloc<Alignement>(size)) LOG_ERROR (RSX, "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)
|
||||
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)
|
||||
{}
|
||||
|
||||
bool operator==(const texture_entry &other)
|
||||
{
|
||||
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height);
|
||||
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height && m_mipmap == other.m_mipmap);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,42 @@ 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;
|
||||
@@ -251,7 +287,6 @@ 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);
|
||||
|
||||
@@ -10,7 +10,6 @@ struct D3D12PipelineProperties
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE Topology;
|
||||
DXGI_FORMAT DepthStencilFormat;
|
||||
DXGI_FORMAT RenderTargetsFormat;
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> IASet;
|
||||
D3D12_BLEND_DESC Blend;
|
||||
unsigned numMRT : 3;
|
||||
D3D12_DEPTH_STENCIL_DESC DepthStencil;
|
||||
@@ -19,23 +18,6 @@ struct D3D12PipelineProperties
|
||||
|
||||
bool operator==(const D3D12PipelineProperties &in) const
|
||||
{
|
||||
if (IASet.size() != in.IASet.size())
|
||||
return false;
|
||||
for (unsigned i = 0; i < IASet.size(); i++)
|
||||
{
|
||||
const D3D12_INPUT_ELEMENT_DESC &a = IASet[i], &b = in.IASet[i];
|
||||
if (a.AlignedByteOffset != b.AlignedByteOffset)
|
||||
return false;
|
||||
if (a.Format != b.Format)
|
||||
return false;
|
||||
if (a.InputSlot != b.InputSlot)
|
||||
return false;
|
||||
if (a.InstanceDataStepRate != b.InstanceDataStepRate)
|
||||
return false;
|
||||
if (a.SemanticIndex != b.SemanticIndex)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(&DepthStencil, &in.DepthStencil, sizeof(D3D12_DEPTH_STENCIL_DESC)))
|
||||
return false;
|
||||
if (memcmp(&Blend, &in.Blend, sizeof(D3D12_BLEND_DESC)))
|
||||
@@ -93,7 +75,7 @@ public:
|
||||
ComPtr<ID3DBlob> bytecode;
|
||||
// For debugging
|
||||
std::string content;
|
||||
std::vector<size_t> vertex_shader_inputs;
|
||||
size_t vertex_shader_input_count;
|
||||
std::vector<size_t> FragmentConstantOffsetCache;
|
||||
size_t m_textureCount;
|
||||
|
||||
@@ -118,29 +100,11 @@ 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>, std::vector<size_t>, size_t>;
|
||||
using pipeline_storage_type = std::tuple<ComPtr<ID3D12PipelineState>, size_t, size_t>;
|
||||
using pipeline_properties = D3D12PipelineProperties;
|
||||
|
||||
static
|
||||
@@ -176,15 +140,15 @@ struct D3D12Traits
|
||||
D3D12VertexProgramDecompiler VS(RSXVP);
|
||||
std::string shaderCode = VS.Decompile();
|
||||
vertexProgramData.Compile(shaderCode, Shader::SHADER_TYPE::SHADER_TYPE_VERTEX);
|
||||
vertexProgramData.vertex_shader_inputs = VS.input_slots;
|
||||
vertexProgramData.vertex_shader_input_count = RSXVP.rsx_vertex_inputs.size();
|
||||
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> 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, 17> root_signatures)
|
||||
{
|
||||
std::tuple<ID3D12PipelineState *, std::vector<size_t>, size_t> result = {};
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {};
|
||||
@@ -199,7 +163,7 @@ struct D3D12Traits
|
||||
graphicPipelineStateDesc.PS.BytecodeLength = fragmentProgramData.bytecode->GetBufferSize();
|
||||
graphicPipelineStateDesc.PS.pShaderBytecode = fragmentProgramData.bytecode->GetBufferPointer();
|
||||
|
||||
graphicPipelineStateDesc.pRootSignature = root_signatures[fragmentProgramData.m_textureCount].Get();
|
||||
graphicPipelineStateDesc.pRootSignature = root_signatures[fragmentProgramData.m_textureCount][vertexProgramData.vertex_shader_input_count].Get();
|
||||
|
||||
graphicPipelineStateDesc.BlendState = pipelineProperties.Blend;
|
||||
graphicPipelineStateDesc.DepthStencilState = pipelineProperties.DepthStencil;
|
||||
@@ -211,10 +175,6 @@ 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;
|
||||
@@ -226,7 +186,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_inputs, fragmentProgramData.m_textureCount);
|
||||
return std::make_tuple(pso, vertexProgramData.vertex_shader_input_count, fragmentProgramData.m_textureCount);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -171,58 +171,23 @@ 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_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)
|
||||
if (!m_rtts_dirty)
|
||||
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, 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);
|
||||
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);
|
||||
|
||||
// write descriptors
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(m_surface.color_format);
|
||||
@@ -261,7 +226,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 render_targets::init(ID3D12Device *device)
|
||||
void rsx::render_targets::init(ID3D12Device *device)
|
||||
{
|
||||
g_descriptor_stride_rtv = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
}
|
||||
@@ -488,91 +453,21 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
}
|
||||
|
||||
|
||||
void D3D12GSRender::copy_render_targets_to_memory(void *buffer, u8 rtt)
|
||||
std::array<std::vector<gsl::byte>, 4> D3D12GSRender::copy_render_targets_to_memory()
|
||||
{
|
||||
size_t heap_offset = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, 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;
|
||||
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);
|
||||
rsx::surface_info surface = {};
|
||||
surface.unpack(rsx::method_registers[NV4097_SET_SURFACE_FORMAT]);
|
||||
return m_rtts.get_render_targets_data(surface.color_format, clip_w, clip_h, m_device.Get(), m_command_queue.Get(), m_readback_resources, get_current_resource_storage());
|
||||
}
|
||||
|
||||
void D3D12GSRender::copy_depth_buffer_to_memory(void *buffer)
|
||||
std::array<std::vector<gsl::byte>, 2> D3D12GSRender::copy_depth_stencil_buffer_to_memory()
|
||||
{
|
||||
unsigned clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
unsigned clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
|
||||
size_t row_pitch = align(clip_w * 4, 256);
|
||||
|
||||
size_t buffer_size = row_pitch * clip_h;
|
||||
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();
|
||||
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
rsx::surface_info surface = {};
|
||||
surface.unpack(rsx::method_registers[NV4097_SET_SURFACE_FORMAT]);
|
||||
return m_rtts.get_depth_stencil_data(surface.depth_format, clip_w, clip_h, m_device.Get(), m_command_queue.Get(), m_readback_resources, get_current_resource_storage());
|
||||
}
|
||||
|
||||
|
||||
void D3D12GSRender::copy_stencil_buffer_to_memory(void *buffer)
|
||||
{
|
||||
unsigned clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
|
||||
unsigned clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
|
||||
|
||||
size_t row_pitch = align(clip_w * 4, 256);
|
||||
|
||||
size_t buffer_size = row_pitch * clip_h;
|
||||
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
|
||||
|
||||
@@ -5,177 +5,18 @@
|
||||
#include "d3dx12.h"
|
||||
|
||||
#include "D3D12Formats.h"
|
||||
#include <gsl.h>
|
||||
#include "D3D12MemoryHelpers.h"
|
||||
#include "../Common/surface_store.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(
|
||||
@@ -284,6 +125,133 @@ 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>
|
||||
@@ -296,3 +264,4 @@ struct render_targets : public rsx::surface_store<render_target_traits>
|
||||
void init(ID3D12Device *device);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -52,20 +52,40 @@ 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)
|
||||
{
|
||||
OS << "struct VertexInput" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
std::vector<std::tuple<size_t, std::string>> input_data;
|
||||
for (const ParamType PT : inputs)
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
OS << " " << PT.type << " " << PI.name << ": TEXCOORD" << PI.location << ";" << std::endl;
|
||||
input_slots.push_back(PI.location);
|
||||
input_data.push_back(std::make_tuple(PI.location, PI.name));
|
||||
}
|
||||
}
|
||||
OS << "};" << std::endl;
|
||||
|
||||
std::sort(input_data.begin(), input_data.end());
|
||||
|
||||
size_t t_register = 0;
|
||||
for (const auto &attribute : input_data)
|
||||
{
|
||||
if (declare_input(OS, attribute, rsx_vertex_program.rsx_vertex_inputs, t_register))
|
||||
t_register++;
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12VertexProgramDecompiler::insertConstants(std::stringstream & OS, const std::vector<ParamType> & constants)
|
||||
@@ -140,9 +160,39 @@ 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(VertexInput In)" << std::endl;
|
||||
OS << "PixelInput main(uint vertex_id : SV_VertexID)" << std::endl;
|
||||
OS << "{" << std::endl;
|
||||
|
||||
// Declare inside main function
|
||||
@@ -162,7 +212,9 @@ void D3D12VertexProgramDecompiler::insertMainStart(std::stringstream & OS)
|
||||
for (const ParamType PT : m_parr.params[PF_PARAM_IN])
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl;
|
||||
{
|
||||
add_input(OS, PI, rsx_vertex_program.rsx_vertex_inputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +234,7 @@ void D3D12VertexProgramDecompiler::insertMainEnd(std::stringstream & OS)
|
||||
}
|
||||
|
||||
D3D12VertexProgramDecompiler::D3D12VertexProgramDecompiler(const RSXVertexProgram &prog) :
|
||||
VertexProgramDecompiler(prog)
|
||||
VertexProgramDecompiler(prog), rsx_vertex_program(prog)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,8 @@ protected:
|
||||
virtual void insertOutputs(std::stringstream &OS, const std::vector<ParamType> &outputs);
|
||||
virtual void insertMainStart(std::stringstream &OS);
|
||||
virtual void insertMainEnd(std::stringstream &OS);
|
||||
|
||||
const RSXVertexProgram &rsx_vertex_program;
|
||||
public:
|
||||
std::vector<size_t> input_slots;
|
||||
D3D12VertexProgramDecompiler(const RSXVertexProgram &prog);
|
||||
};
|
||||
|
||||
@@ -753,6 +753,42 @@ 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];
|
||||
|
||||
+43
-38
@@ -276,44 +276,14 @@ 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;
|
||||
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());
|
||||
}
|
||||
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());
|
||||
draw_state.programs = get_programs();
|
||||
draw_state.name = name;
|
||||
frame_debug.draw_calls.push_back(draw_state);
|
||||
@@ -331,7 +301,10 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,6 +507,38 @@ 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
@@ -15,19 +15,16 @@ 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;
|
||||
buffer color_buffer[4];
|
||||
buffer depth;
|
||||
buffer stencil;
|
||||
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;
|
||||
};
|
||||
std::vector<std::pair<u32, u32> > command_queue;
|
||||
std::vector<draw_state> draw_calls;
|
||||
@@ -290,6 +287,11 @@ 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;
|
||||
@@ -347,19 +349,17 @@ namespace rsx
|
||||
* Copy rtt values to buffer.
|
||||
* TODO: It's more efficient to combine multiple call of this function into one.
|
||||
*/
|
||||
virtual void copy_render_targets_to_memory(void *buffer, u8 rtt) {};
|
||||
virtual std::array<std::vector<gsl::byte>, 4> copy_render_targets_to_memory() {
|
||||
return std::array<std::vector<gsl::byte>, 4>();
|
||||
};
|
||||
|
||||
/**
|
||||
* Copy depth content to buffer.
|
||||
* Copy depth and stencil content to buffers.
|
||||
* TODO: It's more efficient to combine multiple call of this function into one.
|
||||
*/
|
||||
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::array<std::vector<gsl::byte>, 2> copy_depth_stencil_buffer_to_memory() {
|
||||
return std::array<std::vector<gsl::byte>, 2>();
|
||||
};
|
||||
|
||||
virtual std::pair<std::string, std::string> get_programs() const { return std::make_pair("", ""); };
|
||||
public:
|
||||
|
||||
@@ -190,7 +190,23 @@ 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;
|
||||
};
|
||||
|
||||
@@ -282,6 +282,11 @@ namespace rsx
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
force_inline void set_surface_dirty_bit(thread* rsx, u32)
|
||||
{
|
||||
rsx->m_rtts_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace nv308a
|
||||
@@ -786,6 +791,16 @@ 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>();
|
||||
@@ -806,6 +821,19 @@ 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>();
|
||||
|
||||
@@ -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
|
||||
u16 limit_mask = (log2width < log2height) ? log2width : log2height;
|
||||
u32 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);
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ 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:
|
||||
@@ -478,6 +479,7 @@ 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;
|
||||
@@ -485,7 +487,6 @@ 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:
|
||||
@@ -595,6 +596,7 @@ 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:
|
||||
|
||||
@@ -1039,7 +1039,8 @@ s32 cellFsChangeFileSizeByFdWithoutAllocation()
|
||||
|
||||
s32 cellFsSetDiscReadRetrySetting()
|
||||
{
|
||||
throw EXCEPTION("");
|
||||
UNIMPLEMENTED_FUNC(cellFs);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsRegisterConversionCallback()
|
||||
|
||||
@@ -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 CELL_OK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
s32 sceNpCommerceCreateCtx()
|
||||
|
||||
@@ -235,7 +235,8 @@ s32 sceNpMatching2SetSignalingOptParam()
|
||||
|
||||
s32 sceNpMatching2RegisterContextCallback()
|
||||
{
|
||||
throw EXCEPTION("");
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpMatching2SendRoomChatMessage()
|
||||
@@ -275,7 +276,8 @@ s32 sceNpMatching2GrantRoomOwner()
|
||||
|
||||
s32 sceNpMatching2CreateContext()
|
||||
{
|
||||
throw EXCEPTION("");
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpMatching2GetSignalingOptParamLocal()
|
||||
@@ -325,12 +327,14 @@ s32 sceNpMatching2DeleteServerContext()
|
||||
|
||||
s32 sceNpMatching2SetDefaultRequestOptParam()
|
||||
{
|
||||
throw EXCEPTION("");
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpMatching2RegisterRoomEventCallback()
|
||||
{
|
||||
throw EXCEPTION("");
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpMatching2GetRoomPasswordLocal()
|
||||
@@ -380,7 +384,8 @@ s32 sceNpMatching2SetLobbyMemberDataInternal()
|
||||
|
||||
s32 sceNpMatching2RegisterRoomMessageCallback()
|
||||
{
|
||||
throw EXCEPTION("");
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -193,7 +193,8 @@ s32 _sys_memchr()
|
||||
|
||||
s32 _sys_memmove()
|
||||
{
|
||||
return CELL_OK; //throw EXCEPTION("");
|
||||
UNIMPLEMENTED_FUNC(sys_libc);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s64 _sys_strlen(vm::cptr<char> str)
|
||||
|
||||
+106
-30
@@ -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_BUTTON, &RSXDebugger::OnClickBuffer, this);
|
||||
//p_buffer_stencil->Bind(wxEVT_BUTTON, &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_tex->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
|
||||
m_list_captured_draw_calls->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickDrawCalls, this);
|
||||
|
||||
@@ -364,6 +364,8 @@ 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();
|
||||
@@ -380,18 +382,74 @@ 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(u8 *orig_buffer, size_t width, size_t height) noexcept
|
||||
u8* convert_to_wximage_buffer(Surface_color_format format, gsl::span<const gsl::byte> 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++)
|
||||
{
|
||||
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];
|
||||
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];
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
@@ -401,6 +459,8 @@ 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,
|
||||
@@ -409,13 +469,14 @@ 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++)
|
||||
{
|
||||
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)
|
||||
if (width && height && !draw_call.color_buffer[i].empty())
|
||||
{
|
||||
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));
|
||||
buffer_img[i] = wxImage(width, height, convert_to_wximage_buffer(draw_call.surface_color_format, draw_call.color_buffer[i], width, height));
|
||||
wxClientDC dc_canvas(p_buffers[i]);
|
||||
|
||||
if (buffer_img[i].IsOk())
|
||||
@@ -425,56 +486,71 @@ void RSXDebugger::OnClickDrawCalls(wxMouseEvent& event)
|
||||
|
||||
// Buffer Z
|
||||
{
|
||||
size_t width = frame_debug.draw_calls[draw_id].depth.width, height = frame_debug.draw_calls[draw_id].depth.height;
|
||||
if (width && height)
|
||||
if (width && height && !draw_call.depth_stencil[0].empty())
|
||||
{
|
||||
u32 *orig_buffer = (u32*)frame_debug.draw_calls[draw_id].depth.data.data();
|
||||
gsl::span<const gsl::byte> orig_buffer = draw_call.depth_stencil[0];
|
||||
unsigned char *buffer = (unsigned char *)malloc(width * height * 3);
|
||||
|
||||
for (u32 row = 0; row < height; row++)
|
||||
if (draw_call.surface_depth_format == Surface_depth_format::z24s8)
|
||||
{
|
||||
for (u32 col = 0; col < width; col++)
|
||||
for (u32 row = 0; row < height; row++)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxImage img(width, height, buffer);
|
||||
depth_img = wxImage(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);
|
||||
if (depth_img.IsOk())
|
||||
dc_canvas.DrawBitmap(depth_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)
|
||||
if (width && height && !draw_call.depth_stencil[1].empty())
|
||||
{
|
||||
u8 *orig_buffer = frame_debug.draw_calls[draw_id].stencil.data.data();
|
||||
gsl::span<const gsl::byte> orig_buffer = draw_call.depth_stencil[1];
|
||||
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];
|
||||
u8 stencil_val = gsl::as_span<const u8>(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;
|
||||
}
|
||||
}
|
||||
|
||||
wxImage img(width, height, buffer);
|
||||
stencil_img = wxImage(width, height, buffer);
|
||||
wxClientDC dc_canvas(p_buffer_stencil);
|
||||
|
||||
if (img.IsOk())
|
||||
dc_canvas.DrawBitmap(img.Scale(m_panel_width, m_panel_height), 0, 0, false);
|
||||
if (stencil_img.IsOk())
|
||||
dc_canvas.DrawBitmap(stencil_img.Scale(m_panel_width, m_panel_height), 0, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ 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;
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<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" />
|
||||
@@ -516,6 +517,7 @@
|
||||
<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" />
|
||||
|
||||
@@ -936,6 +936,9 @@
|
||||
<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">
|
||||
@@ -1788,5 +1791,8 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user