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 <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
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];
@ -453,7 +455,7 @@ namespace utils
{
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];
if (!r1.valid())
@ -461,7 +463,7 @@ namespace utils
continue;
}
for (int j = i + 1; j < _size; ++j)
for (size_t j = i + 1; j < _size; ++j)
{
const auto &r2 = data[j];
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
*/

View file

@ -28,6 +28,19 @@ namespace rsx
storage = 2,
};
enum surface_metrics : u32
{
pixels = 0,
samples = 1,
bytes = 2
};
enum surface_access : u32
{
read = 0,
write = 1
};
//Sampled image descriptor
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_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
*/

View file

@ -2,7 +2,7 @@
#include "Utilities/GSL.h"
#include "Emu/Memory/vm.h"
#include "TextureUtils.h"
#include "surface_utils.h"
#include "../GCM.h"
#include "../rsx_utils.h"
#include <list>
@ -25,379 +25,6 @@ namespace rsx
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.
* It handles surface creation and storage. Backend should only retrieve pointer to surface.
@ -435,7 +62,7 @@ namespace rsx
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 row = 0; row < height; row++)
{
for (unsigned col = 0; col < width; col++)
dest[col] = src[col];
@ -548,7 +175,7 @@ namespace rsx
{
// Split in X
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;
copy.src_x = _new.width / bytes_to_texels_x;
@ -576,15 +203,15 @@ namespace rsx
{
// Split in Y
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;
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_y = 0;
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_y = 1.f;
copy.target = nullptr;
@ -661,7 +288,6 @@ namespace rsx
if (prev_surface)
{
// Append the previous removed surface to the intersection list
std::pair<u32, surface_type> e = { address, prev_surface };
if constexpr (is_depth_surface)
{
list2.push_back({ address, prev_surface });
@ -873,7 +499,7 @@ namespace rsx
#ifndef INCOMPLETE_SURFACE_CACHE_IMPL
// 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
if (old_surface && old_surface->last_use_tag >= write_tag)
@ -1005,7 +631,7 @@ namespace rsx
#ifndef INCOMPLETE_SURFACE_CACHE_IMPL
// 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
if (old_surface && old_surface->last_use_tag >= write_tag)
@ -1044,8 +670,6 @@ namespace rsx
{
u32 clip_width = clip_horizontal_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();
@ -1267,50 +891,6 @@ namespace rsx
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
*/
@ -1383,10 +963,7 @@ namespace rsx
if (!rsx::pitch_compatible(surface, required_pitch, required_height))
continue;
const u16 scale_x = surface->read_aa_mode > rsx::surface_antialiasing::center_1_sample? 2 : 1;
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;
const auto texture_size = pitch * surface->get_surface_height(rsx::surface_metrics::samples);
if ((this_address + texture_size) <= texaddr)
continue;
@ -1401,11 +978,8 @@ namespace rsx
info.base_address = this_address;
info.is_depth = is_depth;
surface_format_info surface_info{};
Traits::get_surface_info(surface, &surface_info);
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;
const auto normalized_surface_width = surface->get_native_pitch() / required_bpp;
const auto normalized_surface_height = surface->get_surface_height(rsx::surface_metrics::samples);
if (LIKELY(this_address >= texaddr))
{
@ -1445,21 +1019,11 @@ namespace rsx
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
info.src_x = (info.src_x * required_bpp) / surface_info.bpp;
info.width = (info.width * required_bpp) / surface_info.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;
info.src_x = (info.src_x * required_bpp) / surface_bpp;
info.width = (info.width * required_bpp) / surface_bpp;
}
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:
texture_cache() : m_storage(this), m_predictor(this) {}
@ -1700,37 +1626,15 @@ namespace rsx
verify(HERE), 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;
auto src_width = rsx::apply_resolution_scale(section.width, true);
auto src_height = rsx::apply_resolution_scale(h, true);
auto dst_width = u16(src_width * scale_x);
auto dst_height = u16(src_height * scale_y);
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);
}
}
const auto src_width = rsx::apply_resolution_scale(section.width, true);
const auto src_height = rsx::apply_resolution_scale(h, true);
const auto dst_width = src_width;
const auto dst_height = src_height;
surfaces.push_back
({
section.surface->get_surface(),
section.surface->get_surface(rsx::surface_access::read),
surface_transform::identity,
rsx::apply_resolution_scale(src_x, true),
rsx::apply_resolution_scale(src_y, true),
@ -1894,23 +1798,19 @@ namespace rsx
return false;
}
const auto surface_width = texptr->get_surface_width();
const auto surface_height = texptr->get_surface_height();
u32 internal_width = tex_width;
u32 internal_height = tex_height;
get_native_dimensions(internal_width, internal_height, texptr);
const auto surface_width = texptr->get_surface_width(rsx::surface_metrics::samples);
const auto surface_height = texptr->get_surface_height(rsx::surface_metrics::samples);
switch (extended_dimension)
{
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:
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:
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:
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;
@ -1927,12 +1827,8 @@ namespace rsx
{
texptr->read_barrier(cmd);
const auto surface_width = texptr->get_surface_width();
const auto surface_height = texptr->get_surface_height();
u32 internal_width = tex_width;
u32 internal_height = tex_height;
get_native_dimensions(internal_width, internal_height, texptr);
const auto surface_width = texptr->get_surface_width(rsx::surface_metrics::samples);
const auto surface_height = texptr->get_surface_height(rsx::surface_metrics::samples);
bool is_depth = texptr->is_depth_surface();
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)
{
internal_height = 1;
tex_height = 1;
}
if ((surface_is_rop_target && g_cfg.video.strict_rendering_mode) ||
internal_width < surface_width ||
internal_height < surface_height ||
tex_width < surface_width ||
tex_height < surface_height ||
force_convert)
{
const auto scaled_w = rsx::apply_resolution_scale(internal_width, true);
const auto scaled_h = rsx::apply_resolution_scale(internal_height, true);
const auto scaled_w = rsx::apply_resolution_scale(tex_width, 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;
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,
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 };
}
const auto scaled_w = rsx::apply_resolution_scale(internal_width, true);
const auto scaled_h = rsx::apply_resolution_scale(internal_height, true);
const auto scaled_w = rsx::apply_resolution_scale(tex_width, true);
const auto scaled_h = rsx::apply_resolution_scale(tex_height, true);
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,
texture_upload_context::framebuffer_storage, is_depth, 1.f, 1.f,
rsx::texture_dimension_extended::texture_dimension_3d, decoded_remap };
}
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,
texture_upload_context::framebuffer_storage, is_depth, 1.f, 1.f,
rsx::texture_dimension_extended::texture_dimension_cubemap, decoded_remap };
@ -2218,12 +2114,8 @@ namespace rsx
const auto& last = overlapping_fbos.back();
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;
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,
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 _h = u32(It->height);
get_rsx_dimensions(_w, _h, It->surface);
if (_w < width)
{
@ -2596,9 +2487,9 @@ namespace rsx
size2i dst_dimensions = { dst.pitch / dst_bpp, dst.height };
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))
{
@ -2673,11 +2564,11 @@ namespace rsx
// Destination dimensions are relaxed (true)
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;
max_dst_width = (u16)(dst_subres.surface->get_surface_width() * typeless_info.dst_scaling_hint);
max_dst_height = dst_subres.surface->get_surface_height();
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(rsx::surface_metrics::samples);
}
// Check if available target is acceptable
@ -2824,7 +2715,7 @@ namespace rsx
else
{
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;
}
@ -2969,13 +2860,13 @@ namespace rsx
const f32 resolution_scale = rsx::get_resolution_scale();
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.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.y2 = (u16)(src_area.y2 * resolution_scale);
@ -2984,13 +2875,13 @@ namespace rsx
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.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.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();
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
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,
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_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
// 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();
set_viewport();
set_scissor();
@ -223,9 +210,6 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
layout.color_addresses, layout.zeta_address,
layout.actual_color_pitch, layout.actual_zeta_pitch);
bool old_format_found = false;
gl::texture::format old_format;
std::array<GLuint, 4> color_targets;
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 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)
{
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();
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);
@ -256,10 +235,13 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
color_targets[i] = rtt->id();
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 };
rtt->tile = find_tile(color_offsets[i], color_locations[i]);
rtt->write_aa_mode = layout.aa_mode;
m_surface_info[i].address = layout.color_addresses[i];
m_surface_info[i].pitch = layout.actual_color_pitch[i];
m_surface_info[i].width = layout.width;
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));
}
else
@ -285,9 +267,14 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
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;
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));
}
else
@ -457,7 +444,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
m_gl_texture_cache.lock_memory_region(
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);
}
}

View file

@ -51,11 +51,6 @@ namespace gl
{
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;
public:
@ -69,11 +64,6 @@ namespace gl
native_pitch = pitch;
}
u16 get_native_pitch() const override
{
return native_pitch;
}
void set_surface_dimensions(u16 w, u16 h, u16 pitch)
{
surface_width = w;
@ -91,16 +81,6 @@ namespace gl
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
{
switch (get_internal_format())
@ -119,8 +99,9 @@ namespace gl
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;
}
@ -222,8 +203,8 @@ struct gl_render_target_traits
if (!sink)
{
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_h = rsx::apply_resolution_scale(prev.height, true, ref->get_surface_height());
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(rsx::surface_metrics::pixels));
sink = std::make_unique<gl::render_target>(new_w, new_h, internal_format);
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*/)
{
return (surface->get_internal_format() == ref->get_internal_format() &&
surface->get_surface_width() >= width &&
surface->get_surface_height() >= 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();
surface->get_surface_width(rsx::surface_metrics::pixels) >= width &&
surface->get_surface_height(rsx::surface_metrics::pixels) >= height);
}
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)
{
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->last_use_tag = 0;
surface->memory_usage_flags = rsx::surface_usage_flags::unknown;
@ -310,9 +281,7 @@ struct gl_render_target_traits
static
void notify_surface_persist(const std::unique_ptr<gl::render_target>& surface)
{
surface->save_aa_mode();
}
{}
static
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)
{
switch (static_cast<gl::render_target*>(vram_texture)->read_aa_mode)
{
case rsx::surface_antialiasing::center_1_sample:
break;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
real_width *= 2;
break;
default:
real_width *= 2;
real_height *= 2;
break;
}
auto surface = gl::as_rtt(vram_texture);
real_width *= surface->samples_x;
real_height *= surface->samples_y;
}
areai src_area = { 0, 0, 0, 0 };
@ -628,9 +619,17 @@ namespace gl
const bool typeless = dst_aspect != slice.src->aspect() ||
!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_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))
{
@ -643,17 +642,17 @@ namespace gl
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,
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);
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, src_w, src_h, 1);
}
else
{
verify(HERE), dst_image->get_target() == gl::texture::target::texture2D;
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 };
auto _dst = dst_image;

View file

@ -1033,6 +1033,7 @@ namespace rsx
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_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 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 (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;
break;
@ -1223,7 +1225,8 @@ namespace rsx
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
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
// Update flags to match current
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;
}
set_scissor();
return;
}
@ -2755,6 +2740,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
// Reset framebuffer information
VkFormat old_format = VK_FORMAT_UNDEFINED;
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)
{
@ -2774,6 +2760,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
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;
}
//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.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;
}
//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];
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_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;
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));
}
@ -2895,7 +2881,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
m_texture_cache.lock_memory_region(
*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);
}
}
@ -3184,7 +3170,7 @@ void VKGSRender::flip(int buffer, bool emu_flip)
// 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",
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_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*>
{
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
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;
}
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
{
return !!(aspect() & VK_IMAGE_ASPECT_DEPTH_BIT);
@ -273,8 +248,8 @@ namespace rsx
{
if (!sink)
{
const auto new_w = rsx::apply_resolution_scale(prev.width, true, ref->get_surface_width());
const auto new_h = rsx::apply_resolution_scale(prev.height, true, ref->get_surface_height());
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(rsx::surface_metrics::pixels));
auto& dev = cmd.get_command_pool().get_owner();
sink = std::make_unique<vk::render_target>(dev, dev.get_memory_mapping().device_local,
@ -282,7 +257,7 @@ namespace rsx
VK_IMAGE_TYPE_2D,
ref->format(),
new_w, new_h, 1, 1, 1,
VK_SAMPLE_COUNT_1_BIT,
(VkSampleCountFlagBits)ref->samples(),
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL,
ref->info.usage,
@ -316,15 +291,6 @@ namespace rsx
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)
{
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)
{
surface->rsx_pitch = (u16)pitch;
surface->reset_aa_mode();
surface->set_aa_mode(rsx::surface_antialiasing::center_1_sample);
surface->queue_tag(address);
surface->last_use_tag = 0;
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)
{
surface->save_aa_mode();
}
{}
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)
{
switch (static_cast<vk::render_target*>(vram_texture)->read_aa_mode)
{
case rsx::surface_antialiasing::center_1_sample:
break;
case rsx::surface_antialiasing::diagonal_centered_2_samples:
transfer_width *= 2;
break;
default:
transfer_width *= 2;
transfer_height *= 2;
break;
}
auto surface = vk::as_rtt(vram_texture);
transfer_width *= surface->samples_x;
transfer_height *= surface->samples_y;
}
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);
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))
{
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);
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 areai src_rect = coordi{{ section.src_x, section.src_y }, { convert_w, section.src_h }};
const areai dst_rect = coordi{{ section.src_x, section.src_y }, { section.src_w, section.src_h }};
const u16 convert_w = u16(src_w * dst_bpp) / src_bpp;
const areai src_rect = coordi{{ src_x, src_y }, { convert_w, 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);
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
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;
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.dstSubresource = { dst_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)
{
@ -572,7 +573,7 @@ namespace vk
if (section.xform == surface_transform::identity)
{
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 } },
1, src_image->aspect(), 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)
{
VkBufferImageCopy copy{};
copy.imageExtent = { section.src_w, section.src_h, 1 };
copy.imageOffset = { section.src_x, section.src_y, 0 };
copy.imageExtent = { src_w, src_h, 1 };
copy.imageOffset = { src_x, src_y, 0 };
copy.imageSubresource = { src_image->aspect(), 0, 0, 1 };
auto scratch_buf = vk::get_scratch_buffer();
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_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
@ -606,16 +607,16 @@ namespace vk
dst_x = 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
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,
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 } },
1, new_src_aspect, 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 pitch = 0;
bool is_depth_surface = false;
rsx::surface_color_format color_format;
rsx::surface_depth_format depth_format;
u16 width = 0;
u16 height = 0;
u8 bpp = 0;
u8 samples = 0;
address_range range{};
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)
{
// 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_h = src_h;
switch (static_cast<const SurfaceType*>(surface->old_contents.source)->read_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;
}
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;
}
auto src = static_cast<const SurfaceType*>(surface->old_contents.source);
dst_w = (dst_w * src->samples_x) / surface->samples_x;
dst_h = (dst_h * src->samples_y) / surface->samples_y;
const f32 scale_x = (f32)dst_w / src_w;
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_trace.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\texture_cache.h" />
<ClInclude Include="Emu\RSX\Common\texture_cache_checker.h" />

View file

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