rsx: Remove surface aa_mode hacks

This commit is contained in:
kd-11 2019-05-20 17:14:02 +03:00 committed by kd-11
parent ac3982d2b0
commit 0d906d6974
17 changed files with 644 additions and 809 deletions

View file

@ -1,4 +1,6 @@
#include "types.h" #pragma once
#include "types.h"
#include "StrFmt.h" #include "StrFmt.h"
#include <vector> #include <vector>
@ -376,7 +378,7 @@ namespace utils
// We use index access because we might have to push_back within the loop, which could invalidate the iterators // We use index access because we might have to push_back within the loop, which could invalidate the iterators
size_type _size = data.size(); size_type _size = data.size();
for (int n = 0; n < _size; ++n) for (size_type n = 0; n < _size; ++n)
{ {
address_range &existing = data[n]; address_range &existing = data[n];
@ -453,7 +455,7 @@ namespace utils
{ {
size_t _size = data.size(); size_t _size = data.size();
for (int i = 0; i < _size; ++i) for (size_t i = 0; i < _size; ++i)
{ {
const auto &r1 = data[i]; const auto &r1 = data[i];
if (!r1.valid()) if (!r1.valid())
@ -461,7 +463,7 @@ namespace utils
continue; continue;
} }
for (int j = i + 1; j < _size; ++j) for (size_t j = i + 1; j < _size; ++j)
{ {
const auto &r2 = data[j]; const auto &r2 = data[j];
if (!r2.valid()) if (!r2.valid())

View file

@ -652,6 +652,23 @@ u8 get_format_block_size_in_bytes(rsx::surface_color_format format)
} }
} }
u8 get_format_sample_count(rsx::surface_antialiasing antialias)
{
switch (antialias)
{
case rsx::surface_antialiasing::center_1_sample:
return 1;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
return 2;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
return 4;
default:
ASSUME(0);
return 0;
}
}
/** /**
* Returns number of texel lines decoded in one pitch-length number of bytes * Returns number of texel lines decoded in one pitch-length number of bytes
*/ */

View file

@ -28,6 +28,19 @@ namespace rsx
storage = 2, storage = 2,
}; };
enum surface_metrics : u32
{
pixels = 0,
samples = 1,
bytes = 2
};
enum surface_access : u32
{
read = 0,
write = 1
};
//Sampled image descriptor //Sampled image descriptor
struct sampled_image_descriptor_base struct sampled_image_descriptor_base
{ {
@ -108,6 +121,8 @@ u8 get_format_block_size_in_bytes(int format);
u8 get_format_block_size_in_texel(int format); u8 get_format_block_size_in_texel(int format);
u8 get_format_block_size_in_bytes(rsx::surface_color_format format); u8 get_format_block_size_in_bytes(rsx::surface_color_format format);
u8 get_format_sample_count(rsx::surface_antialiasing antialias);
/** /**
* Returns number of texel rows encoded in one pitch-length line of bytes * Returns number of texel rows encoded in one pitch-length line of bytes
*/ */

View file

@ -2,7 +2,7 @@
#include "Utilities/GSL.h" #include "Utilities/GSL.h"
#include "Emu/Memory/vm.h" #include "Emu/Memory/vm.h"
#include "TextureUtils.h" #include "surface_utils.h"
#include "../GCM.h" #include "../GCM.h"
#include "../rsx_utils.h" #include "../rsx_utils.h"
#include <list> #include <list>
@ -25,379 +25,6 @@ namespace rsx
size_t get_packed_pitch(surface_color_format format, u32 width); size_t get_packed_pitch(surface_color_format format, u32 width);
} }
enum surface_state_flags : u32
{
ready = 0,
erase_bkgnd = 1
};
template <typename surface_type>
struct surface_overlap_info_t
{
surface_type surface = nullptr;
u32 base_address = 0;
bool is_depth = false;
bool is_clipped = false;
u16 src_x = 0;
u16 src_y = 0;
u16 dst_x = 0;
u16 dst_y = 0;
u16 width = 0;
u16 height = 0;
areai get_src_area() const
{
return coordi{ {src_x, src_y}, {width, height} };
}
areai get_dst_area() const
{
return coordi{ {dst_x, dst_y}, {width, height} };
}
};
struct surface_format_info
{
u32 surface_width;
u32 surface_height;
u16 native_pitch;
u16 rsx_pitch;
u8 bpp;
};
template <typename surface_type>
struct deferred_clipped_region
{
u16 src_x, src_y, dst_x, dst_y, width, height;
f32 transfer_scale_x, transfer_scale_y;
surface_type target;
surface_type source;
template <typename T>
deferred_clipped_region<T> cast() const
{
deferred_clipped_region<T> ret;
ret.src_x = src_x;
ret.src_y = src_y;
ret.dst_x = dst_x;
ret.dst_y = dst_y;
ret.width = width;
ret.height = height;
ret.transfer_scale_x = transfer_scale_x;
ret.transfer_scale_y = transfer_scale_y;
ret.target = (T)(target);
ret.source = (T)(source);
return ret;
}
operator bool() const
{
return (source != nullptr);
}
template <typename T>
void init_transfer(T target_surface)
{
if (!width)
{
// Perform intersection here
const auto region = rsx::get_transferable_region(target_surface);
width = std::get<0>(region);
height = std::get<1>(region);
transfer_scale_x = f32(std::get<2>(region)) / width;
transfer_scale_y = f32(std::get<3>(region)) / height;
target = target_surface;
}
}
areai src_rect() const
{
verify(HERE), width;
return { src_x, src_y, src_x + width, src_y + height };
}
areai dst_rect() const
{
verify(HERE), width;
return { dst_x, dst_y, dst_x + u16(width * transfer_scale_x + 0.5f), dst_y + u16(height * transfer_scale_y + 0.5f) };
}
};
template <typename image_storage_type>
struct render_target_descriptor
{
u64 last_use_tag = 0; // tag indicating when this block was last confirmed to have been written to
std::array<std::pair<u32, u64>, 5> memory_tag_samples;
deferred_clipped_region<image_storage_type> old_contents{};
rsx::surface_antialiasing read_aa_mode = rsx::surface_antialiasing::center_1_sample;
GcmTileInfo *tile = nullptr;
rsx::surface_antialiasing write_aa_mode = rsx::surface_antialiasing::center_1_sample;
flags32_t memory_usage_flags = surface_usage_flags::unknown;
flags32_t state_flags = surface_state_flags::ready;
union
{
rsx::surface_color_format gcm_color_format;
rsx::surface_depth_format gcm_depth_format;
}
format_info;
render_target_descriptor() = default;
virtual ~render_target_descriptor()
{
if (old_contents)
{
// Cascade resource derefs
LOG_ERROR(RSX, "Resource was destroyed whilst holding a resource reference!");
}
}
virtual image_storage_type get_surface() = 0;
virtual u16 get_surface_width() const = 0;
virtual u16 get_surface_height() const = 0;
virtual u16 get_rsx_pitch() const = 0;
virtual u16 get_native_pitch() const = 0;
virtual bool is_depth_surface() const = 0;
virtual void release_ref(image_storage_type) const = 0;
u8 get_bpp() const
{
return u8(get_native_pitch() / get_surface_width());
}
void save_aa_mode()
{
read_aa_mode = write_aa_mode;
write_aa_mode = rsx::surface_antialiasing::center_1_sample;
}
void reset_aa_mode()
{
write_aa_mode = read_aa_mode = rsx::surface_antialiasing::center_1_sample;
}
void set_format(rsx::surface_color_format format)
{
format_info.gcm_color_format = format;
}
void set_format(rsx::surface_depth_format format)
{
format_info.gcm_depth_format = format;
}
rsx::surface_color_format get_surface_color_format()
{
return format_info.gcm_color_format;
}
rsx::surface_depth_format get_surface_depth_format()
{
return format_info.gcm_depth_format;
}
bool dirty() const
{
return (state_flags != rsx::surface_state_flags::ready) || old_contents;
}
bool test() const
{
if (dirty())
{
// TODO
// Should RCB or mem-sync (inherit previous mem) to init memory
LOG_TODO(RSX, "Resource used before memory initialization");
}
// Tags are tested in an X pattern
for (const auto &tag : memory_tag_samples)
{
if (!tag.first)
break;
if (tag.second != *reinterpret_cast<u64*>(vm::g_sudo_addr + tag.first))
return false;
}
return true;
}
void clear_rw_barrier()
{
release_ref(old_contents.source);
old_contents = {};
}
template<typename T>
void set_old_contents(T* other)
{
verify(HERE), !old_contents;
if (!other || other->get_rsx_pitch() != this->get_rsx_pitch())
{
old_contents = {};
return;
}
old_contents = {};
old_contents.source = other;
other->add_ref();
}
template<typename T>
void set_old_contents_region(const T& region, bool normalized)
{
if (old_contents)
{
// This can happen when doing memory splits
auto old_surface = static_cast<decltype(region.source)>(old_contents.source);
if (old_surface->last_use_tag > region.source->last_use_tag)
{
return;
}
clear_rw_barrier();
}
// NOTE: This method will not perform pitch verification!
verify(HERE), !old_contents, region.source, region.source != this;
old_contents = region.template cast<image_storage_type>();
region.source->add_ref();
// Reverse normalization process if needed
if (normalized)
{
const u16 bytes_to_texels_x = region.source->get_bpp() * (region.source->write_aa_mode == rsx::surface_antialiasing::center_1_sample? 1 : 2);
const u16 rows_to_texels_y = (region.source->write_aa_mode > rsx::surface_antialiasing::diagonal_centered_2_samples? 2 : 1);
old_contents.src_x /= bytes_to_texels_x;
old_contents.src_y /= rows_to_texels_y;
old_contents.width /= bytes_to_texels_x;
old_contents.height /= rows_to_texels_y;
const u16 bytes_to_texels_x2 = (get_bpp() * (write_aa_mode == rsx::surface_antialiasing::center_1_sample? 1 : 2));
const u16 rows_to_texels_y2 = (write_aa_mode > rsx::surface_antialiasing::diagonal_centered_2_samples)? 2 : 1;
old_contents.dst_x /= bytes_to_texels_x2;
old_contents.dst_y /= rows_to_texels_y2;
old_contents.transfer_scale_x = f32(bytes_to_texels_x) / bytes_to_texels_x2;
old_contents.transfer_scale_y = f32(rows_to_texels_y) / rows_to_texels_y2;
}
// Apply resolution scale if needed
if (g_cfg.video.resolution_scale_percent != 100)
{
auto src_width = rsx::apply_resolution_scale(old_contents.width, true, old_contents.source->width());
auto src_height = rsx::apply_resolution_scale(old_contents.height, true, old_contents.source->height());
auto dst_width = rsx::apply_resolution_scale(old_contents.width, true, old_contents.target->width());
auto dst_height = rsx::apply_resolution_scale(old_contents.height, true, old_contents.target->height());
old_contents.transfer_scale_x *= f32(dst_width) / src_width;
old_contents.transfer_scale_y *= f32(dst_height) / src_height;
old_contents.width = src_width;
old_contents.height = src_height;
old_contents.src_x = rsx::apply_resolution_scale(old_contents.src_x, false, old_contents.source->width());
old_contents.src_y = rsx::apply_resolution_scale(old_contents.src_y, false, old_contents.source->height());
old_contents.dst_x = rsx::apply_resolution_scale(old_contents.dst_x, false, old_contents.target->width());
old_contents.dst_y = rsx::apply_resolution_scale(old_contents.dst_y, false, old_contents.target->height());
}
}
void queue_tag(u32 address)
{
for (int i = 0; i < memory_tag_samples.size(); ++i)
{
if (LIKELY(i))
memory_tag_samples[i].first = 0;
else
memory_tag_samples[i].first = address; // Top left
}
const u32 pitch = get_native_pitch();
if (UNLIKELY(pitch < 16))
{
// Not enough area to gather samples if pitch is too small
return;
}
// Top right corner
memory_tag_samples[1].first = address + pitch - 8;
if (const u32 h = get_surface_height(); h > 1)
{
// Last row
const u32 pitch2 = get_rsx_pitch();
const u32 last_row_offset = pitch2 * (h - 1);
memory_tag_samples[2].first = address + last_row_offset; // Bottom left corner
memory_tag_samples[3].first = address + last_row_offset + pitch - 8; // Bottom right corner
// Centroid
const u32 center_row_offset = pitch2 * (h / 2);
memory_tag_samples[4].first = address + center_row_offset + pitch / 2;
}
}
void sync_tag()
{
for (auto &tag : memory_tag_samples)
{
if (!tag.first)
break;
tag.second = *reinterpret_cast<u64*>(vm::g_sudo_addr + tag.first);
}
}
void on_write(u64 write_tag = 0)
{
if (write_tag)
{
// Update use tag if requested
last_use_tag = write_tag;
}
// Tag unconditionally without introducing new data
sync_tag();
read_aa_mode = write_aa_mode;
// HACK!! This should be cleared through memory barriers only
state_flags = rsx::surface_state_flags::ready;
if (old_contents.source)
{
clear_rw_barrier();
}
}
// Returns the rect area occupied by this surface expressed as an 8bpp image with no AA
areau get_normalized_memory_area() const
{
const u16 internal_width = get_native_pitch() * (write_aa_mode > rsx::surface_antialiasing::center_1_sample? 2: 1);
const u16 internal_height = get_surface_height() * (write_aa_mode > rsx::surface_antialiasing::diagonal_centered_2_samples? 2: 1);
return { 0, 0, internal_width, internal_height };
}
rsx::address_range get_memory_range() const
{
const u32 internal_height = get_surface_height() * (write_aa_mode > rsx::surface_antialiasing::diagonal_centered_2_samples? 2: 1);
return rsx::address_range::start_length(memory_tag_samples[0].first, internal_height * get_rsx_pitch());
}
};
/** /**
* Helper for surface (ie color and depth stencil render target) management. * 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 handles surface creation and storage. Backend should only retrieve pointer to surface.
@ -435,7 +62,7 @@ namespace rsx
template<typename T, typename U> 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) 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 row = 0; row < height; row++)
{ {
for (unsigned col = 0; col < width; col++) for (unsigned col = 0; col < width; col++)
dest[col] = src[col]; dest[col] = src[col];
@ -548,7 +175,7 @@ namespace rsx
{ {
// Split in X // Split in X
const u32 baseaddr = address + _new.width; const u32 baseaddr = address + _new.width;
const u32 bytes_to_texels_x = (bpp * get_aa_factor_u(prev_surface->write_aa_mode)); const u32 bytes_to_texels_x = (bpp * prev_surface->samples_x);
deferred_clipped_region<surface_type> copy; deferred_clipped_region<surface_type> copy;
copy.src_x = _new.width / bytes_to_texels_x; copy.src_x = _new.width / bytes_to_texels_x;
@ -576,15 +203,15 @@ namespace rsx
{ {
// Split in Y // Split in Y
const u32 baseaddr = address + (_new.height * prev_surface->get_rsx_pitch()); const u32 baseaddr = address + (_new.height * prev_surface->get_rsx_pitch());
const u32 bytes_to_texels_x = (bpp * get_aa_factor_u(prev_surface->write_aa_mode)); const u32 bytes_to_texels_x = (bpp * prev_surface->samples_x);
deferred_clipped_region<surface_type> copy; deferred_clipped_region<surface_type> copy;
copy.src_x = 0; copy.src_x = 0;
copy.src_y = _new.height / get_aa_factor_v(prev_surface->write_aa_mode); copy.src_y = _new.height / prev_surface->samples_y;
copy.dst_x = 0; copy.dst_x = 0;
copy.dst_y = 0; copy.dst_y = 0;
copy.width = std::min(_new.width, old.width) / bytes_to_texels_x; copy.width = std::min(_new.width, old.width) / bytes_to_texels_x;
copy.height = (old.height - _new.height) / get_aa_factor_v(prev_surface->write_aa_mode); copy.height = (old.height - _new.height) / prev_surface->samples_y;
copy.transfer_scale_x = 1.f; copy.transfer_scale_x = 1.f;
copy.transfer_scale_y = 1.f; copy.transfer_scale_y = 1.f;
copy.target = nullptr; copy.target = nullptr;
@ -661,7 +288,6 @@ namespace rsx
if (prev_surface) if (prev_surface)
{ {
// Append the previous removed surface to the intersection list // Append the previous removed surface to the intersection list
std::pair<u32, surface_type> e = { address, prev_surface };
if constexpr (is_depth_surface) if constexpr (is_depth_surface)
{ {
list2.push_back({ address, prev_surface }); list2.push_back({ address, prev_surface });
@ -873,7 +499,7 @@ namespace rsx
#ifndef INCOMPLETE_SURFACE_CACHE_IMPL #ifndef INCOMPLETE_SURFACE_CACHE_IMPL
// TODO: This can be done better after refactoring // TODO: This can be done better after refactoring
new_surface->write_aa_mode = antialias; new_surface->set_aa_mode(antialias);
// Check if old_surface is 'new' and avoid intersection // Check if old_surface is 'new' and avoid intersection
if (old_surface && old_surface->last_use_tag >= write_tag) if (old_surface && old_surface->last_use_tag >= write_tag)
@ -1005,7 +631,7 @@ namespace rsx
#ifndef INCOMPLETE_SURFACE_CACHE_IMPL #ifndef INCOMPLETE_SURFACE_CACHE_IMPL
// TODO: Forward this to the management functions // TODO: Forward this to the management functions
new_surface->write_aa_mode = antialias; new_surface->set_aa_mode(antialias);
// Check if old_surface is 'new' and avoid intersection // Check if old_surface is 'new' and avoid intersection
if (old_surface && old_surface->last_use_tag >= write_tag) if (old_surface && old_surface->last_use_tag >= write_tag)
@ -1044,8 +670,6 @@ namespace rsx
{ {
u32 clip_width = clip_horizontal_reg; u32 clip_width = clip_horizontal_reg;
u32 clip_height = clip_vertical_reg; u32 clip_height = clip_vertical_reg;
// u32 clip_x = clip_horizontal_reg;
// u32 clip_y = clip_vertical_reg;
cache_tag = rsx::get_shared_tag(); cache_tag = rsx::get_shared_tag();
@ -1267,50 +891,6 @@ namespace rsx
return result; return result;
} }
/**
* Moves a single surface from surface storage to invalidated surface store.
* Can be triggered by the texture cache's blit functionality when formats do not match
*/
void invalidate_single_surface(surface_type surface, bool depth)
{
if (!depth)
{
for (auto It = m_render_targets_storage.begin(); It != m_render_targets_storage.end(); It++)
{
const auto address = It->first;
const auto ref = Traits::get(It->second);
if (surface == ref)
{
Traits::notify_surface_invalidated(It->second);
invalidated_resources.push_back(std::move(It->second));
m_render_targets_storage.erase(It);
cache_tag = rsx::get_shared_tag();
return;
}
}
}
else
{
for (auto It = m_depth_stencil_storage.begin(); It != m_depth_stencil_storage.end(); It++)
{
const auto address = It->first;
const auto ref = Traits::get(It->second);
if (surface == ref)
{
Traits::notify_surface_invalidated(It->second);
invalidated_resources.push_back(std::move(It->second));
m_depth_stencil_storage.erase(It);
cache_tag = rsx::get_shared_tag();
return;
}
}
}
}
/** /**
* Invalidates surface that exists at an address * Invalidates surface that exists at an address
*/ */
@ -1383,10 +963,7 @@ namespace rsx
if (!rsx::pitch_compatible(surface, required_pitch, required_height)) if (!rsx::pitch_compatible(surface, required_pitch, required_height))
continue; continue;
const u16 scale_x = surface->read_aa_mode > rsx::surface_antialiasing::center_1_sample? 2 : 1; const auto texture_size = pitch * surface->get_surface_height(rsx::surface_metrics::samples);
const u16 scale_y = surface->read_aa_mode > rsx::surface_antialiasing::diagonal_centered_2_samples? 2 : 1;
const auto texture_size = pitch * surface->get_surface_height() * scale_y;
if ((this_address + texture_size) <= texaddr) if ((this_address + texture_size) <= texaddr)
continue; continue;
@ -1401,11 +978,8 @@ namespace rsx
info.base_address = this_address; info.base_address = this_address;
info.is_depth = is_depth; info.is_depth = is_depth;
surface_format_info surface_info{}; const auto normalized_surface_width = surface->get_native_pitch() / required_bpp;
Traits::get_surface_info(surface, &surface_info); const auto normalized_surface_height = surface->get_surface_height(rsx::surface_metrics::samples);
const auto normalized_surface_width = (surface_info.surface_width * scale_x * surface_info.bpp) / required_bpp;
const auto normalized_surface_height = surface_info.surface_height * scale_y;
if (LIKELY(this_address >= texaddr)) if (LIKELY(this_address >= texaddr))
{ {
@ -1445,21 +1019,11 @@ namespace rsx
info.is_clipped = (info.width < required_width || info.height < required_height); info.is_clipped = (info.width < required_width || info.height < required_height);
if (UNLIKELY(surface_info.bpp != required_bpp)) if (auto surface_bpp = surface->get_bpp(); UNLIKELY(surface_bpp != required_bpp))
{ {
// Width is calculated in the coordinate-space of the requester; normalize // Width is calculated in the coordinate-space of the requester; normalize
info.src_x = (info.src_x * required_bpp) / surface_info.bpp; info.src_x = (info.src_x * required_bpp) / surface_bpp;
info.width = (info.width * required_bpp) / surface_info.bpp; info.width = (info.width * required_bpp) / surface_bpp;
}
if (UNLIKELY(scale_x > 1))
{
info.src_x /= scale_x;
info.dst_x /= scale_x;
info.width /= scale_x;
info.src_y /= scale_y;
info.dst_y /= scale_y;
info.height /= scale_y;
} }
result.push_back(info); result.push_back(info);

View file

@ -0,0 +1,450 @@
#pragma once
#include "Utilities/types.h"
#include "Utilities/geometry.h"
#include "Utilities/address_range.h"
#include "TextureUtils.h"
#include "../rsx_utils.h"
namespace rsx
{
enum surface_state_flags : u32
{
ready = 0,
erase_bkgnd = 1
};
template <typename surface_type>
struct surface_overlap_info_t
{
surface_type surface = nullptr;
u32 base_address = 0;
bool is_depth = false;
bool is_clipped = false;
u16 src_x = 0;
u16 src_y = 0;
u16 dst_x = 0;
u16 dst_y = 0;
u16 width = 0;
u16 height = 0;
areai get_src_area() const
{
return coordi{ {src_x, src_y}, {width, height} };
}
areai get_dst_area() const
{
return coordi{ {dst_x, dst_y}, {width, height} };
}
};
template <typename surface_type>
struct deferred_clipped_region
{
u16 src_x, src_y, dst_x, dst_y, width, height;
f32 transfer_scale_x, transfer_scale_y;
surface_type target;
surface_type source;
template <typename T>
deferred_clipped_region<T> cast() const
{
deferred_clipped_region<T> ret;
ret.src_x = src_x;
ret.src_y = src_y;
ret.dst_x = dst_x;
ret.dst_y = dst_y;
ret.width = width;
ret.height = height;
ret.transfer_scale_x = transfer_scale_x;
ret.transfer_scale_y = transfer_scale_y;
ret.target = (T)(target);
ret.source = (T)(source);
return ret;
}
operator bool() const
{
return (source != nullptr);
}
template <typename T>
void init_transfer(T target_surface)
{
if (!width)
{
// Perform intersection here
const auto region = rsx::get_transferable_region(target_surface);
width = std::get<0>(region);
height = std::get<1>(region);
transfer_scale_x = f32(std::get<2>(region)) / width;
transfer_scale_y = f32(std::get<3>(region)) / height;
target = target_surface;
}
}
areai src_rect() const
{
verify(HERE), width;
return { src_x, src_y, src_x + width, src_y + height };
}
areai dst_rect() const
{
verify(HERE), width;
return { dst_x, dst_y, dst_x + u16(width * transfer_scale_x + 0.5f), dst_y + u16(height * transfer_scale_y + 0.5f) };
}
};
template <typename image_storage_type>
struct render_target_descriptor
{
u64 last_use_tag = 0; // tag indicating when this block was last confirmed to have been written to
std::array<std::pair<u32, u64>, 5> memory_tag_samples;
// Obsolete, requires updating
deferred_clipped_region<image_storage_type> old_contents{};
// Surface properties
u16 rsx_pitch = 0;
u16 native_pitch = 0;
u16 surface_width = 0;
u16 surface_height = 0;
u8 spp = 1;
u8 samples_x = 1;
u8 samples_y = 1;
flags32_t memory_usage_flags = surface_usage_flags::unknown;
flags32_t state_flags = surface_state_flags::ready;
union
{
rsx::surface_color_format gcm_color_format;
rsx::surface_depth_format gcm_depth_format;
}
format_info;
render_target_descriptor() {}
virtual ~render_target_descriptor()
{
if (old_contents)
{
// Cascade resource derefs
LOG_ERROR(RSX, "Resource was destroyed whilst holding a resource reference!");
}
}
virtual image_storage_type get_surface(rsx::surface_access access_type) = 0;
virtual bool is_depth_surface() const = 0;
virtual void release_ref(image_storage_type) const = 0;
virtual u16 get_surface_width(rsx::surface_metrics metrics = rsx::surface_metrics::pixels) const
{
switch (metrics)
{
case rsx::surface_metrics::samples:
return surface_width * samples_x;
case rsx::surface_metrics::pixels:
return surface_width;
case rsx::surface_metrics::bytes:
return rsx_pitch;
default:
fmt::throw_exception("Unknown surface metric %d", u32(metrics));
}
}
virtual u16 get_surface_height(rsx::surface_metrics metrics = rsx::surface_metrics::pixels) const
{
switch (metrics)
{
case rsx::surface_metrics::samples:
case rsx::surface_metrics::bytes:
return surface_height * samples_y;
case rsx::surface_metrics::pixels:
return surface_height;
default:
fmt::throw_exception("Unknown surface metric %d", u32(metrics));
}
}
virtual u16 get_rsx_pitch() const
{
return rsx_pitch;
}
virtual u16 get_native_pitch() const
{
return native_pitch;
}
u8 get_bpp() const
{
return u8(get_native_pitch() / get_surface_width());
}
u8 get_spp() const
{
return spp;
}
void set_aa_mode(rsx::surface_antialiasing aa)
{
switch (aa)
{
case rsx::surface_antialiasing::center_1_sample:
samples_x = samples_y = spp = 1;
break;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
samples_x = spp = 2;
samples_y = 1;
break;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
samples_x = samples_y = 2;
spp = 4;
break;
default:
fmt::throw_exception("Unknown AA mode 0x%x", (u32)aa);
}
}
void set_format(rsx::surface_color_format format)
{
format_info.gcm_color_format = format;
}
void set_format(rsx::surface_depth_format format)
{
format_info.gcm_depth_format = format;
}
rsx::surface_color_format get_surface_color_format()
{
return format_info.gcm_color_format;
}
rsx::surface_depth_format get_surface_depth_format()
{
return format_info.gcm_depth_format;
}
bool dirty() const
{
return (state_flags != rsx::surface_state_flags::ready) || old_contents;
}
bool test() const
{
if (dirty())
{
// TODO
// Should RCB or mem-sync (inherit previous mem) to init memory
LOG_TODO(RSX, "Resource used before memory initialization");
}
// Tags are tested in an X pattern
for (const auto &tag : memory_tag_samples)
{
if (!tag.first)
break;
if (tag.second != *reinterpret_cast<u64*>(vm::g_sudo_addr + tag.first))
return false;
}
return true;
}
void clear_rw_barrier()
{
release_ref(old_contents.source);
old_contents = {};
}
template<typename T>
void set_old_contents(T* other)
{
verify(HERE), !old_contents;
if (!other || other->get_rsx_pitch() != this->get_rsx_pitch())
{
old_contents = {};
return;
}
old_contents = {};
old_contents.source = other;
other->add_ref();
}
template<typename T>
void set_old_contents_region(const T& region, bool normalized)
{
if (old_contents)
{
// This can happen when doing memory splits
auto old_surface = static_cast<decltype(region.source)>(old_contents.source);
if (old_surface->last_use_tag > region.source->last_use_tag)
{
return;
}
clear_rw_barrier();
}
// NOTE: This method will not perform pitch verification!
verify(HERE), !old_contents, region.source, region.source != this;
old_contents = region.template cast<image_storage_type>();
region.source->add_ref();
// Reverse normalization process if needed
if (normalized)
{
const u16 bytes_to_texels_x = region.source->get_bpp() * region.source->samples_x;
const u16 rows_to_texels_y = region.source->samples_y;
old_contents.src_x /= bytes_to_texels_x;
old_contents.src_y /= rows_to_texels_y;
old_contents.width /= bytes_to_texels_x;
old_contents.height /= rows_to_texels_y;
const u16 bytes_to_texels_x2 = (get_bpp() * samples_x);
const u16 rows_to_texels_y2 = samples_y;
old_contents.dst_x /= bytes_to_texels_x2;
old_contents.dst_y /= rows_to_texels_y2;
old_contents.transfer_scale_x = f32(bytes_to_texels_x) / bytes_to_texels_x2;
old_contents.transfer_scale_y = f32(rows_to_texels_y) / rows_to_texels_y2;
}
// Apply resolution scale if needed
if (g_cfg.video.resolution_scale_percent != 100)
{
auto src_width = rsx::apply_resolution_scale(old_contents.width, true, old_contents.source->width());
auto src_height = rsx::apply_resolution_scale(old_contents.height, true, old_contents.source->height());
auto dst_width = rsx::apply_resolution_scale(old_contents.width, true, old_contents.target->width());
auto dst_height = rsx::apply_resolution_scale(old_contents.height, true, old_contents.target->height());
old_contents.transfer_scale_x *= f32(dst_width) / src_width;
old_contents.transfer_scale_y *= f32(dst_height) / src_height;
old_contents.width = src_width;
old_contents.height = src_height;
old_contents.src_x = rsx::apply_resolution_scale(old_contents.src_x, false, old_contents.source->width());
old_contents.src_y = rsx::apply_resolution_scale(old_contents.src_y, false, old_contents.source->height());
old_contents.dst_x = rsx::apply_resolution_scale(old_contents.dst_x, false, old_contents.target->width());
old_contents.dst_y = rsx::apply_resolution_scale(old_contents.dst_y, false, old_contents.target->height());
}
}
void queue_tag(u32 address)
{
for (unsigned i = 0; i < memory_tag_samples.size(); ++i)
{
if (LIKELY(i))
memory_tag_samples[i].first = 0;
else
memory_tag_samples[i].first = address; // Top left
}
const u32 pitch = get_native_pitch();
if (UNLIKELY(pitch < 16))
{
// Not enough area to gather samples if pitch is too small
return;
}
// Top right corner
memory_tag_samples[1].first = address + pitch - 8;
if (const u32 h = get_surface_height(); h > 1)
{
// Last row
const u32 pitch2 = get_rsx_pitch();
const u32 last_row_offset = pitch2 * (h - 1);
memory_tag_samples[2].first = address + last_row_offset; // Bottom left corner
memory_tag_samples[3].first = address + last_row_offset + pitch - 8; // Bottom right corner
// Centroid
const u32 center_row_offset = pitch2 * (h / 2);
memory_tag_samples[4].first = address + center_row_offset + pitch / 2;
}
}
void sync_tag()
{
for (auto &tag : memory_tag_samples)
{
if (!tag.first)
break;
tag.second = *reinterpret_cast<u64*>(vm::g_sudo_addr + tag.first);
}
}
void on_write(u64 write_tag = 0)
{
if (write_tag)
{
// Update use tag if requested
last_use_tag = write_tag;
}
// Tag unconditionally without introducing new data
sync_tag();
// HACK!! This should be cleared through memory barriers only
state_flags = rsx::surface_state_flags::ready;
if (old_contents.source)
{
clear_rw_barrier();
}
}
// Returns the rect area occupied by this surface expressed as an 8bpp image with no AA
areau get_normalized_memory_area() const
{
const u16 internal_width = get_surface_width(rsx::surface_metrics::bytes);
const u16 internal_height = get_surface_height(rsx::surface_metrics::bytes);
return { 0, 0, internal_width, internal_height };
}
rsx::address_range get_memory_range() const
{
const u32 internal_height = get_surface_height(rsx::surface_metrics::samples);
return rsx::address_range::start_length(memory_tag_samples[0].first, internal_height * get_rsx_pitch());
}
template <typename T>
void transform_samples_to_pixels(area_base<T>& area)
{
if (LIKELY(spp == 1)) return;
area.x1 /= samples_x;
area.x2 /= samples_x;
area.y1 /= samples_y;
area.y2 /= samples_y;
}
template <typename T>
void transform_samples_to_pixels(T& x1, T& x2, T& y1, T& y2)
{
if (LIKELY(spp == 1)) return;
x1 /= samples_x;
x2 /= samples_x;
y1 /= samples_y;
y2 /= samples_y;
}
};
}

View file

@ -1007,80 +1007,6 @@ namespace rsx
} }
} }
/**
* Scaling helpers
* - get_native_dimensions() returns w and h for the native texture given rsx dimensions
* on rsx a 512x512 texture with 4x AA is treated as a 1024x1024 texture for example
* - get_rsx_dimensions() inverse, return rsx w and h given a real texture w and h
* - get_internal_scaling_x/y() returns a scaling factor to be multiplied by 1/size
* when sampling with unnormalized coordinates. tcoords passed to rsx will be in rsx dimensions
*/
template <typename T, typename U>
inline void get_native_dimensions(T &width, T &height, U surface)
{
switch (surface->read_aa_mode)
{
case rsx::surface_antialiasing::center_1_sample:
return;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
width /= 2;
return;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
width /= 2;
height /= 2;
return;
}
}
template <typename T, typename U>
inline void get_rsx_dimensions(T &width, T &height, U surface)
{
switch (surface->read_aa_mode)
{
case rsx::surface_antialiasing::center_1_sample:
return;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
width *= 2;
return;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
width *= 2;
height *= 2;
return;
}
}
template <typename T>
inline f32 get_internal_scaling_x(T surface)
{
switch (surface->read_aa_mode)
{
default:
case rsx::surface_antialiasing::center_1_sample:
return 1.f;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
return 0.5f;
}
}
template <typename T>
inline f32 get_internal_scaling_y(T surface)
{
switch (surface->read_aa_mode)
{
default:
case rsx::surface_antialiasing::center_1_sample:
case rsx::surface_antialiasing::diagonal_centered_2_samples:
return 1.f;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
return 0.5f;
}
}
public: public:
texture_cache() : m_storage(this), m_predictor(this) {} texture_cache() : m_storage(this), m_predictor(this) {}
@ -1700,37 +1626,15 @@ namespace rsx
verify(HERE), dst_y >= slice_begin; verify(HERE), dst_y >= slice_begin;
dst_y = (dst_y - slice_begin); dst_y = (dst_y - slice_begin);
const auto scale_x = 1.f / get_internal_scaling_x(section.surface);
const auto scale_y = 1.f / get_internal_scaling_y(section.surface);
const auto h = std::min(section_end, slice_end) - section.dst_y; const auto h = std::min(section_end, slice_end) - section.dst_y;
auto src_width = rsx::apply_resolution_scale(section.width, true); const auto src_width = rsx::apply_resolution_scale(section.width, true);
auto src_height = rsx::apply_resolution_scale(h, true); const auto src_height = rsx::apply_resolution_scale(h, true);
auto dst_width = u16(src_width * scale_x); const auto dst_width = src_width;
auto dst_height = u16(src_height * scale_y); const auto dst_height = src_height;
if (scale_x > 1.f)
{
// Clipping
const auto limit_x = dst_x + dst_width;
const auto limit_y = dst_x + dst_height;
if (limit_x > slice_w)
{
dst_width = (slice_w - dst_x);
src_width = u16(dst_width / scale_x);
}
if (limit_y > slice_h)
{
dst_height = (slice_h - dst_y);
src_height = u16(dst_height / scale_y);
}
}
surfaces.push_back surfaces.push_back
({ ({
section.surface->get_surface(), section.surface->get_surface(rsx::surface_access::read),
surface_transform::identity, surface_transform::identity,
rsx::apply_resolution_scale(src_x, true), rsx::apply_resolution_scale(src_x, true),
rsx::apply_resolution_scale(src_y, true), rsx::apply_resolution_scale(src_y, true),
@ -1894,23 +1798,19 @@ namespace rsx
return false; return false;
} }
const auto surface_width = texptr->get_surface_width(); const auto surface_width = texptr->get_surface_width(rsx::surface_metrics::samples);
const auto surface_height = texptr->get_surface_height(); const auto surface_height = texptr->get_surface_height(rsx::surface_metrics::samples);
u32 internal_width = tex_width;
u32 internal_height = tex_height;
get_native_dimensions(internal_width, internal_height, texptr);
switch (extended_dimension) switch (extended_dimension)
{ {
case rsx::texture_dimension_extended::texture_dimension_1d: case rsx::texture_dimension_extended::texture_dimension_1d:
return (surface_width >= internal_width); return (surface_width >= tex_width);
case rsx::texture_dimension_extended::texture_dimension_2d: case rsx::texture_dimension_extended::texture_dimension_2d:
return (surface_width >= internal_width && surface_height >= internal_height); return (surface_width >= tex_width && surface_height >= tex_height);
case rsx::texture_dimension_extended::texture_dimension_3d: case rsx::texture_dimension_extended::texture_dimension_3d:
return (surface_width >= internal_width && surface_height >= (internal_height * tex_depth)); return (surface_width >= tex_width && surface_height >= (tex_height * tex_depth));
case rsx::texture_dimension_extended::texture_dimension_cubemap: case rsx::texture_dimension_extended::texture_dimension_cubemap:
return (surface_width == internal_height && surface_width >= internal_width && surface_height >= (internal_height * 6)); return (surface_width == tex_height && surface_width >= tex_width && surface_height >= (tex_height * 6));
} }
return false; return false;
@ -1927,12 +1827,8 @@ namespace rsx
{ {
texptr->read_barrier(cmd); texptr->read_barrier(cmd);
const auto surface_width = texptr->get_surface_width(); const auto surface_width = texptr->get_surface_width(rsx::surface_metrics::samples);
const auto surface_height = texptr->get_surface_height(); const auto surface_height = texptr->get_surface_height(rsx::surface_metrics::samples);
u32 internal_width = tex_width;
u32 internal_height = tex_height;
get_native_dimensions(internal_width, internal_height, texptr);
bool is_depth = texptr->is_depth_surface(); bool is_depth = texptr->is_depth_surface();
const bool force_convert = !render_target_format_is_compatible(texptr, format); const bool force_convert = !render_target_format_is_compatible(texptr, format);
@ -1958,19 +1854,19 @@ namespace rsx
{ {
if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_1d) if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_1d)
{ {
internal_height = 1; tex_height = 1;
} }
if ((surface_is_rop_target && g_cfg.video.strict_rendering_mode) || if ((surface_is_rop_target && g_cfg.video.strict_rendering_mode) ||
internal_width < surface_width || tex_width < surface_width ||
internal_height < surface_height || tex_height < surface_height ||
force_convert) force_convert)
{ {
const auto scaled_w = rsx::apply_resolution_scale(internal_width, true); const auto scaled_w = rsx::apply_resolution_scale(tex_width, true);
const auto scaled_h = rsx::apply_resolution_scale(internal_height, true); const auto scaled_h = rsx::apply_resolution_scale(tex_height, true);
const auto command = surface_is_rop_target ? deferred_request_command::copy_image_dynamic : deferred_request_command::copy_image_static; const auto command = surface_is_rop_target ? deferred_request_command::copy_image_dynamic : deferred_request_command::copy_image_static;
return { texptr->get_surface(), command, texaddr, format, 0, 0, scaled_w, scaled_h, 1, return { texptr->get_surface(rsx::surface_access::read), command, texaddr, format, 0, 0, scaled_w, scaled_h, 1,
texture_upload_context::framebuffer_storage, is_depth, scale_x, scale_y, texture_upload_context::framebuffer_storage, is_depth, scale_x, scale_y,
extended_dimension, decoded_remap }; extended_dimension, decoded_remap };
} }
@ -1984,19 +1880,19 @@ namespace rsx
is_depth, scale_x, scale_y, rsx::texture_dimension_extended::texture_dimension_2d, surface_is_rop_target }; is_depth, scale_x, scale_y, rsx::texture_dimension_extended::texture_dimension_2d, surface_is_rop_target };
} }
const auto scaled_w = rsx::apply_resolution_scale(internal_width, true); const auto scaled_w = rsx::apply_resolution_scale(tex_width, true);
const auto scaled_h = rsx::apply_resolution_scale(internal_height, true); const auto scaled_h = rsx::apply_resolution_scale(tex_height, true);
if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_3d) if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_3d)
{ {
return{ texptr->get_surface(), deferred_request_command::_3d_unwrap, texaddr, format, 0, 0, return{ texptr->get_surface(rsx::surface_access::read), deferred_request_command::_3d_unwrap, texaddr, format, 0, 0,
scaled_w, scaled_h, tex_depth, scaled_w, scaled_h, tex_depth,
texture_upload_context::framebuffer_storage, is_depth, 1.f, 1.f, texture_upload_context::framebuffer_storage, is_depth, 1.f, 1.f,
rsx::texture_dimension_extended::texture_dimension_3d, decoded_remap }; rsx::texture_dimension_extended::texture_dimension_3d, decoded_remap };
} }
verify(HERE), extended_dimension == rsx::texture_dimension_extended::texture_dimension_cubemap; verify(HERE), extended_dimension == rsx::texture_dimension_extended::texture_dimension_cubemap;
return{ texptr->get_surface(), deferred_request_command::cubemap_unwrap, texaddr, format, 0, 0, return{ texptr->get_surface(rsx::surface_access::read), deferred_request_command::cubemap_unwrap, texaddr, format, 0, 0,
scaled_w, scaled_h, 1, scaled_w, scaled_h, 1,
texture_upload_context::framebuffer_storage, is_depth, 1.f, 1.f, texture_upload_context::framebuffer_storage, is_depth, 1.f, 1.f,
rsx::texture_dimension_extended::texture_dimension_cubemap, decoded_remap }; rsx::texture_dimension_extended::texture_dimension_cubemap, decoded_remap };
@ -2218,12 +2114,8 @@ namespace rsx
const auto& last = overlapping_fbos.back(); const auto& last = overlapping_fbos.back();
if (last.src_x == 0 && last.src_y == 0) if (last.src_x == 0 && last.src_y == 0)
{ {
u16 internal_width = tex_width;
u16 internal_height = required_surface_height;
get_native_dimensions(internal_width, internal_height, last.surface);
u16 normalized_width = u16(last.width * last.surface->get_bpp()) / bpp; u16 normalized_width = u16(last.width * last.surface->get_bpp()) / bpp;
if (normalized_width >= internal_width && last.height >= internal_height) if (normalized_width >= tex_width && last.height >= tex_height)
{ {
return process_framebuffer_resource_fast(cmd, last.surface, texaddr, format, tex_width, tex_height, depth, return process_framebuffer_resource_fast(cmd, last.surface, texaddr, format, tex_width, tex_height, depth,
scale_x, scale_y, extended_dimension, tex.remap(), tex.decoded_remap(), false); scale_x, scale_y, extended_dimension, tex.remap(), tex.decoded_remap(), false);
@ -2486,7 +2378,6 @@ namespace rsx
auto _w = u32(It->width * It->surface->get_bpp()) / bpp; auto _w = u32(It->width * It->surface->get_bpp()) / bpp;
auto _h = u32(It->height); auto _h = u32(It->height);
get_rsx_dimensions(_w, _h, It->surface);
if (_w < width) if (_w < width)
{ {
@ -2596,9 +2487,9 @@ namespace rsx
size2i dst_dimensions = { dst.pitch / dst_bpp, dst.height }; size2i dst_dimensions = { dst.pitch / dst_bpp, dst.height };
if (src_is_render_target) if (src_is_render_target)
{ {
if (dst_dimensions.width == src_subres.surface->get_surface_width()) if (dst_dimensions.width == src_subres.surface->get_surface_width(rsx::surface_metrics::samples))
{ {
dst_dimensions.height = std::max(src_subres.surface->get_surface_height(), dst.height); dst_dimensions.height = std::max(src_subres.surface->get_surface_height(rsx::surface_metrics::samples), dst.height);
} }
else if (LIKELY(dst_dimensions.width == 1280 || dst_dimensions.width == 2560)) else if (LIKELY(dst_dimensions.width == 1280 || dst_dimensions.width == 2560))
{ {
@ -2673,11 +2564,11 @@ namespace rsx
// Destination dimensions are relaxed (true) // Destination dimensions are relaxed (true)
dst_area = dst_subres.get_src_area(); dst_area = dst_subres.get_src_area();
dest_texture = dst_subres.surface->get_surface(); dest_texture = dst_subres.surface->get_surface(rsx::surface_access::write);
typeless_info.dst_context = texture_upload_context::framebuffer_storage; typeless_info.dst_context = texture_upload_context::framebuffer_storage;
max_dst_width = (u16)(dst_subres.surface->get_surface_width() * typeless_info.dst_scaling_hint); max_dst_width = (u16)(dst_subres.surface->get_surface_width(rsx::surface_metrics::samples) * typeless_info.dst_scaling_hint);
max_dst_height = dst_subres.surface->get_surface_height(); max_dst_height = dst_subres.surface->get_surface_height(rsx::surface_metrics::samples);
} }
// Check if available target is acceptable // Check if available target is acceptable
@ -2824,7 +2715,7 @@ namespace rsx
else else
{ {
src_area = src_subres.get_src_area(); src_area = src_subres.get_src_area();
vram_texture = src_subres.surface->get_surface(); vram_texture = src_subres.surface->get_surface(rsx::surface_access::read);
typeless_info.src_context = texture_upload_context::framebuffer_storage; typeless_info.src_context = texture_upload_context::framebuffer_storage;
} }
@ -2969,13 +2860,13 @@ namespace rsx
const f32 resolution_scale = rsx::get_resolution_scale(); const f32 resolution_scale = rsx::get_resolution_scale();
if (src_is_render_target) if (src_is_render_target)
{ {
if (src_subres.surface->get_surface_width() > g_cfg.video.min_scalable_dimension) if (src_subres.surface->get_surface_width(rsx::surface_metrics::pixels) > g_cfg.video.min_scalable_dimension)
{ {
src_area.x1 = (u16)(src_area.x1 * resolution_scale); src_area.x1 = (u16)(src_area.x1 * resolution_scale);
src_area.x2 = (u16)(src_area.x2 * resolution_scale); src_area.x2 = (u16)(src_area.x2 * resolution_scale);
} }
if (src_subres.surface->get_surface_height() > g_cfg.video.min_scalable_dimension) if (src_subres.surface->get_surface_height(rsx::surface_metrics::pixels) > g_cfg.video.min_scalable_dimension)
{ {
src_area.y1 = (u16)(src_area.y1 * resolution_scale); src_area.y1 = (u16)(src_area.y1 * resolution_scale);
src_area.y2 = (u16)(src_area.y2 * resolution_scale); src_area.y2 = (u16)(src_area.y2 * resolution_scale);
@ -2984,13 +2875,13 @@ namespace rsx
if (dst_is_render_target) if (dst_is_render_target)
{ {
if (dst_subres.surface->get_surface_width() > g_cfg.video.min_scalable_dimension) if (dst_subres.surface->get_surface_width(rsx::surface_metrics::pixels) > g_cfg.video.min_scalable_dimension)
{ {
dst_area.x1 = (u16)(dst_area.x1 * resolution_scale); dst_area.x1 = (u16)(dst_area.x1 * resolution_scale);
dst_area.x2 = (u16)(dst_area.x2 * resolution_scale); dst_area.x2 = (u16)(dst_area.x2 * resolution_scale);
} }
if (dst_subres.surface->get_surface_height() > g_cfg.video.min_scalable_dimension) if (dst_subres.surface->get_surface_height(rsx::surface_metrics::pixels) > g_cfg.video.min_scalable_dimension)
{ {
dst_area.y1 = (u16)(dst_area.y1 * resolution_scale); dst_area.y1 = (u16)(dst_area.y1 * resolution_scale);
dst_area.y2 = (u16)(dst_area.y2 * resolution_scale); dst_area.y2 = (u16)(dst_area.y2 * resolution_scale);
@ -2998,6 +2889,18 @@ namespace rsx
} }
} }
if (src_is_render_target)
{
// TODO: Specify typeless for high sample counts
src_subres.surface->transform_samples_to_pixels(src_area);
}
if (dst_is_render_target)
{
// TODO: Specify typeless for high sample counts
dst_subres.surface->transform_samples_to_pixels(dst_area);
}
typeless_info.analyse(); typeless_info.analyse();
blitter.scale_image(cmd, vram_texture, dest_texture, src_area, dst_area, interpolate, is_depth_blit, typeless_info); blitter.scale_image(cmd, vram_texture, dest_texture, src_area, dst_area, interpolate, is_depth_blit, typeless_info);

View file

@ -1685,7 +1685,7 @@ void GLGSRender::flip(int buffer, bool emu_flip)
// TODO: Take AA scaling into account // TODO: Take AA scaling into account
LOG_WARNING(RSX, "Selected output image does not satisfy the video configuration. Display buffer resolution=%dx%d, avconf resolution=%dx%d, surface=%dx%d", LOG_WARNING(RSX, "Selected output image does not satisfy the video configuration. Display buffer resolution=%dx%d, avconf resolution=%dx%d, surface=%dx%d",
display_buffers[buffer].width, display_buffers[buffer].height, avconfig ? avconfig->resolution_x : 0, avconfig ? avconfig->resolution_y : 0, display_buffers[buffer].width, display_buffers[buffer].height, avconfig ? avconfig->resolution_x : 0, avconfig ? avconfig->resolution_y : 0,
render_target_texture->get_surface_width(), render_target_texture->get_surface_height()); render_target_texture->get_surface_width(rsx::surface_metrics::pixels), render_target_texture->get_surface_height(rsx::surface_metrics::pixels));
buffer_width = render_target_texture->width(); buffer_width = render_target_texture->width();
buffer_height = render_target_texture->height(); buffer_height = render_target_texture->height();

View file

@ -195,19 +195,6 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
{ {
// Nothing has changed, we're still using the same framebuffer // Nothing has changed, we're still using the same framebuffer
// Update flags to match current // Update flags to match current
for (u32 index = 0; index < 4; index++)
{
if (auto surface = std::get<1>(m_rtts.m_bound_render_targets[index]))
{
surface->write_aa_mode = layout.aa_mode;
}
}
if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil))
{
ds->write_aa_mode = layout.aa_mode;
}
m_draw_fbo->bind(); m_draw_fbo->bind();
set_viewport(); set_viewport();
set_scissor(); set_scissor();
@ -223,9 +210,6 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
layout.color_addresses, layout.zeta_address, layout.color_addresses, layout.zeta_address,
layout.actual_color_pitch, layout.actual_zeta_pitch); layout.actual_color_pitch, layout.actual_zeta_pitch);
bool old_format_found = false;
gl::texture::format old_format;
std::array<GLuint, 4> color_targets; std::array<GLuint, 4> color_targets;
GLuint depth_stencil_target; GLuint depth_stencil_target;
@ -234,17 +218,12 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
const u8 color_bpp = get_format_block_size_in_bytes(layout.color_format); const u8 color_bpp = get_format_block_size_in_bytes(layout.color_format);
const u8 depth_bpp = (layout.depth_format == rsx::surface_depth_format::z16 ? 2 : 4); const u8 depth_bpp = (layout.depth_format == rsx::surface_depth_format::z16 ? 2 : 4);
const auto samples = get_format_sample_count(layout.aa_mode);
for (int i = 0; i < rsx::limits::color_buffers_count; ++i) for (int i = 0; i < rsx::limits::color_buffers_count; ++i)
{ {
if (m_surface_info[i].pitch && g_cfg.video.write_color_buffers) if (m_surface_info[i].pitch && g_cfg.video.write_color_buffers)
{ {
if (!old_format_found)
{
old_format = rsx::internals::surface_color_format_to_gl(m_surface_info[i].color_format).format;
old_format_found = true;
}
const utils::address_range surface_range = m_surface_info[i].get_memory_range(); const utils::address_range surface_range = m_surface_info[i].get_memory_range();
m_gl_texture_cache.set_memory_read_flags(surface_range, rsx::memory_read_flags::flush_once); m_gl_texture_cache.set_memory_read_flags(surface_range, rsx::memory_read_flags::flush_once);
m_gl_texture_cache.flush_if_cache_miss_likely(cmd, surface_range); m_gl_texture_cache.flush_if_cache_miss_likely(cmd, surface_range);
@ -256,10 +235,13 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
color_targets[i] = rtt->id(); color_targets[i] = rtt->id();
verify("Pitch mismatch!" HERE), rtt->get_rsx_pitch() == layout.actual_color_pitch[i]; verify("Pitch mismatch!" HERE), rtt->get_rsx_pitch() == layout.actual_color_pitch[i];
m_surface_info[i] = { layout.color_addresses[i], layout.actual_color_pitch[i], false, layout.color_format, layout.depth_format, layout.width, layout.height, color_bpp }; m_surface_info[i].address = layout.color_addresses[i];
m_surface_info[i].pitch = layout.actual_color_pitch[i];
rtt->tile = find_tile(color_offsets[i], color_locations[i]); m_surface_info[i].width = layout.width;
rtt->write_aa_mode = layout.aa_mode; m_surface_info[i].height = layout.height;
m_surface_info[i].color_format = layout.color_format;
m_surface_info[i].bpp = color_bpp;
m_surface_info[i].samples = samples;
m_gl_texture_cache.notify_surface_changed(m_surface_info[i].get_memory_range(layout.aa_factors)); m_gl_texture_cache.notify_surface_changed(m_surface_info[i].get_memory_range(layout.aa_factors));
} }
else else
@ -285,9 +267,14 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
depth_stencil_target = ds->id(); depth_stencil_target = ds->id();
verify("Pitch mismatch!" HERE), std::get<1>(m_rtts.m_bound_depth_stencil)->get_rsx_pitch() == layout.actual_zeta_pitch; verify("Pitch mismatch!" HERE), std::get<1>(m_rtts.m_bound_depth_stencil)->get_rsx_pitch() == layout.actual_zeta_pitch;
m_depth_surface_info = { layout.zeta_address, layout.actual_zeta_pitch, true, layout.color_format, layout.depth_format, layout.width, layout.height, depth_bpp };
ds->write_aa_mode = layout.aa_mode; m_depth_surface_info.address = layout.zeta_address;
m_depth_surface_info.pitch = layout.actual_zeta_pitch;
m_depth_surface_info.width = layout.width;
m_depth_surface_info.height = layout.height;
m_depth_surface_info.depth_format = layout.depth_format;
m_depth_surface_info.bpp = (layout.depth_format == rsx::surface_depth_format::z16? 2 : 4);
m_depth_surface_info.samples = samples;
m_gl_texture_cache.notify_surface_changed(m_depth_surface_info.get_memory_range(layout.aa_factors)); m_gl_texture_cache.notify_surface_changed(m_depth_surface_info.get_memory_range(layout.aa_factors));
} }
else else
@ -457,7 +444,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
m_gl_texture_cache.lock_memory_region( m_gl_texture_cache.lock_memory_region(
cmd, surface, surface->get_memory_range(), false, cmd, surface, surface->get_memory_range(), false,
surface->get_surface_width(), surface->get_surface_height(), surface->get_rsx_pitch(), surface->get_surface_width(rsx::surface_metrics::pixels), surface->get_surface_height(rsx::surface_metrics::pixels), surface->get_rsx_pitch(),
format, type, swap_bytes); format, type, swap_bytes);
} }
} }

View file

@ -51,11 +51,6 @@ namespace gl
{ {
class render_target : public viewable_image, public rsx::ref_counted, public rsx::render_target_descriptor<texture*> class render_target : public viewable_image, public rsx::ref_counted, public rsx::render_target_descriptor<texture*>
{ {
u32 rsx_pitch = 0;
u16 native_pitch = 0;
u16 surface_height = 0;
u16 surface_width = 0;
u16 surface_pixel_size = 0; u16 surface_pixel_size = 0;
public: public:
@ -69,11 +64,6 @@ namespace gl
native_pitch = pitch; native_pitch = pitch;
} }
u16 get_native_pitch() const override
{
return native_pitch;
}
void set_surface_dimensions(u16 w, u16 h, u16 pitch) void set_surface_dimensions(u16 w, u16 h, u16 pitch)
{ {
surface_width = w; surface_width = w;
@ -91,16 +81,6 @@ namespace gl
return rsx_pitch; return rsx_pitch;
} }
u16 get_surface_width() const override
{
return surface_width;
}
u16 get_surface_height() const override
{
return surface_height;
}
bool is_depth_surface() const override bool is_depth_surface() const override
{ {
switch (get_internal_format()) switch (get_internal_format())
@ -119,8 +99,9 @@ namespace gl
static_cast<gl::render_target*>(t)->release(); static_cast<gl::render_target*>(t)->release();
} }
texture* get_surface() override texture* get_surface(rsx::surface_access access_type) override
{ {
// TODO
return (gl::texture*)this; return (gl::texture*)this;
} }
@ -222,8 +203,8 @@ struct gl_render_target_traits
if (!sink) if (!sink)
{ {
auto internal_format = (GLenum)ref->get_internal_format(); auto internal_format = (GLenum)ref->get_internal_format();
const auto new_w = rsx::apply_resolution_scale(prev.width, true, ref->get_surface_width()); const auto new_w = rsx::apply_resolution_scale(prev.width, true, ref->get_surface_width(rsx::surface_metrics::pixels));
const auto new_h = rsx::apply_resolution_scale(prev.height, true, ref->get_surface_height()); const auto new_h = rsx::apply_resolution_scale(prev.height, true, ref->get_surface_height(rsx::surface_metrics::pixels));
sink = std::make_unique<gl::render_target>(new_w, new_h, internal_format); sink = std::make_unique<gl::render_target>(new_w, new_h, internal_format);
sink->add_ref(); sink->add_ref();
@ -253,18 +234,8 @@ struct gl_render_target_traits
bool is_compatible_surface(const gl::render_target* surface, const gl::render_target* ref, u16 width, u16 height, u8 /*sample_count*/) bool is_compatible_surface(const gl::render_target* surface, const gl::render_target* ref, u16 width, u16 height, u8 /*sample_count*/)
{ {
return (surface->get_internal_format() == ref->get_internal_format() && return (surface->get_internal_format() == ref->get_internal_format() &&
surface->get_surface_width() >= width && surface->get_surface_width(rsx::surface_metrics::pixels) >= width &&
surface->get_surface_height() >= height); surface->get_surface_height(rsx::surface_metrics::pixels) >= height);
}
static
void get_surface_info(gl::render_target *surface, rsx::surface_format_info *info)
{
info->rsx_pitch = surface->get_rsx_pitch();
info->native_pitch = surface->get_native_pitch();
info->surface_width = surface->get_surface_width();
info->surface_height = surface->get_surface_height();
info->bpp = surface->get_bpp();
} }
static void prepare_rtt_for_drawing(gl::command_context&, gl::render_target* rtt) static void prepare_rtt_for_drawing(gl::command_context&, gl::render_target* rtt)
@ -290,7 +261,7 @@ struct gl_render_target_traits
void invalidate_surface_contents(gl::command_context&, gl::render_target *surface, u32 address, size_t pitch) void invalidate_surface_contents(gl::command_context&, gl::render_target *surface, u32 address, size_t pitch)
{ {
surface->set_rsx_pitch((u16)pitch); surface->set_rsx_pitch((u16)pitch);
surface->reset_aa_mode(); surface->set_aa_mode(rsx::surface_antialiasing::center_1_sample);
surface->queue_tag(address); surface->queue_tag(address);
surface->last_use_tag = 0; surface->last_use_tag = 0;
surface->memory_usage_flags = rsx::surface_usage_flags::unknown; surface->memory_usage_flags = rsx::surface_usage_flags::unknown;
@ -310,9 +281,7 @@ struct gl_render_target_traits
static static
void notify_surface_persist(const std::unique_ptr<gl::render_target>& surface) void notify_surface_persist(const std::unique_ptr<gl::render_target>& surface)
{ {}
surface->save_aa_mode();
}
static static
void notify_surface_reused(const std::unique_ptr<gl::render_target>& surface) void notify_surface_reused(const std::unique_ptr<gl::render_target>& surface)

View file

@ -245,18 +245,9 @@ namespace gl
if (context == rsx::texture_upload_context::framebuffer_storage) if (context == rsx::texture_upload_context::framebuffer_storage)
{ {
switch (static_cast<gl::render_target*>(vram_texture)->read_aa_mode) auto surface = gl::as_rtt(vram_texture);
{ real_width *= surface->samples_x;
case rsx::surface_antialiasing::center_1_sample: real_height *= surface->samples_y;
break;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
real_width *= 2;
break;
default:
real_width *= 2;
real_height *= 2;
break;
}
} }
areai src_area = { 0, 0, 0, 0 }; areai src_area = { 0, 0, 0, 0 };
@ -628,9 +619,17 @@ namespace gl
const bool typeless = dst_aspect != slice.src->aspect() || const bool typeless = dst_aspect != slice.src->aspect() ||
!formats_are_bitcast_compatible((GLenum)slice.src->get_internal_format(), (GLenum)dst_image->get_internal_format()); !formats_are_bitcast_compatible((GLenum)slice.src->get_internal_format(), (GLenum)dst_image->get_internal_format());
std::unique_ptr<gl::texture> tmp;
auto src_image = slice.src; auto src_image = slice.src;
auto src_x = slice.src_x; auto src_x = slice.src_x;
std::unique_ptr<gl::texture> tmp; auto src_y = slice.src_y;
auto src_w = slice.src_w;
auto src_h = slice.src_h;
if (auto surface = dynamic_cast<gl::render_target*>(slice.src))
{
surface->transform_samples_to_pixels(src_x, src_y, src_w, src_h);
}
if (UNLIKELY(typeless)) if (UNLIKELY(typeless))
{ {
@ -643,17 +642,17 @@ namespace gl
gl::copy_typeless(src_image, slice.src); gl::copy_typeless(src_image, slice.src);
} }
if (slice.src_w == slice.dst_w && slice.src_h == slice.dst_h) if (src_w == slice.dst_w && src_h == slice.dst_h)
{ {
glCopyImageSubData(src_image->id(), GL_TEXTURE_2D, 0, src_x, slice.src_y, 0, glCopyImageSubData(src_image->id(), GL_TEXTURE_2D, 0, src_x, src_y, 0,
dst_image->id(), (GLenum)dst_image->get_target(), 0, slice.dst_x, slice.dst_y, slice.dst_z, slice.src_w, slice.src_h, 1); dst_image->id(), (GLenum)dst_image->get_target(), 0, slice.dst_x, slice.dst_y, slice.dst_z, src_w, src_h, 1);
} }
else else
{ {
verify(HERE), dst_image->get_target() == gl::texture::target::texture2D; verify(HERE), dst_image->get_target() == gl::texture::target::texture2D;
auto _blitter = gl::g_hw_blitter; auto _blitter = gl::g_hw_blitter;
const areai src_rect = { src_x, slice.src_y, src_x + slice.src_w, slice.src_y + slice.src_h }; const areai src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
const areai dst_rect = { slice.dst_x, slice.dst_y, slice.dst_x + slice.dst_w, slice.dst_y + slice.dst_h }; const areai dst_rect = { slice.dst_x, slice.dst_y, slice.dst_x + slice.dst_w, slice.dst_y + slice.dst_h };
auto _dst = dst_image; auto _dst = dst_image;

View file

@ -1033,6 +1033,7 @@ namespace rsx
const auto aa_mode = rsx::method_registers.surface_antialias(); const auto aa_mode = rsx::method_registers.surface_antialias();
const u32 aa_factor_u = (aa_mode == rsx::surface_antialiasing::center_1_sample) ? 1 : 2; const u32 aa_factor_u = (aa_mode == rsx::surface_antialiasing::center_1_sample) ? 1 : 2;
const u32 aa_factor_v = (aa_mode == rsx::surface_antialiasing::center_1_sample || aa_mode == rsx::surface_antialiasing::diagonal_centered_2_samples) ? 1 : 2; const u32 aa_factor_v = (aa_mode == rsx::surface_antialiasing::center_1_sample || aa_mode == rsx::surface_antialiasing::diagonal_centered_2_samples) ? 1 : 2;
const u8 sample_count = get_format_sample_count(aa_mode);
const auto depth_texel_size = (layout.depth_format == rsx::surface_depth_format::z16 ? 2 : 4) * aa_factor_u; const auto depth_texel_size = (layout.depth_format == rsx::surface_depth_format::z16 ? 2 : 4) * aa_factor_u;
const auto color_texel_size = get_format_block_size_in_bytes(layout.color_format) * aa_factor_u; const auto color_texel_size = get_format_block_size_in_bytes(layout.color_format) * aa_factor_u;
@ -1213,7 +1214,8 @@ namespace rsx
if (layout.color_addresses[i]) if (layout.color_addresses[i])
{ {
if (m_surface_info[i].width != layout.width || if (m_surface_info[i].width != layout.width ||
m_surface_info[i].height != layout.height) m_surface_info[i].height != layout.height ||
m_surface_info[i].samples != sample_count)
{ {
really_changed = true; really_changed = true;
break; break;
@ -1223,7 +1225,8 @@ namespace rsx
if (!really_changed) if (!really_changed)
{ {
if (layout.zeta_address == m_depth_surface_info.address) if (layout.zeta_address == m_depth_surface_info.address &&
sample_count == m_depth_surface_info.samples)
{ {
// Same target is reused // Same target is reused
return layout; return layout;

View file

@ -2725,22 +2725,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
{ {
// Nothing has changed, we're still using the same framebuffer // Nothing has changed, we're still using the same framebuffer
// Update flags to match current // Update flags to match current
set_scissor();
const auto aa_mode = rsx::method_registers.surface_antialias();
for (u32 index = 0; index < 4; index++)
{
if (auto surface = std::get<1>(m_rtts.m_bound_render_targets[index]))
{
surface->write_aa_mode = layout.aa_mode;
}
}
if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil))
{
ds->write_aa_mode = layout.aa_mode;
}
return; return;
} }
@ -2755,6 +2740,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
// Reset framebuffer information // Reset framebuffer information
VkFormat old_format = VK_FORMAT_UNDEFINED; VkFormat old_format = VK_FORMAT_UNDEFINED;
const auto color_bpp = get_format_block_size_in_bytes(layout.color_format); const auto color_bpp = get_format_block_size_in_bytes(layout.color_format);
const auto samples = get_format_sample_count(layout.aa_mode);
for (u8 i = 0; i < rsx::limits::color_buffers_count; ++i) for (u8 i = 0; i < rsx::limits::color_buffers_count; ++i)
{ {
@ -2774,6 +2760,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
m_surface_info[i].height = layout.height; m_surface_info[i].height = layout.height;
m_surface_info[i].color_format = layout.color_format; m_surface_info[i].color_format = layout.color_format;
m_surface_info[i].bpp = color_bpp; m_surface_info[i].bpp = color_bpp;
m_surface_info[i].samples = samples;
} }
//Process depth surface as well //Process depth surface as well
@ -2791,6 +2778,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
m_depth_surface_info.height = layout.height; m_depth_surface_info.height = layout.height;
m_depth_surface_info.depth_format = layout.depth_format; m_depth_surface_info.depth_format = layout.depth_format;
m_depth_surface_info.bpp = (layout.depth_format == rsx::surface_depth_format::z16? 2 : 4); m_depth_surface_info.bpp = (layout.depth_format == rsx::surface_depth_format::z16? 2 : 4);
m_depth_surface_info.samples = samples;
} }
//Bind created rtts as current fbo... //Bind created rtts as current fbo...
@ -2808,7 +2796,6 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
m_surface_info[index].pitch = layout.actual_color_pitch[index]; m_surface_info[index].pitch = layout.actual_color_pitch[index];
verify("Pitch mismatch!" HERE), surface->rsx_pitch == layout.actual_color_pitch[index]; verify("Pitch mismatch!" HERE), surface->rsx_pitch == layout.actual_color_pitch[index];
surface->write_aa_mode = layout.aa_mode;
m_texture_cache.notify_surface_changed(m_surface_info[index].get_memory_range(layout.aa_factors)); m_texture_cache.notify_surface_changed(m_surface_info[index].get_memory_range(layout.aa_factors));
m_draw_buffers.push_back(index); m_draw_buffers.push_back(index);
} }
@ -2823,7 +2810,6 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
m_depth_surface_info.pitch = layout.actual_zeta_pitch; m_depth_surface_info.pitch = layout.actual_zeta_pitch;
verify("Pitch mismatch!" HERE), ds->rsx_pitch == layout.actual_zeta_pitch; verify("Pitch mismatch!" HERE), ds->rsx_pitch == layout.actual_zeta_pitch;
ds->write_aa_mode = layout.aa_mode;
m_texture_cache.notify_surface_changed(m_depth_surface_info.get_memory_range(layout.aa_factors)); m_texture_cache.notify_surface_changed(m_depth_surface_info.get_memory_range(layout.aa_factors));
} }
@ -2895,7 +2881,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
m_texture_cache.lock_memory_region( m_texture_cache.lock_memory_region(
*m_current_command_buffer, surface, surface->get_memory_range(), false, *m_current_command_buffer, surface, surface->get_memory_range(), false,
surface->get_surface_width(), surface->get_surface_height(), surface->get_rsx_pitch(), surface->get_surface_width(rsx::surface_metrics::pixels), surface->get_surface_height(rsx::surface_metrics::pixels), surface->get_rsx_pitch(),
gcm_format, swap_bytes); gcm_format, swap_bytes);
} }
} }
@ -3184,7 +3170,7 @@ void VKGSRender::flip(int buffer, bool emu_flip)
// TODO: Take AA scaling into account // TODO: Take AA scaling into account
LOG_WARNING(RSX, "Selected output image does not satisfy the video configuration. Display buffer resolution=%dx%d, avconf resolution=%dx%d, surface=%dx%d", LOG_WARNING(RSX, "Selected output image does not satisfy the video configuration. Display buffer resolution=%dx%d, avconf resolution=%dx%d, surface=%dx%d",
display_buffers[buffer].width, display_buffers[buffer].height, avconfig? avconfig->resolution_x : 0, avconfig? avconfig->resolution_y : 0, display_buffers[buffer].width, display_buffers[buffer].height, avconfig? avconfig->resolution_x : 0, avconfig? avconfig->resolution_y : 0,
render_target_texture->get_surface_width(), render_target_texture->get_surface_height()); render_target_texture->get_surface_width(rsx::surface_metrics::pixels), render_target_texture->get_surface_height(rsx::surface_metrics::pixels));
buffer_width = render_target_texture->width(); buffer_width = render_target_texture->width();
buffer_height = render_target_texture->height(); buffer_height = render_target_texture->height();

View file

@ -13,41 +13,16 @@ namespace vk
{ {
struct render_target : public viewable_image, public rsx::ref_counted, public rsx::render_target_descriptor<vk::viewable_image*> struct render_target : public viewable_image, public rsx::ref_counted, public rsx::render_target_descriptor<vk::viewable_image*>
{ {
u16 native_pitch = 0;
u16 rsx_pitch = 0;
u16 surface_width = 0;
u16 surface_height = 0;
u64 frame_tag = 0; // frame id when invalidated, 0 if not invalid u64 frame_tag = 0; // frame id when invalidated, 0 if not invalid
using viewable_image::viewable_image; using viewable_image::viewable_image;
vk::viewable_image* get_surface() override vk::viewable_image* get_surface(rsx::surface_access access_type) override
{ {
// TODO
return (vk::viewable_image*)this; return (vk::viewable_image*)this;
} }
u16 get_surface_width() const override
{
return surface_width;
}
u16 get_surface_height() const override
{
return surface_height;
}
u16 get_rsx_pitch() const override
{
return rsx_pitch;
}
u16 get_native_pitch() const override
{
return native_pitch;
}
bool is_depth_surface() const override bool is_depth_surface() const override
{ {
return !!(aspect() & VK_IMAGE_ASPECT_DEPTH_BIT); return !!(aspect() & VK_IMAGE_ASPECT_DEPTH_BIT);
@ -273,8 +248,8 @@ namespace rsx
{ {
if (!sink) if (!sink)
{ {
const auto new_w = rsx::apply_resolution_scale(prev.width, true, ref->get_surface_width()); const auto new_w = rsx::apply_resolution_scale(prev.width, true, ref->get_surface_width(rsx::surface_metrics::pixels));
const auto new_h = rsx::apply_resolution_scale(prev.height, true, ref->get_surface_height()); const auto new_h = rsx::apply_resolution_scale(prev.height, true, ref->get_surface_height(rsx::surface_metrics::pixels));
auto& dev = cmd.get_command_pool().get_owner(); auto& dev = cmd.get_command_pool().get_owner();
sink = std::make_unique<vk::render_target>(dev, dev.get_memory_mapping().device_local, sink = std::make_unique<vk::render_target>(dev, dev.get_memory_mapping().device_local,
@ -282,7 +257,7 @@ namespace rsx
VK_IMAGE_TYPE_2D, VK_IMAGE_TYPE_2D,
ref->format(), ref->format(),
new_w, new_h, 1, 1, 1, new_w, new_h, 1, 1, 1,
VK_SAMPLE_COUNT_1_BIT, (VkSampleCountFlagBits)ref->samples(),
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_OPTIMAL,
ref->info.usage, ref->info.usage,
@ -316,15 +291,6 @@ namespace rsx
surface->get_surface_height() >= height); surface->get_surface_height() >= height);
} }
static void get_surface_info(vk::render_target *surface, rsx::surface_format_info *info)
{
info->rsx_pitch = surface->rsx_pitch;
info->native_pitch = surface->native_pitch;
info->surface_width = surface->get_surface_width();
info->surface_height = surface->get_surface_height();
info->bpp = surface->get_bpp();
}
static void prepare_rtt_for_drawing(vk::command_buffer& cmd, vk::render_target *surface) static void prepare_rtt_for_drawing(vk::command_buffer& cmd, vk::render_target *surface)
{ {
surface->change_layout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); surface->change_layout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
@ -357,7 +323,7 @@ namespace rsx
static void invalidate_surface_contents(vk::command_buffer& /*cmd*/, vk::render_target *surface, u32 address, size_t pitch) static void invalidate_surface_contents(vk::command_buffer& /*cmd*/, vk::render_target *surface, u32 address, size_t pitch)
{ {
surface->rsx_pitch = (u16)pitch; surface->rsx_pitch = (u16)pitch;
surface->reset_aa_mode(); surface->set_aa_mode(rsx::surface_antialiasing::center_1_sample);
surface->queue_tag(address); surface->queue_tag(address);
surface->last_use_tag = 0; surface->last_use_tag = 0;
surface->memory_usage_flags = rsx::surface_usage_flags::unknown; surface->memory_usage_flags = rsx::surface_usage_flags::unknown;
@ -378,9 +344,7 @@ namespace rsx
} }
static void notify_surface_persist(const std::unique_ptr<vk::render_target> &surface) static void notify_surface_persist(const std::unique_ptr<vk::render_target> &surface)
{ {}
surface->save_aa_mode();
}
static void notify_surface_reused(const std::unique_ptr<vk::render_target> &surface) static void notify_surface_reused(const std::unique_ptr<vk::render_target> &surface)
{ {

View file

@ -211,18 +211,9 @@ namespace vk
{ {
if (context == rsx::texture_upload_context::framebuffer_storage) if (context == rsx::texture_upload_context::framebuffer_storage)
{ {
switch (static_cast<vk::render_target*>(vram_texture)->read_aa_mode) auto surface = vk::as_rtt(vram_texture);
{ transfer_width *= surface->samples_x;
case rsx::surface_antialiasing::center_1_sample: transfer_height *= surface->samples_y;
break;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
transfer_width *= 2;
break;
default:
transfer_width *= 2;
transfer_height *= 2;
break;
}
} }
if (transfer_width != vram_texture->width() || transfer_height != vram_texture->height()) if (transfer_width != vram_texture->width() || transfer_height != vram_texture->height())
@ -512,15 +503,25 @@ namespace vk
section.src->push_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); section.src->push_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
auto src_image = section.src; auto src_image = section.src;
auto src_x = section.src_x;
auto src_y = section.src_y;
auto src_w = section.src_w;
auto src_h = section.src_h;
if (auto surface = dynamic_cast<vk::render_target*>(section.src))
{
surface->transform_samples_to_pixels(src_x, src_y, src_w, src_h);
}
if (UNLIKELY(typeless)) if (UNLIKELY(typeless))
{ {
src_image = vk::get_typeless_helper(dst->info.format, section.src_x + section.src_w, section.src_y + section.src_h); src_image = vk::get_typeless_helper(dst->info.format, src_x + src_w, src_y + src_h);
src_image->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); src_image->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
const auto src_bpp = vk::get_format_texel_width(section.src->format()); const auto src_bpp = vk::get_format_texel_width(section.src->format());
const u16 convert_w = u16(section.src_w * dst_bpp) / src_bpp; const u16 convert_w = u16(src_w * dst_bpp) / src_bpp;
const areai src_rect = coordi{{ section.src_x, section.src_y }, { convert_w, section.src_h }}; const areai src_rect = coordi{{ src_x, src_y }, { convert_w, src_h }};
const areai dst_rect = coordi{{ section.src_x, section.src_y }, { section.src_w, section.src_h }}; const areai dst_rect = coordi{{ src_x, src_y }, { src_w, src_h }};
vk::copy_image_typeless(cmd, section.src, src_image, src_rect, dst_rect, 1, section.src->aspect(), dst_aspect); vk::copy_image_typeless(cmd, section.src, src_image, src_rect, dst_rect, 1, section.src->aspect(), dst_aspect);
src_image->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); src_image->change_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
} }
@ -530,14 +531,14 @@ namespace vk
// Final aspect mask of the 'final' transfer source // Final aspect mask of the 'final' transfer source
const auto new_src_aspect = src_image->aspect(); const auto new_src_aspect = src_image->aspect();
if (LIKELY(section.src_w == section.dst_w && section.src_h == section.dst_h && section.xform == surface_transform::identity)) if (LIKELY(src_w == section.dst_w && src_h == section.dst_h && section.xform == surface_transform::identity))
{ {
VkImageCopy copy_rgn; VkImageCopy copy_rgn;
copy_rgn.srcOffset = { section.src_x, section.src_y, 0 }; copy_rgn.srcOffset = { src_x, src_y, 0 };
copy_rgn.dstOffset = { section.dst_x, section.dst_y, 0 }; copy_rgn.dstOffset = { section.dst_x, section.dst_y, 0 };
copy_rgn.dstSubresource = { dst_aspect, 0, 0, 1 }; copy_rgn.dstSubresource = { dst_aspect, 0, 0, 1 };
copy_rgn.srcSubresource = { new_src_aspect, 0, 0, 1 }; copy_rgn.srcSubresource = { new_src_aspect, 0, 0, 1 };
copy_rgn.extent = { section.src_w, section.src_h, 1 }; copy_rgn.extent = { src_w, src_h, 1 };
if (dst->info.imageType == VK_IMAGE_TYPE_3D) if (dst->info.imageType == VK_IMAGE_TYPE_3D)
{ {
@ -572,7 +573,7 @@ namespace vk
if (section.xform == surface_transform::identity) if (section.xform == surface_transform::identity)
{ {
vk::copy_scaled_image(cmd, src_image->value, _dst->value, section.src->current_layout, _dst->current_layout, vk::copy_scaled_image(cmd, src_image->value, _dst->value, section.src->current_layout, _dst->current_layout,
coordi{ { section.src_x, section.src_y }, { section.src_w, section.src_h } }, coordi{ { src_x, src_y }, { src_w, src_h } },
coordi{ { section.dst_x, section.dst_y }, { section.dst_w, section.dst_h } }, coordi{ { section.dst_x, section.dst_y }, { section.dst_w, section.dst_h } },
1, src_image->aspect(), src_image->info.format == _dst->info.format, 1, src_image->aspect(), src_image->info.format == _dst->info.format,
VK_FILTER_NEAREST, src_image->info.format, _dst->info.format); VK_FILTER_NEAREST, src_image->info.format, _dst->info.format);
@ -580,14 +581,14 @@ namespace vk
else if (section.xform == surface_transform::argb_to_bgra) else if (section.xform == surface_transform::argb_to_bgra)
{ {
VkBufferImageCopy copy{}; VkBufferImageCopy copy{};
copy.imageExtent = { section.src_w, section.src_h, 1 }; copy.imageExtent = { src_w, src_h, 1 };
copy.imageOffset = { section.src_x, section.src_y, 0 }; copy.imageOffset = { src_x, src_y, 0 };
copy.imageSubresource = { src_image->aspect(), 0, 0, 1 }; copy.imageSubresource = { src_image->aspect(), 0, 0, 1 };
auto scratch_buf = vk::get_scratch_buffer(); auto scratch_buf = vk::get_scratch_buffer();
vkCmdCopyImageToBuffer(cmd, src_image->value, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, scratch_buf->value, 1, &copy); vkCmdCopyImageToBuffer(cmd, src_image->value, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, scratch_buf->value, 1, &copy);
const auto mem_length = section.src_w * section.src_h * dst_bpp; const auto mem_length = src_w * src_h * dst_bpp;
vk::insert_buffer_memory_barrier(cmd, scratch_buf->value, 0, mem_length, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::insert_buffer_memory_barrier(cmd, scratch_buf->value, 0, mem_length, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
@ -606,16 +607,16 @@ namespace vk
dst_x = 0; dst_x = 0;
dst_y = 0; dst_y = 0;
if (section.src_w != section.dst_w || section.src_h != section.dst_h) if (src_w != section.dst_w || src_h != section.dst_h)
{ {
// Optionally scale if needed // Optionally scale if needed
if (UNLIKELY(tmp == _dst)) if (UNLIKELY(tmp == _dst))
{ {
dst_y = section.src_h; dst_y = src_h;
} }
vk::copy_scaled_image(cmd, tmp->value, _dst->value, tmp->current_layout, _dst->current_layout, vk::copy_scaled_image(cmd, tmp->value, _dst->value, tmp->current_layout, _dst->current_layout,
areai{ 0, 0, section.src_w, (s32)section.src_h }, areai{ 0, 0, src_w, (s32)src_h },
coordi{ { dst_x, dst_y }, { section.dst_w, section.dst_h } }, coordi{ { dst_x, dst_y }, { section.dst_w, section.dst_h } },
1, new_src_aspect, tmp->info.format == _dst->info.format, 1, new_src_aspect, tmp->info.format == _dst->info.format,
VK_FILTER_NEAREST, tmp->info.format, _dst->info.format); VK_FILTER_NEAREST, tmp->info.format, _dst->info.format);

View file

@ -80,23 +80,18 @@ namespace rsx
u32 address = 0; u32 address = 0;
u32 pitch = 0; u32 pitch = 0;
bool is_depth_surface = false;
rsx::surface_color_format color_format; rsx::surface_color_format color_format;
rsx::surface_depth_format depth_format; rsx::surface_depth_format depth_format;
u16 width = 0; u16 width = 0;
u16 height = 0; u16 height = 0;
u8 bpp = 0; u8 bpp = 0;
u8 samples = 0;
address_range range{}; address_range range{};
gcm_framebuffer_info() = default; gcm_framebuffer_info() = default;
gcm_framebuffer_info(const u32 address_, const u32 pitch_, bool is_depth_, const rsx::surface_color_format fmt_, const rsx::surface_depth_format dfmt_, const u16 w, const u16 h, const u8 bpp_)
:address(address_), pitch(pitch_), is_depth_surface(is_depth_), color_format(fmt_), depth_format(dfmt_), width(w), height(h), bpp(bpp_)
{}
void calculate_memory_range(u32 aa_factor_u, u32 aa_factor_v) void calculate_memory_range(u32 aa_factor_u, u32 aa_factor_v)
{ {
// Account for the last line of the block not reaching the end // Account for the last line of the block not reaching the end
@ -587,33 +582,9 @@ namespace rsx
u16 dst_w = src_w; u16 dst_w = src_w;
u16 dst_h = src_h; u16 dst_h = src_h;
switch (static_cast<const SurfaceType*>(surface->old_contents.source)->read_aa_mode) auto src = static_cast<const SurfaceType*>(surface->old_contents.source);
{ dst_w = (dst_w * src->samples_x) / surface->samples_x;
case rsx::surface_antialiasing::center_1_sample: dst_h = (dst_h * src->samples_y) / surface->samples_y;
break;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
dst_w *= 2;
break;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
dst_w *= 2;
dst_h *= 2;
break;
}
switch (surface->write_aa_mode)
{
case rsx::surface_antialiasing::center_1_sample:
break;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
dst_w /= 2;
break;
case rsx::surface_antialiasing::square_centered_4_samples:
case rsx::surface_antialiasing::square_rotated_4_samples:
dst_w /= 2;
dst_h /= 2;
break;
}
const f32 scale_x = (f32)dst_w / src_w; const f32 scale_x = (f32)dst_w / src_w;
const f32 scale_y = (f32)dst_h / src_h; const f32 scale_y = (f32)dst_h / src_h;

View file

@ -547,6 +547,7 @@
<ClInclude Include="Emu\RSX\Capture\rsx_replay.h" /> <ClInclude Include="Emu\RSX\Capture\rsx_replay.h" />
<ClInclude Include="Emu\RSX\Capture\rsx_trace.h" /> <ClInclude Include="Emu\RSX\Capture\rsx_trace.h" />
<ClInclude Include="Emu\RSX\Common\GLSLCommon.h" /> <ClInclude Include="Emu\RSX\Common\GLSLCommon.h" />
<ClInclude Include="Emu\RSX\Common\surface_utils.h" />
<ClInclude Include="Emu\RSX\Common\TextGlyphs.h" /> <ClInclude Include="Emu\RSX\Common\TextGlyphs.h" />
<ClInclude Include="Emu\RSX\Common\texture_cache.h" /> <ClInclude Include="Emu\RSX\Common\texture_cache.h" />
<ClInclude Include="Emu\RSX\Common\texture_cache_checker.h" /> <ClInclude Include="Emu\RSX\Common\texture_cache_checker.h" />
@ -617,4 +618,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

View file

@ -1519,5 +1519,8 @@
<ClInclude Include="Emu\Audio\Null\NullAudioBackend.h"> <ClInclude Include="Emu\Audio\Null\NullAudioBackend.h">
<Filter>Emu\Audio\Null</Filter> <Filter>Emu\Audio\Null</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\RSX\Common\surface_utils.h">
<Filter>Emu\GPU\RSX\Common</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>