mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 12:32:43 +00:00
Merge pull request #1446 from vlj/rsx
rsx/common/d3d12: Move surface_store in common
This commit is contained in:
commit
9f7caf90e3
66
rpcs3/Emu/RSX/Common/surface_store.cpp
Normal file
66
rpcs3/Emu/RSX/Common/surface_store.cpp
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
348
rpcs3/Emu/RSX/Common/surface_store.h
Normal file
348
rpcs3/Emu/RSX/Common/surface_store.h
Normal file
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
@ -116,7 +116,7 @@ private:
|
||||
data_heap m_buffer_data;
|
||||
data_heap m_readback_resources;
|
||||
|
||||
render_targets m_rtts;
|
||||
rsx::render_targets m_rtts;
|
||||
|
||||
std::vector<D3D12_INPUT_ELEMENT_DESC> m_IASet;
|
||||
|
||||
@ -127,13 +127,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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -6,356 +6,10 @@
|
||||
|
||||
#include "D3D12Formats.h"
|
||||
#include "D3D12MemoryHelpers.h"
|
||||
#include <gsl.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 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);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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, 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();
|
||||
}
|
||||
|
||||
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 = get_aligned_pitch(surface_color_format, gsl::narrow<u32>(width));
|
||||
size_t dst_pitch = 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct render_target_traits
|
||||
{
|
||||
@ -481,7 +135,7 @@ struct render_target_traits
|
||||
{
|
||||
ID3D12GraphicsCommandList* command_list = res_store.command_list.Get();
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(color_format);
|
||||
size_t row_pitch = rsx::get_aligned_pitch(color_format, gsl::narrow<u32>(width));
|
||||
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);
|
||||
@ -593,6 +247,11 @@ struct render_target_traits
|
||||
{
|
||||
readback_heap.unmap();
|
||||
}
|
||||
|
||||
static ID3D12Resource* get(const ComPtr<ID3D12Resource> &in)
|
||||
{
|
||||
return in.Get();
|
||||
}
|
||||
};
|
||||
|
||||
struct render_targets : public rsx::surface_store<render_target_traits>
|
||||
@ -605,3 +264,4 @@ struct render_targets : public rsx::surface_store<render_target_traits>
|
||||
void init(ID3D12Device *device);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -504,6 +504,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
|
||||
|
@ -287,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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user