mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-07-10 18:14:42 -06:00
Merge 5a2f0c11e2 into 4003b017f5
This commit is contained in:
commit
4eabcf1b9d
@ -1703,6 +1703,48 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
rsx::surface_color_format get_compatible_surface_color_format(u32 gcm_format)
|
||||
{
|
||||
switch (gcm_format)
|
||||
{
|
||||
case CELL_GCM_TEXTURE_R5G6B5:
|
||||
return rsx::surface_color_format::r5g6b5;
|
||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||
return rsx::surface_color_format::a8r8g8b8;
|
||||
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
|
||||
return rsx::surface_color_format::w16z16y16x16;
|
||||
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT:
|
||||
return rsx::surface_color_format::w32z32y32x32;
|
||||
case CELL_GCM_TEXTURE_A1R5G5B5:
|
||||
return rsx::surface_color_format::x1r5g5b5_o1r5g5b5;
|
||||
case CELL_GCM_TEXTURE_B8:
|
||||
return rsx::surface_color_format::b8;
|
||||
case CELL_GCM_TEXTURE_G8B8:
|
||||
return rsx::surface_color_format::g8b8;
|
||||
case CELL_GCM_TEXTURE_X32_FLOAT:
|
||||
return rsx::surface_color_format::x32;
|
||||
default:
|
||||
fmt::throw_exception("Unhandled surface format 0x%x", gcm_format);
|
||||
}
|
||||
}
|
||||
|
||||
rsx::surface_depth_format2 get_compatible_surface_depth_format(u32 gcm_format)
|
||||
{
|
||||
switch (gcm_format)
|
||||
{
|
||||
case RSX_FORMAT_CLASS_DEPTH16_UNORM:
|
||||
return rsx::surface_depth_format2::z16_uint;
|
||||
case RSX_FORMAT_CLASS_DEPTH24_UNORM_X8_PACK32:
|
||||
return rsx::surface_depth_format2::z24s8_uint;
|
||||
case RSX_FORMAT_CLASS_DEPTH16_FLOAT:
|
||||
return rsx::surface_depth_format2::z16_float;
|
||||
case RSX_FORMAT_CLASS_DEPTH24_FLOAT_X8_PACK32:
|
||||
return rsx::surface_depth_format2::z24s8_float;
|
||||
default:
|
||||
fmt::throw_exception("Invalid depth format 0x%x", gcm_format);
|
||||
}
|
||||
}
|
||||
|
||||
u32 get_max_depth_value(rsx::surface_depth_format2 format)
|
||||
{
|
||||
return get_format_block_size_in_bytes(format) == 2 ? 0xFFFF : 0xFFFFFF;
|
||||
|
||||
@ -284,6 +284,21 @@ namespace rsx
|
||||
usz alignment;
|
||||
};
|
||||
|
||||
struct image_section_attributes_t
|
||||
{
|
||||
u32 address;
|
||||
u32 gcm_format;
|
||||
u32 pitch;
|
||||
u16 width;
|
||||
u16 height;
|
||||
u16 depth;
|
||||
u16 mipmaps;
|
||||
u16 slice_h;
|
||||
u8 bpp;
|
||||
bool swizzled;
|
||||
bool edge_clamped;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get size to store texture in a linear fashion.
|
||||
* Storage is assumed to use a rowPitchAlignment boundary for every row of texture.
|
||||
@ -350,6 +365,9 @@ namespace rsx
|
||||
std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_color_format format);
|
||||
std::pair<u32, bool> get_compatible_gcm_format(rsx::surface_depth_format2 format);
|
||||
|
||||
rsx::surface_color_format get_compatible_surface_color_format(u32 gcm_format);
|
||||
rsx::surface_depth_format2 get_compatible_surface_depth_format(u32 gcm_format);
|
||||
|
||||
format_class classify_format(rsx::surface_depth_format2 format);
|
||||
format_class classify_format(u32 gcm_format);
|
||||
|
||||
|
||||
@ -532,7 +532,7 @@ namespace rsx
|
||||
if (!new_surface)
|
||||
{
|
||||
ensure(store);
|
||||
new_surface_storage = Traits::create_new_surface(address, format, width, height, pitch, antialias, scaling_config, std::forward<Args>(extra_params)...);
|
||||
new_surface_storage = Traits::create_new_surface(command_list, address, format, width, height, pitch, antialias, scaling_config, std::forward<Args>(extra_params)...);
|
||||
new_surface = Traits::get(new_surface_storage);
|
||||
Traits::prepare_surface_for_drawing(command_list, new_surface);
|
||||
allocate_rsx_memory(new_surface);
|
||||
@ -1027,6 +1027,83 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare a render target surface for drawing without binding it to the current RTV/DSV set.
|
||||
// Useful for transfer operations to ensure watertight writes.
|
||||
template <typename ...Args>
|
||||
void prepare_transfer_target(
|
||||
command_list_type command_list,
|
||||
surface_type surface,
|
||||
rsx::surface_access access,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
// We need to reintersect the surface against the surface hierarchy tree to avoid data loss
|
||||
if (!surface->is_depth_surface()) [[ likely ]]
|
||||
{
|
||||
bind_address_as_render_targets(
|
||||
command_list,
|
||||
surface->base_addr,
|
||||
surface->format_info.gcm_color_format,
|
||||
surface->get_aa_mode(),
|
||||
surface->get_surface_width(),
|
||||
surface->get_surface_height(),
|
||||
surface->get_rsx_pitch(),
|
||||
surface->get_resolution_scaling_config(),
|
||||
std::forward<Args>(extra_params)...);
|
||||
}
|
||||
else
|
||||
{
|
||||
bind_address_as_depth_stencil(
|
||||
command_list,
|
||||
surface->base_addr,
|
||||
surface->format_info.gcm_depth_format,
|
||||
surface->get_aa_mode(),
|
||||
surface->get_surface_width(),
|
||||
surface->get_surface_height(),
|
||||
surface->get_rsx_pitch(),
|
||||
surface->get_resolution_scaling_config(),
|
||||
std::forward<Args>(extra_params)...);
|
||||
}
|
||||
|
||||
ensure(access.is_transfer());
|
||||
surface->memory_barrier(command_list, access);
|
||||
}
|
||||
|
||||
// Create surface on-demand from an RSX image description
|
||||
template <typename ...Args>
|
||||
surface_type create_surface_from_rsx_section(
|
||||
command_list_type command_list,
|
||||
const rsx::image_section_attributes_t& attributes,
|
||||
const rsx::surface_scaling_config_t& scaling_config,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
cache_tag = rsx::get_shared_tag();
|
||||
|
||||
if (rsx::classify_format(attributes.gcm_format) == RSX_FORMAT_CLASS_COLOR)
|
||||
{
|
||||
return bind_address_as_render_targets(
|
||||
command_list,
|
||||
attributes.address,
|
||||
rsx::get_compatible_surface_color_format(attributes.gcm_format),
|
||||
rsx::surface_antialiasing::center_1_sample,
|
||||
attributes.width,
|
||||
attributes.height,
|
||||
attributes.pitch,
|
||||
scaling_config,
|
||||
std::forward<Args>(extra_params)...);
|
||||
}
|
||||
|
||||
return bind_address_as_depth_stencil(
|
||||
command_list,
|
||||
attributes.address,
|
||||
rsx::get_compatible_surface_depth_format(attributes.gcm_format),
|
||||
rsx::surface_antialiasing::center_1_sample,
|
||||
attributes.width,
|
||||
attributes.height,
|
||||
attributes.pitch,
|
||||
{},
|
||||
std::forward<Args>(extra_params)...);
|
||||
}
|
||||
|
||||
u8 get_color_surface_count() const
|
||||
{
|
||||
return static_cast<u8>(m_bound_render_target_ids.size());
|
||||
|
||||
@ -12,10 +12,11 @@ namespace rsx
|
||||
{
|
||||
enum surface_state_flags : u32
|
||||
{
|
||||
ready = 0,
|
||||
erase_bkgnd = 1,
|
||||
require_resolve = 2,
|
||||
require_unresolve = 4
|
||||
ready = 0x00,
|
||||
erase_bkgnd = 0x01,
|
||||
require_resolve = 0x02,
|
||||
require_unresolve = 0x04,
|
||||
force_data_load = 0x08
|
||||
};
|
||||
|
||||
enum class surface_sample_layout : u32
|
||||
@ -146,6 +147,9 @@ namespace rsx
|
||||
u8 samples_x = 1;
|
||||
u8 samples_y = 1;
|
||||
|
||||
// AA mode
|
||||
rsx::surface_antialiasing aa_mode = rsx::surface_antialiasing::center_1_sample;
|
||||
|
||||
// Scaling configuration
|
||||
surface_scaling_config_t resolution_scaling_config;
|
||||
|
||||
@ -257,6 +261,8 @@ namespace rsx
|
||||
|
||||
void set_aa_mode(rsx::surface_antialiasing aa)
|
||||
{
|
||||
aa_mode = aa;
|
||||
|
||||
switch (aa)
|
||||
{
|
||||
case rsx::surface_antialiasing::center_1_sample:
|
||||
@ -276,6 +282,11 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
rsx::surface_antialiasing get_aa_mode() const
|
||||
{
|
||||
return aa_mode;
|
||||
}
|
||||
|
||||
void set_spp(u8 count)
|
||||
{
|
||||
switch (count)
|
||||
|
||||
@ -1,12 +1,19 @@
|
||||
#include "stdafx.h"
|
||||
#include "texture_cache_utils.h"
|
||||
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
#include "Utilities/address_range.h"
|
||||
#include "util/fnv_hash.hpp"
|
||||
|
||||
#include "texture_cache_utils.h"
|
||||
#include "texture_cache_helpers.h"
|
||||
#include "texture_cache_blit_helpers.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
constexpr u32 min_lockable_data_size = 4096; // Increasing this value has worse results even on systems with pages > 4k
|
||||
|
||||
namespace helpers = rsx::texture_cache_helpers;
|
||||
|
||||
void buffered_section::init_lockable_range(const address_range32& range)
|
||||
{
|
||||
locked_range = range.to_page_range();
|
||||
@ -215,4 +222,292 @@ namespace rsx
|
||||
|
||||
return (fast_hash_internal() == mem_hash);
|
||||
}
|
||||
|
||||
namespace blit_engine_helpers
|
||||
{
|
||||
// Applies reverse-scan subpixel correction and computes the mirror/flip adjustments for the source.
|
||||
void apply_pixel_transforms(
|
||||
rsx::blit_src_info& src,
|
||||
const rsx::blit_dst_info& dst,
|
||||
typeless_xfer& typeless_info,
|
||||
u32& src_address,
|
||||
u16& src_w,
|
||||
u16& src_h,
|
||||
u8 src_bpp)
|
||||
{
|
||||
if (true) // This block is a debug/sanity check and should be optionally disabled with a config option
|
||||
{
|
||||
// Do subpixel correction in the special case of reverse scanning
|
||||
// When reverse scanning, pixel0 is at offset = (dimension - 1)
|
||||
if (dst.scale_y < 0.f && src.offset_y)
|
||||
{
|
||||
if (src.offset_y = (src.height - src.offset_y);
|
||||
src.offset_y == 1)
|
||||
{
|
||||
src.offset_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dst.scale_x < 0.f && src.offset_x)
|
||||
{
|
||||
if (src.offset_x = (src.width - src.offset_x);
|
||||
src.offset_x == 1)
|
||||
{
|
||||
src.offset_x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((src_h + src.offset_y) > src.height) [[unlikely]]
|
||||
{
|
||||
// TODO: Special case that needs wrapping around (custom blit)
|
||||
rsx_log.error("Transfer cropped in Y, src_h=%d, offset_y=%d, block_h=%d", src_h, src.offset_y, src.height);
|
||||
src_h = src.height - src.offset_y;
|
||||
}
|
||||
|
||||
if ((src_w + src.offset_x) > src.width) [[unlikely]]
|
||||
{
|
||||
// TODO: Special case that needs wrapping around (custom blit)
|
||||
rsx_log.error("Transfer cropped in X, src_w=%d, offset_x=%d, block_w=%d", src_w, src.offset_x, src.width);
|
||||
src_w = src.width - src.offset_x;
|
||||
}
|
||||
}
|
||||
|
||||
if (dst.scale_y < 0.f)
|
||||
{
|
||||
typeless_info.flip_vertical = true;
|
||||
src_address -= (src.pitch * (src_h - 1));
|
||||
}
|
||||
|
||||
if (dst.scale_x < 0.f)
|
||||
{
|
||||
typeless_info.flip_horizontal = true;
|
||||
src_address += (src.width - src_w) * src_bpp;
|
||||
}
|
||||
}
|
||||
|
||||
// Given a surface's actual bpp, decide whether the blit side must be typeless and pick its format.
|
||||
void configure_typeless_format(
|
||||
/*out*/ bool& is_typeless,
|
||||
/*out*/ f32& scaling_hint,
|
||||
/*out*/ u32& gcm_format,
|
||||
u8 surface_bpp,
|
||||
u8 blit_bpp,
|
||||
bool is_argb8,
|
||||
bool surface_is_depth,
|
||||
bool is_format_convert)
|
||||
{
|
||||
const bool typeless = (surface_bpp != blit_bpp || is_format_convert);
|
||||
|
||||
if (!typeless) [[likely]]
|
||||
{
|
||||
// Use format as-is
|
||||
gcm_format = helpers::get_sized_blit_format(is_argb8, surface_is_depth, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Enable type scaling
|
||||
is_typeless = true;
|
||||
scaling_hint = static_cast<f32>(surface_bpp) / blit_bpp;
|
||||
gcm_format = helpers::get_sized_blit_format(is_argb8, false, is_format_convert);
|
||||
}
|
||||
}
|
||||
|
||||
// Whether a cached surface's format is an acceptable source for a blit.
|
||||
// Only accept 16-bit data for 16-bit transfers and 32-bit for 32-bit transfers.
|
||||
// NOTE: some formats are copy-compatible but not scaling-compatible (hence the is_copy_op / dst_is_render_target checks).
|
||||
bool is_blit_source_format_compatible(u32 gcm_format, bool src_is_argb8, bool is_copy_op, bool dst_is_render_target)
|
||||
{
|
||||
switch (gcm_format)
|
||||
{
|
||||
case CELL_GCM_TEXTURE_X32_FLOAT:
|
||||
case CELL_GCM_TEXTURE_Y16_X16:
|
||||
case CELL_GCM_TEXTURE_Y16_X16_FLOAT:
|
||||
// Should be copy compatible but not scaling compatible
|
||||
return src_is_argb8 && (is_copy_op || dst_is_render_target);
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT:
|
||||
// Should be copy compatible but not scaling compatible
|
||||
return src_is_argb8 && (is_copy_op || !dst_is_render_target);
|
||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||
case CELL_GCM_TEXTURE_D8R8G8B8:
|
||||
// Perfect match
|
||||
return src_is_argb8;
|
||||
case CELL_GCM_TEXTURE_X16:
|
||||
case CELL_GCM_TEXTURE_G8B8:
|
||||
case CELL_GCM_TEXTURE_A1R5G5B5:
|
||||
case CELL_GCM_TEXTURE_A4R4G4B4:
|
||||
case CELL_GCM_TEXTURE_D1R5G5B5:
|
||||
case CELL_GCM_TEXTURE_R5G5B5A1:
|
||||
// Copy compatible
|
||||
return !src_is_argb8 && (is_copy_op || dst_is_render_target);
|
||||
case CELL_GCM_TEXTURE_DEPTH16:
|
||||
case CELL_GCM_TEXTURE_DEPTH16_FLOAT:
|
||||
// Copy compatible
|
||||
return !src_is_argb8 && (is_copy_op || !dst_is_render_target);
|
||||
case CELL_GCM_TEXTURE_R5G6B5:
|
||||
// Perfect match
|
||||
return !src_is_argb8;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Decides whether a transfer into main memory should run on the GPU or fall back to a CPU memcpy.
|
||||
// Pure heuristic: the caller applies the returned effects (early-out, rtt discard, collision handling).
|
||||
transfer_configuration configure_transfer_mode(
|
||||
const rsx::blit_src_info& src,
|
||||
const rsx::blit_dst_info& dst,
|
||||
bool dst_is_render_target,
|
||||
bool is_copy_op,
|
||||
bool is_format_convert,
|
||||
bool dst_is_tiled,
|
||||
bool src_is_tiled,
|
||||
u16 src_w,
|
||||
u16 src_h,
|
||||
u16 dst_w,
|
||||
u16 dst_h,
|
||||
u32 dst_address)
|
||||
{
|
||||
transfer_configuration config{};
|
||||
|
||||
// Determine whether to perform this transfer on CPU or GPU (src data may not be graphical)
|
||||
const bool is_trivial_copy = is_copy_op && !is_format_convert && !dst.swizzled && !dst_is_tiled && !src_is_tiled;
|
||||
const bool is_block_transfer = (dst_w == src_w && dst_h == src_h && (src.pitch == dst.pitch || src_h == 1));
|
||||
const bool is_mirror_op = (dst.scale_x < 0.f || dst.scale_y < 0.f);
|
||||
|
||||
// Always use GPU blit if src or dst is in the surface store
|
||||
if (dst_is_render_target)
|
||||
{
|
||||
if (is_trivial_copy && src_h == 1)
|
||||
{
|
||||
dst_is_render_target = false;
|
||||
config.discard_dst_render_target = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_trivial_copy)
|
||||
{
|
||||
// Check if trivial memcpy can perform the same task
|
||||
// Used to copy programs and arbitrary data to the GPU in some cases
|
||||
// NOTE: This case overrides the GPU texture scaling option
|
||||
if (is_block_transfer && !is_mirror_op)
|
||||
{
|
||||
config.fall_back_to_cpu = true;
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_cfg.video.use_gpu_texture_scaling && !dst_is_tiled && !src_is_tiled)
|
||||
{
|
||||
if (dst.swizzled)
|
||||
{
|
||||
// Swizzle operation requested. Use fallback
|
||||
config.fall_back_to_cpu = true;
|
||||
return config;
|
||||
}
|
||||
|
||||
if (is_trivial_copy && get_location(dst_address) != CELL_GCM_LOCATION_LOCAL)
|
||||
{
|
||||
// Trivial copy and the destination is in XDR memory
|
||||
config.fall_back_to_cpu = true;
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// Verifies that the memory range defined by [base_address, write_end] actually exists in VM
|
||||
// The heurestic-defined block_end input is speculative. e.g We may be rendering to one corner of a larger image.
|
||||
// Returns true if we can use the entire range, false if we can only use the [base_address, write_end] area
|
||||
bool validate_memory_range(u32 base_address, u32 write_end, u32 block_end)
|
||||
{
|
||||
if (block_end <= write_end)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Confirm if the pages actually exist in vm
|
||||
if (get_location(base_address) == CELL_GCM_LOCATION_LOCAL)
|
||||
{
|
||||
const auto vram_end = rsx::get_current_renderer()->local_mem_size + rsx::constants::local_mem_base;
|
||||
return block_end <= vram_end;
|
||||
}
|
||||
|
||||
// Main memory block validation
|
||||
return vm::check_addr(write_end, vm::page_readable, (block_end - write_end));
|
||||
}
|
||||
|
||||
// Reverse projects output clip rect back onto the source input.
|
||||
// This cuts out a post-transfer clip operation at the cost of possible edge bleed.
|
||||
void reproject_clip_offsets(
|
||||
rsx::blit_dst_info& dst_info,
|
||||
areai& src_area,
|
||||
u16 max_dst_width,
|
||||
u16 max_dst_height,
|
||||
f32 scale_x,
|
||||
f32 scale_y,
|
||||
const typeless_xfer& typeless_info)
|
||||
{
|
||||
// Validate clipping region
|
||||
if ((dst_info.offset_x + dst_info.clip_x + dst_info.clip_width) > max_dst_width) dst_info.clip_x = 0;
|
||||
if ((dst_info.offset_y + dst_info.clip_y + dst_info.clip_height) > max_dst_height) dst_info.clip_y = 0;
|
||||
|
||||
// Reproject clip offsets onto source to simplify blit
|
||||
if (dst_info.clip_x || dst_info.clip_y)
|
||||
{
|
||||
const u16 scaled_clip_offset_x = static_cast<u16>(dst_info.clip_x / (scale_x * typeless_info.src_scaling_hint));
|
||||
const u16 scaled_clip_offset_y = static_cast<u16>(dst_info.clip_y / scale_y);
|
||||
|
||||
src_area.x1 += scaled_clip_offset_x;
|
||||
src_area.x2 += scaled_clip_offset_x;
|
||||
src_area.y1 += scaled_clip_offset_y;
|
||||
src_area.y2 += scaled_clip_offset_y;
|
||||
}
|
||||
}
|
||||
|
||||
// Reconcile cross-aspect transfers. Transfers cannot go across aspects due to API limitations.
|
||||
void reconcile_depth_color_typeless(
|
||||
typeless_xfer& typeless_info,
|
||||
bool src_is_argb8,
|
||||
bool dst_is_argb8)
|
||||
{
|
||||
if (typeless_info.src_gcm_format == typeless_info.dst_gcm_format) [[ likely ]]
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto src_is_depth = texture_cache_helpers::is_gcm_depth_format(typeless_info.src_gcm_format);
|
||||
const auto dst_is_depth = helpers::is_gcm_depth_format(typeless_info.dst_gcm_format);
|
||||
|
||||
if (src_is_depth == dst_is_depth)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Make the depth side typeless because the other side is guaranteed to be color
|
||||
if (src_is_depth)
|
||||
{
|
||||
// SRC is depth, transfer must be done typelessly
|
||||
if (!typeless_info.src_is_typeless)
|
||||
{
|
||||
typeless_info.src_is_typeless = true;
|
||||
typeless_info.src_gcm_format = helpers::get_sized_blit_format(src_is_argb8, false, false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// DST is depth, transfer must be done typelessly
|
||||
if (!typeless_info.dst_is_typeless)
|
||||
{
|
||||
typeless_info.dst_is_typeless = true;
|
||||
typeless_info.dst_gcm_format = helpers::get_sized_blit_format(dst_is_argb8, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
80
rpcs3/Emu/RSX/Common/texture_cache_blit_helpers.h
Normal file
80
rpcs3/Emu/RSX/Common/texture_cache_blit_helpers.h
Normal file
@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include "texture_cache_utils.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace blit_engine_helpers
|
||||
{
|
||||
// Result of the CPU-vs-GPU transfer heuristic for a main-memory destination.
|
||||
struct transfer_configuration
|
||||
{
|
||||
bool fall_back_to_cpu = false; // Abort the GPU path and let the caller memcpy instead
|
||||
bool discard_dst_render_target = false; // dst was a render target but should be treated as plain memory
|
||||
};
|
||||
|
||||
// Applies reverse-scan subpixel correction and computes the mirror/flip adjustments for the source.
|
||||
void apply_pixel_transforms(
|
||||
rsx::blit_src_info& src,
|
||||
const rsx::blit_dst_info& dst,
|
||||
typeless_xfer& typeless_info,
|
||||
u32& src_address,
|
||||
u16& src_w,
|
||||
u16& src_h,
|
||||
u8 src_bpp);
|
||||
|
||||
// Given a surface's actual bpp, decide whether the blit side must be typeless and pick its format.
|
||||
void configure_typeless_format(
|
||||
/*out*/ bool& is_typeless,
|
||||
/*out*/ f32& scaling_hint,
|
||||
/*out*/ u32& gcm_format,
|
||||
u8 surface_bpp,
|
||||
u8 blit_bpp,
|
||||
bool is_argb8,
|
||||
bool surface_is_depth,
|
||||
bool is_format_convert);
|
||||
|
||||
// Whether a cached surface's format is an acceptable source for a blit.
|
||||
// Only accept 16-bit data for 16-bit transfers and 32-bit for 32-bit transfers.
|
||||
// NOTE: some formats are copy-compatible but not scaling-compatible (hence the is_copy_op / dst_is_render_target checks).
|
||||
bool is_blit_source_format_compatible(u32 gcm_format, bool src_is_argb8, bool is_copy_op, bool dst_is_render_target);
|
||||
|
||||
// Decides whether a transfer into main memory should run on the GPU or fall back to a CPU memcpy.
|
||||
// Pure heuristic: the caller applies the returned effects (early-out, rtt discard, collision handling).
|
||||
transfer_configuration configure_transfer_mode(
|
||||
const rsx::blit_src_info& src,
|
||||
const rsx::blit_dst_info& dst,
|
||||
bool dst_is_render_target,
|
||||
bool is_copy_op,
|
||||
bool is_format_convert,
|
||||
bool dst_is_tiled,
|
||||
bool src_is_tiled,
|
||||
u16 src_w,
|
||||
u16 src_h,
|
||||
u16 dst_w,
|
||||
u16 dst_h,
|
||||
u32 dst_address);
|
||||
|
||||
// Verifies that the memory range defined by [base_address, write_end] actually exists in VM
|
||||
// The heurestic-defined block_end input is speculative. e.g We may be rendering to one corner of a larger image.
|
||||
// Returns true if we can use the entire range, false if we can only use the [base_address, write_end] area
|
||||
bool validate_memory_range(u32 base_address, u32 write_end, u32 block_end);
|
||||
|
||||
// Reverse projects output clip rect back onto the source input.
|
||||
// This cuts out a post-transfer clip operation at the cost of possible edge bleed.
|
||||
void reproject_clip_offsets(
|
||||
rsx::blit_dst_info& dst_info,
|
||||
areai& src_area,
|
||||
u16 max_dst_width,
|
||||
u16 max_dst_height,
|
||||
f32 scale_x,
|
||||
f32 scale_y,
|
||||
const typeless_xfer& typeless_info);
|
||||
|
||||
// Reconcile cross-aspect transfers. Transfers cannot go across aspects due to API limitations.
|
||||
void reconcile_depth_color_typeless(
|
||||
typeless_xfer& typeless_info,
|
||||
bool src_is_argb8,
|
||||
bool dst_is_argb8);
|
||||
}
|
||||
}
|
||||
@ -46,21 +46,6 @@ namespace rsx
|
||||
blit_image_static, // Variant of the copy command that does scaling instead of copying
|
||||
};
|
||||
|
||||
struct image_section_attributes_t
|
||||
{
|
||||
u32 address;
|
||||
u32 gcm_format;
|
||||
u32 pitch;
|
||||
u16 width;
|
||||
u16 height;
|
||||
u16 depth;
|
||||
u16 mipmaps;
|
||||
u16 slice_h;
|
||||
u8 bpp;
|
||||
bool swizzled;
|
||||
bool edge_clamped;
|
||||
};
|
||||
|
||||
struct blit_op_result
|
||||
{
|
||||
bool succeeded = false;
|
||||
|
||||
@ -325,10 +325,6 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool /*
|
||||
|
||||
if (!m_rtts.orphaned_surfaces.empty())
|
||||
{
|
||||
gl::texture::format format;
|
||||
gl::texture::type type;
|
||||
bool swap_bytes;
|
||||
|
||||
for (auto& [base_addr, surface] : m_rtts.orphaned_surfaces)
|
||||
{
|
||||
bool lock = surface->is_depth_surface() ? !!g_cfg.video.write_depth_buffer :
|
||||
@ -354,31 +350,15 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool /*
|
||||
continue;
|
||||
}
|
||||
|
||||
if (surface->is_depth_surface())
|
||||
{
|
||||
const auto depth_format_gl = rsx::internals::surface_depth_format_to_gl(surface->get_surface_depth_format());
|
||||
format = depth_format_gl.format;
|
||||
type = depth_format_gl.type;
|
||||
swap_bytes = (type != gl::texture::type::uint_24_8);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto color_format_gl = rsx::internals::surface_color_format_to_gl(surface->get_surface_color_format());
|
||||
format = color_format_gl.format;
|
||||
type = color_format_gl.type;
|
||||
swap_bytes = color_format_gl.swap_bytes;
|
||||
}
|
||||
|
||||
m_gl_texture_cache.lock_memory_region(
|
||||
cmd, surface, surface->get_memory_range(), false,
|
||||
surface->get_surface_width<rsx::surface_metrics::pixels>(), surface->get_surface_height<rsx::surface_metrics::pixels>(), surface->get_rsx_pitch(),
|
||||
format, type, swap_bytes);
|
||||
surface);
|
||||
}
|
||||
|
||||
m_rtts.orphaned_surfaces.clear();
|
||||
}
|
||||
|
||||
const auto color_format = rsx::internals::surface_color_format_to_gl(m_framebuffer_layout.color_format);
|
||||
for (u8 i = 0; i < rsx::limits::color_buffers_count; ++i)
|
||||
{
|
||||
if (!m_surface_info[i].address || !m_surface_info[i].pitch) continue;
|
||||
@ -390,7 +370,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool /*
|
||||
m_gl_texture_cache.lock_memory_region(
|
||||
cmd, m_rtts.m_bound_render_targets[i].second, surface_range, true,
|
||||
m_surface_info[i].width, m_surface_info[i].height, m_surface_info[i].pitch,
|
||||
color_format.format, color_format.type, color_format.swap_bytes);
|
||||
m_rtts.m_bound_render_targets[i].second);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -403,11 +383,10 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool /*
|
||||
const auto surface_range = m_depth_surface_info.get_memory_range();
|
||||
if (g_cfg.video.write_depth_buffer)
|
||||
{
|
||||
const auto depth_format_gl = rsx::internals::surface_depth_format_to_gl(m_framebuffer_layout.depth_format);
|
||||
m_gl_texture_cache.lock_memory_region(
|
||||
cmd, m_rtts.m_bound_depth_stencil.second, surface_range, true,
|
||||
m_depth_surface_info.width, m_depth_surface_info.height, m_depth_surface_info.pitch,
|
||||
depth_format_gl.format, depth_format_gl.type, depth_format_gl.type != gl::texture::type::uint_24_8);
|
||||
m_rtts.m_bound_depth_stencil.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -472,15 +451,17 @@ void gl::render_target::load_memory(gl::command_context& cmd)
|
||||
}
|
||||
}
|
||||
|
||||
state_flags &= ~rsx::surface_state_flags::erase_bkgnd;
|
||||
state_flags &= ~(rsx::surface_state_flags::erase_bkgnd | rsx::surface_state_flags::force_data_load);
|
||||
}
|
||||
|
||||
void gl::render_target::initialize_memory(gl::command_context& cmd, rsx::surface_access access)
|
||||
{
|
||||
const bool memory_load = is_depth_surface() ?
|
||||
const bool read_buffers_config = is_depth_surface() ?
|
||||
!!g_cfg.video.read_depth_buffer :
|
||||
!!g_cfg.video.read_color_buffers;
|
||||
|
||||
const bool memory_load = (state_flags & rsx::surface_state_flags::force_data_load) || read_buffers_config;
|
||||
|
||||
if (!memory_load)
|
||||
{
|
||||
clear_memory(cmd);
|
||||
|
||||
@ -135,12 +135,12 @@ struct gl_render_target_traits
|
||||
|
||||
static
|
||||
std::unique_ptr<gl::render_target> create_new_surface(
|
||||
gl::command_context&,
|
||||
u32 address,
|
||||
rsx::surface_color_format surface_color_format,
|
||||
usz width, usz height, usz pitch,
|
||||
rsx::surface_antialiasing antialias,
|
||||
const rsx::surface_scaling_config_t& resolution_scaling_config
|
||||
)
|
||||
const rsx::surface_scaling_config_t& resolution_scaling_config)
|
||||
{
|
||||
auto format = rsx::internals::surface_color_format_to_gl(surface_color_format);
|
||||
const auto [width_, height_] = rsx::apply_resolution_scale<true>(resolution_scaling_config, static_cast<u16>(width), static_cast<u16>(height));
|
||||
@ -181,12 +181,12 @@ struct gl_render_target_traits
|
||||
|
||||
static
|
||||
std::unique_ptr<gl::render_target> create_new_surface(
|
||||
u32 address,
|
||||
rsx::surface_depth_format2 surface_depth_format,
|
||||
usz width, usz height, usz pitch,
|
||||
rsx::surface_antialiasing antialias,
|
||||
const rsx::surface_scaling_config_t& resolution_scaling_config
|
||||
)
|
||||
gl::command_context&,
|
||||
u32 address,
|
||||
rsx::surface_depth_format2 surface_depth_format,
|
||||
usz width, usz height, usz pitch,
|
||||
rsx::surface_antialiasing antialias,
|
||||
const rsx::surface_scaling_config_t& resolution_scaling_config)
|
||||
{
|
||||
auto format = rsx::internals::surface_depth_format_to_gl(surface_depth_format);
|
||||
const auto [width_, height_] = rsx::apply_resolution_scale<true>(resolution_scaling_config, static_cast<u16>(width), static_cast<u16>(height));
|
||||
@ -252,7 +252,7 @@ struct gl_render_target_traits
|
||||
sink->resolution_scaling_config = scaling_config;
|
||||
|
||||
sink->set_name(fmt::format("SINK_%u@0x%x", sink->id(), address));
|
||||
sink->set_spp(ref->get_spp());
|
||||
sink->set_aa_mode(ref->get_aa_mode());
|
||||
sink->set_native_pitch(static_cast<u32>(prev.width) * ref->get_bpp() * ref->samples_x);
|
||||
sink->set_rsx_pitch(ref->get_rsx_pitch());
|
||||
sink->set_surface_dimensions(prev.width, prev.height, ref->get_rsx_pitch());
|
||||
|
||||
@ -120,6 +120,30 @@ namespace gl
|
||||
baseclass::on_section_resources_created();
|
||||
}
|
||||
|
||||
void create(u16 w, u16 h, u16 depth, u16 mipmaps, gl::texture* image, u32 rsx_pitch, bool managed, const gl::render_target* surface)
|
||||
{
|
||||
gl::texture::format format;
|
||||
gl::texture::type type;
|
||||
bool swap_bytes;
|
||||
|
||||
if (surface->is_depth_surface())
|
||||
{
|
||||
const auto depth_format_gl = rsx::internals::surface_depth_format_to_gl(surface->get_surface_depth_format());
|
||||
format = depth_format_gl.format;
|
||||
type = depth_format_gl.type;
|
||||
swap_bytes = (type != gl::texture::type::uint_24_8);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto color_format_gl = rsx::internals::surface_color_format_to_gl(surface->get_surface_color_format());
|
||||
format = color_format_gl.format;
|
||||
type = color_format_gl.type;
|
||||
swap_bytes = color_format_gl.swap_bytes;
|
||||
}
|
||||
|
||||
create(w, h, depth, mipmaps, image, rsx_pitch, managed, format, type, swap_bytes);
|
||||
}
|
||||
|
||||
void set_dimensions(u32 width, u32 height, u32 /*depth*/, u32 pitch)
|
||||
{
|
||||
this->width = width;
|
||||
|
||||
@ -2480,8 +2480,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
|
||||
m_framebuffer_layout.target, m_framebuffer_layout.aa_mode, m_framebuffer_layout.raster_type,
|
||||
m_framebuffer_layout.color_addresses, m_framebuffer_layout.zeta_address,
|
||||
m_framebuffer_layout.actual_color_pitch, m_framebuffer_layout.actual_zeta_pitch,
|
||||
resolution_scaling_config,
|
||||
(*m_device), *m_current_command_buffer);
|
||||
resolution_scaling_config);
|
||||
|
||||
// Reset framebuffer information
|
||||
const auto color_bpp = get_format_block_size_in_bytes(m_framebuffer_layout.color_format);
|
||||
@ -2572,9 +2571,6 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
|
||||
|
||||
if (!m_rtts.orphaned_surfaces.empty())
|
||||
{
|
||||
u32 gcm_format;
|
||||
bool swap_bytes;
|
||||
|
||||
for (auto& [base_addr, surface] : m_rtts.orphaned_surfaces)
|
||||
{
|
||||
bool lock = surface->is_depth_surface() ? !!g_cfg.video.write_depth_buffer :
|
||||
@ -2600,28 +2596,15 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (surface->is_depth_surface())
|
||||
{
|
||||
gcm_format = (surface->get_surface_depth_format() != rsx::surface_depth_format::z16) ? CELL_GCM_TEXTURE_DEPTH16 : CELL_GCM_TEXTURE_DEPTH24_D8;
|
||||
swap_bytes = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto info = get_compatible_gcm_format(surface->get_surface_color_format());
|
||||
gcm_format = info.first;
|
||||
swap_bytes = info.second;
|
||||
}
|
||||
|
||||
m_texture_cache.lock_memory_region(
|
||||
*m_current_command_buffer, surface, surface->get_memory_range(), false,
|
||||
surface->get_surface_width<rsx::surface_metrics::pixels>(), surface->get_surface_height<rsx::surface_metrics::pixels>(), surface->get_rsx_pitch(),
|
||||
gcm_format, swap_bytes);
|
||||
surface);
|
||||
}
|
||||
|
||||
m_rtts.orphaned_surfaces.clear();
|
||||
}
|
||||
|
||||
const auto color_fmt_info = get_compatible_gcm_format(m_framebuffer_layout.color_format);
|
||||
for (u8 index : m_draw_buffers)
|
||||
{
|
||||
if (!m_surface_info[index].address || !m_surface_info[index].pitch) continue;
|
||||
@ -2632,7 +2615,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
|
||||
m_texture_cache.lock_memory_region(
|
||||
*m_current_command_buffer, m_rtts.m_bound_render_targets[index].second, surface_range, true,
|
||||
m_surface_info[index].width, m_surface_info[index].height, m_framebuffer_layout.actual_color_pitch[index],
|
||||
color_fmt_info.first, color_fmt_info.second);
|
||||
m_rtts.m_bound_render_targets[index].second);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2645,10 +2628,10 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
|
||||
const utils::address_range32 surface_range = m_depth_surface_info.get_memory_range();
|
||||
if (g_cfg.video.write_depth_buffer)
|
||||
{
|
||||
const u32 gcm_format = (m_depth_surface_info.depth_format == rsx::surface_depth_format::z16) ? CELL_GCM_TEXTURE_DEPTH16 : CELL_GCM_TEXTURE_DEPTH24_D8;
|
||||
m_texture_cache.lock_memory_region(
|
||||
*m_current_command_buffer, m_rtts.m_bound_depth_stencil.second, surface_range, true,
|
||||
m_depth_surface_info.width, m_depth_surface_info.height, m_framebuffer_layout.actual_zeta_pitch, gcm_format, true);
|
||||
m_depth_surface_info.width, m_depth_surface_info.height, m_framebuffer_layout.actual_zeta_pitch,
|
||||
m_rtts.m_bound_depth_stencil.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -794,13 +794,16 @@ namespace vk
|
||||
}
|
||||
}
|
||||
|
||||
state_flags &= ~rsx::surface_state_flags::erase_bkgnd;
|
||||
state_flags &= ~(rsx::surface_state_flags::erase_bkgnd | rsx::surface_state_flags::force_data_load);
|
||||
}
|
||||
|
||||
void render_target::initialize_memory(vk::command_buffer& cmd, rsx::surface_access access)
|
||||
{
|
||||
const bool is_depth = is_depth_surface();
|
||||
const bool should_read_buffers = is_depth ? !!g_cfg.video.read_depth_buffer : !!g_cfg.video.read_color_buffers;
|
||||
const bool read_buffers_config = is_depth_surface() ?
|
||||
!!g_cfg.video.read_depth_buffer :
|
||||
!!g_cfg.video.read_color_buffers;
|
||||
|
||||
const bool should_read_buffers = (state_flags & rsx::surface_state_flags::force_data_load) || read_buffers_config;
|
||||
|
||||
if (!should_read_buffers)
|
||||
{
|
||||
@ -938,7 +941,8 @@ namespace vk
|
||||
}
|
||||
|
||||
const bool is_depth = is_depth_surface();
|
||||
const bool should_read_buffers = is_depth ? !!g_cfg.video.read_depth_buffer : !!g_cfg.video.read_color_buffers;
|
||||
const bool read_buffers_config = is_depth ? !!g_cfg.video.read_depth_buffer : !!g_cfg.video.read_color_buffers;
|
||||
const bool should_read_buffers = (state_flags & rsx::surface_state_flags::force_data_load) || read_buffers_config;
|
||||
|
||||
if (should_read_buffers)
|
||||
{
|
||||
|
||||
@ -196,12 +196,12 @@ namespace vk
|
||||
}
|
||||
|
||||
static std::unique_ptr<vk::render_target> create_new_surface(
|
||||
const vk::command_buffer& cmd,
|
||||
u32 address,
|
||||
rsx::surface_color_format format,
|
||||
usz width, usz height, usz pitch,
|
||||
rsx::surface_antialiasing antialias,
|
||||
const rsx::surface_scaling_config_t& resolution_scaling_config,
|
||||
vk::render_device& device, vk::command_buffer& cmd)
|
||||
const rsx::surface_scaling_config_t& resolution_scaling_config)
|
||||
{
|
||||
const auto fmt = vk::get_compatible_surface_format(format);
|
||||
VkFormat requested_format = fmt.first;
|
||||
@ -234,7 +234,8 @@ namespace vk
|
||||
std::unique_ptr<vk::render_target> rtt;
|
||||
const auto [width_, height_] = rsx::apply_resolution_scale<true>(resolution_scaling_config, static_cast<u16>(width), static_cast<u16>(height));
|
||||
|
||||
rtt = std::make_unique<vk::render_target>(device, device.get_memory_mapping().device_local,
|
||||
auto pdev = vk::get_current_renderer();
|
||||
rtt = std::make_unique<vk::render_target>(*pdev, pdev->get_memory_mapping().device_local,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
VK_IMAGE_TYPE_2D,
|
||||
requested_format,
|
||||
@ -268,14 +269,15 @@ namespace vk
|
||||
}
|
||||
|
||||
static std::unique_ptr<vk::render_target> create_new_surface(
|
||||
const vk::command_buffer& cmd,
|
||||
u32 address,
|
||||
rsx::surface_depth_format2 format,
|
||||
usz width, usz height, usz pitch,
|
||||
rsx::surface_antialiasing antialias,
|
||||
const rsx::surface_scaling_config_t& resolution_scaling_config,
|
||||
vk::render_device& device, vk::command_buffer& cmd)
|
||||
const rsx::surface_scaling_config_t& resolution_scaling_config)
|
||||
{
|
||||
const VkFormat requested_format = vk::get_compatible_depth_surface_format(device.get_formats_support(), format);
|
||||
auto pdev = vk::get_current_renderer();
|
||||
const VkFormat requested_format = vk::get_compatible_depth_surface_format(pdev->get_formats_support(), format);
|
||||
|
||||
u8 samples;
|
||||
rsx::surface_sample_layout sample_layout;
|
||||
@ -301,7 +303,7 @@ namespace vk
|
||||
std::unique_ptr<vk::render_target> ds;
|
||||
const auto [width_, height_] = rsx::apply_resolution_scale<true>(resolution_scaling_config, static_cast<u16>(width), static_cast<u16>(height));
|
||||
|
||||
ds = std::make_unique<vk::render_target>(device, device.get_memory_mapping().device_local,
|
||||
ds = std::make_unique<vk::render_target>(*pdev, pdev->get_memory_mapping().device_local,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
VK_IMAGE_TYPE_2D,
|
||||
requested_format,
|
||||
@ -366,7 +368,7 @@ namespace vk
|
||||
sink->sample_layout = ref->sample_layout;
|
||||
sink->resolution_scaling_config = scaling_config;
|
||||
|
||||
sink->set_spp(ref->get_spp());
|
||||
sink->set_aa_mode(ref->get_aa_mode());
|
||||
sink->format_info = ref->format_info;
|
||||
sink->memory_usage_flags = rsx::surface_usage_flags::storage;
|
||||
sink->state_flags = rsx::surface_state_flags::erase_bkgnd;
|
||||
|
||||
@ -37,7 +37,7 @@ namespace vk
|
||||
|
||||
std::unique_ptr<vk::viewable_image> managed_texture = nullptr;
|
||||
|
||||
//DMA relevant data
|
||||
// DMA relevant data
|
||||
std::unique_ptr<vk::event> dma_fence;
|
||||
vk::render_device* m_device = nullptr;
|
||||
vk::viewable_image* vram_texture = nullptr;
|
||||
@ -99,6 +99,26 @@ namespace vk
|
||||
baseclass::on_section_resources_created();
|
||||
}
|
||||
|
||||
void create(u16 w, u16 h, u16 depth, u16 mipmaps, vk::image* image, u32 rsx_pitch, bool managed, const vk::render_target* surface)
|
||||
{
|
||||
u32 gcm_format;
|
||||
bool swap_bytes;
|
||||
|
||||
if (surface->is_depth_surface())
|
||||
{
|
||||
gcm_format = (surface->get_surface_depth_format() != rsx::surface_depth_format::z16) ? CELL_GCM_TEXTURE_DEPTH16 : CELL_GCM_TEXTURE_DEPTH24_D8;
|
||||
swap_bytes = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto info = get_compatible_gcm_format(surface->get_surface_color_format());
|
||||
gcm_format = info.first;
|
||||
swap_bytes = info.second;
|
||||
}
|
||||
|
||||
create(w, h, depth, mipmaps, image, rsx_pitch, managed, gcm_format, swap_bytes);
|
||||
}
|
||||
|
||||
void release_dma_resources()
|
||||
{
|
||||
if (dma_fence)
|
||||
|
||||
@ -680,6 +680,7 @@
|
||||
<ClInclude Include="Emu\RSX\Common\bitfield.hpp" />
|
||||
<ClInclude Include="Emu\RSX\Common\buffer_stream.hpp" />
|
||||
<ClInclude Include="Emu\RSX\Common\reverse_ptr.hpp" />
|
||||
<ClInclude Include="Emu\RSX\Common\texture_cache_blit_helpers.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\tiled_dma_copy.hpp" />
|
||||
<ClInclude Include="Emu\RSX\Common\expected.hpp" />
|
||||
<ClInclude Include="Emu\RSX\Common\io_buffer.h" />
|
||||
|
||||
@ -2950,6 +2950,9 @@
|
||||
<ClInclude Include="Emu\Cell\Modules\libsvc1d.h">
|
||||
<Filter>Emu\Cell\Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\Common\texture_cache_blit_helpers.h">
|
||||
<Filter>Emu\GPU\RSX\Common</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user