From 3150619320e9f7f1c7547b7dfd5da21a6091341b Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 3 Jun 2018 14:52:21 +0300 Subject: [PATCH] rsx: Preserve read AA state separate from write AA state - Some applications (e.g Backbreaker) use an evil hack to resolve MSAA. The application respecifies a formerly AA region as a region with no AA then performs a framebuffer feedback lookup. The old memory keeps AA during read, but writes back to itself with AA resolved. This is evil on several levels but it just happens to work on PS3 --- rpcs3/Emu/RSX/Common/surface_store.h | 69 +++++++++++++++------ rpcs3/Emu/RSX/Common/texture_cache.h | 8 +-- rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h | 14 ++--- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 26 +++----- rpcs3/Emu/RSX/GL/GLRenderTargets.cpp | 8 +-- rpcs3/Emu/RSX/GL/GLRenderTargets.h | 23 ++++--- rpcs3/Emu/RSX/GL/GLTextureCache.h | 2 +- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 41 +++++------- rpcs3/Emu/RSX/VK/VKRenderTargets.h | 25 ++++---- rpcs3/Emu/RSX/VK/VKTextureCache.h | 2 +- rpcs3/Emu/RSX/rsx_utils.h | 4 +- 11 files changed, 115 insertions(+), 107 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index f74ce65e38..ca9d12dfb0 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -61,14 +61,36 @@ namespace rsx template struct render_target_descriptor { + bool dirty = false; + image_storage_type old_contents = nullptr; + rsx::surface_antialiasing read_aa_mode = rsx::surface_antialiasing::center_1_sample; + GcmTileInfo *tile = nullptr; - rsx::surface_antialiasing aa_mode = rsx::surface_antialiasing::center_1_sample; + rsx::surface_antialiasing write_aa_mode = rsx::surface_antialiasing::center_1_sample; 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; + + 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 on_write() + { + read_aa_mode = write_aa_mode; + dirty = false; + old_contents = nullptr; + } }; /** @@ -134,6 +156,7 @@ namespace rsx std::list invalidated_resources; u64 cache_tag = 0ull; + u64 write_tag = 0ull; surface_store() = default; ~surface_store() = default; @@ -175,6 +198,7 @@ namespace rsx surface_storage_type &rtt = It->second; if (Traits::rtt_has_format_width_height(rtt, color_format, width, height)) { + Traits::notify_surface_persist(rtt); Traits::prepare_rtt_for_drawing(command_list, Traits::get(rtt)); return Traits::get(rtt); } @@ -206,7 +230,7 @@ namespace rsx invalidated_resources.erase(It); new_surface = Traits::get(new_surface_storage); - Traits::invalidate_rtt_surface_contents(command_list, new_surface, contents_to_copy, true); + Traits::invalidate_surface_contents(command_list, new_surface, contents_to_copy); Traits::prepare_rtt_for_drawing(command_list, new_surface); break; } @@ -259,6 +283,7 @@ namespace rsx surface_storage_type &ds = It->second; if (Traits::ds_has_format_width_height(ds, depth_format, width, height)) { + Traits::notify_surface_persist(ds); Traits::prepare_ds_for_drawing(command_list, Traits::get(ds)); return Traits::get(ds); } @@ -290,7 +315,7 @@ namespace rsx new_surface = Traits::get(new_surface_storage); Traits::prepare_ds_for_drawing(command_list, new_surface); - Traits::invalidate_depth_surface_contents(command_list, new_surface, contents_to_copy, true); + Traits::invalidate_surface_contents(command_list, new_surface, contents_to_copy); break; } } @@ -527,19 +552,6 @@ namespace rsx return result; } - /** - * Invalidates cached surface data and marks surface contents as deleteable - * Called at the end of a frame (workaround, need to find the proper invalidate command) - */ - void invalidate_surface_cache_data(command_list_type command_list) - { - for (auto &rtt : m_render_targets_storage) - Traits::invalidate_rtt_surface_contents(command_list, Traits::get(std::get<1>(rtt)), nullptr, false); - - for (auto &ds : m_depth_stencil_storage) - Traits::invalidate_depth_surface_contents(command_list, Traits::get(std::get<1>(ds)), nullptr, true); - } - /** * 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 @@ -653,7 +665,7 @@ namespace rsx bool doubled_x = false; bool doubled_y = false; - switch (surface->aa_mode) + switch (surface->read_aa_mode) { case rsx::surface_antialiasing::square_rotated_4_samples: case rsx::surface_antialiasing::square_centered_4_samples: @@ -741,7 +753,7 @@ namespace rsx u16 real_width = requested_width; u16 real_height = requested_height; - switch (surface->aa_mode) + switch (surface->read_aa_mode) { case rsx::surface_antialiasing::diagonal_centered_2_samples: real_width /= 2; @@ -894,5 +906,26 @@ namespace rsx process_list_function(m_depth_stencil_storage, true); return result; } + + void on_write() + { + if (write_tag == cache_tag) + return; + + for (auto &rtt : m_bound_render_targets) + { + if (auto surface = std::get<1>(rtt)) + { + surface->on_write(); + } + } + + if (auto ds = std::get<1>(m_bound_depth_stencil)) + { + ds->on_write(); + } + + write_tag = cache_tag; + } }; } diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 093055d657..c4e7474466 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -740,7 +740,7 @@ namespace rsx template inline void get_native_dimensions(T &width, T &height, U surface) { - switch (surface->aa_mode) + switch (surface->read_aa_mode) { case rsx::surface_antialiasing::center_1_sample: return; @@ -758,7 +758,7 @@ namespace rsx template inline void get_rsx_dimensions(T &width, T &height, U surface) { - switch (surface->aa_mode) + switch (surface->read_aa_mode) { case rsx::surface_antialiasing::center_1_sample: return; @@ -776,7 +776,7 @@ namespace rsx template inline f32 get_internal_scaling_x(T surface) { - switch (surface->aa_mode) + switch (surface->read_aa_mode) { default: case rsx::surface_antialiasing::center_1_sample: @@ -791,7 +791,7 @@ namespace rsx template inline f32 get_internal_scaling_y(T surface) { - switch (surface->aa_mode) + switch (surface->read_aa_mode) { default: case rsx::surface_antialiasing::center_1_sample: diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h index ef45073680..ecd60addd2 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h @@ -129,21 +129,17 @@ struct render_target_traits } static - void invalidate_rtt_surface_contents( + void invalidate_surface_contents( gsl::not_null, - ID3D12Resource*, ID3D12Resource*, bool) + ID3D12Resource*, ID3D12Resource*) {} static - void invalidate_depth_surface_contents( - gsl::not_null, - ID3D12Resource*, ID3D12Resource*, bool) - { - //TODO - } + void notify_surface_invalidated(const ComPtr&) + {} static - void notify_surface_invalidated(const ComPtr&) + void notify_surface_persist(const ComPtr&) {} static diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 0afbf517e6..5118f83a63 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -214,11 +214,8 @@ void GLGSRender::end() //Copy data from old contents onto this one const auto region = rsx::get_transferable_region(surface); gl::g_hw_blitter->scale_image(surface->old_contents, surface, { 0, 0, std::get<0>(region), std::get<1>(region) }, { 0, 0, std::get<2>(region) , std::get<3>(region) }, !is_depth, is_depth, {}); - surface->set_cleared(); } //TODO: download image contents and reupload them or do a memory cast to copy memory contents if not compatible - - surface->old_contents = nullptr; }; //Check if we have any 'recycled' surfaces in memory and if so, clear them @@ -273,15 +270,12 @@ void GLGSRender::end() if (clear_depth) gl_state.depth_mask(rsx::method_registers.depth_write_enabled()); - - ds->set_cleared(); } - if (ds && ds->old_contents != nullptr && ds->get_rsx_pitch() == ds->old_contents->get_rsx_pitch() && + if (ds && ds->old_contents != nullptr && ds->get_rsx_pitch() == static_cast(ds->old_contents)->get_rsx_pitch() && ds->old_contents->get_internal_format() == gl::texture::internal_format::rgba8) { m_depth_converter.run(ds->width(), ds->height(), ds->id(), ds->old_contents->id()); - ds->old_contents = nullptr; } if (g_cfg.video.strict_rendering_mode) @@ -298,11 +292,6 @@ void GLGSRender::end() } } } - else - { - // Old contents are one use only. Keep the depth conversion check from firing over and over - if (ds) ds->old_contents = nullptr; - } glEnable(GL_SCISSOR_TEST); @@ -571,6 +560,8 @@ void GLGSRender::end() } } + m_rtts.on_write(); + m_attrib_ring_buffer->notify(); m_index_ring_buffer->notify(); m_vertex_state_buffer->notify(); @@ -988,11 +979,9 @@ void GLGSRender::clear_surface(u32 arg) gl_state.clear_depth(f32(clear_depth) / max_depth_value); mask |= GLenum(gl::buffers::depth); - gl::render_target *ds = std::get<1>(m_rtts.m_bound_depth_stencil); - if (ds && !ds->cleared()) + if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil)) { - ds->set_cleared(); - ds->old_contents = nullptr; + ds->on_write(); } } @@ -1036,10 +1025,9 @@ void GLGSRender::clear_surface(u32 arg) for (auto &rtt : m_rtts.m_bound_render_targets) { - if (std::get<0>(rtt) != 0) + if (auto surface = std::get<1>(rtt)) { - std::get<1>(rtt)->set_cleared(true); - std::get<1>(rtt)->old_contents = nullptr; + surface->on_write(); } } diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp index bac2ce7bbc..6ba91eb980 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp @@ -375,13 +375,13 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk { if (auto surface = std::get<1>(m_rtts.m_bound_render_targets[index])) { - surface->aa_mode = aa_mode; + surface->write_aa_mode = aa_mode; } } if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil)) { - ds->aa_mode = aa_mode; + ds->write_aa_mode = aa_mode; } return; @@ -426,7 +426,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk m_surface_info[i] = { surface_addresses[i], pitchs[i], false, surface_format, depth_format, clip_horizontal, clip_vertical }; rtt->tile = find_tile(color_offsets[i], color_locations[i]); - rtt->aa_mode = aa_mode; + rtt->write_aa_mode = aa_mode; m_gl_texture_cache.notify_surface_changed(surface_addresses[i]); m_gl_texture_cache.tag_framebuffer(surface_addresses[i]); } @@ -455,7 +455,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk std::get<1>(m_rtts.m_bound_depth_stencil)->set_rsx_pitch(rsx::method_registers.surface_z_pitch()); m_depth_surface_info = { depth_address, depth_surface_pitch, true, surface_format, depth_format, clip_horizontal, clip_vertical }; - ds->aa_mode = aa_mode; + ds->write_aa_mode = aa_mode; m_gl_texture_cache.notify_surface_changed(depth_address); m_gl_texture_cache.tag_framebuffer(depth_address); diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.h b/rpcs3/Emu/RSX/GL/GLRenderTargets.h index 0c5d9dcb7f..8ee0c1471e 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.h +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.h @@ -51,8 +51,6 @@ namespace gl { class render_target : public texture, public rsx::ref_counted, public rsx::render_target_descriptor { - bool is_cleared = false; - u32 rsx_pitch = 0; u16 native_pitch = 0; @@ -65,20 +63,18 @@ namespace gl std::unordered_map> views; public: - render_target *old_contents = nullptr; - render_target(GLuint width, GLuint height, GLenum sized_format) :texture(GL_TEXTURE_2D, width, height, 1, 1, sized_format) {} void set_cleared(bool clear=true) { - is_cleared = clear; + dirty = !clear; } bool cleared() const { - return is_cleared; + return !dirty; } // Internal pitch is the actual row length in bytes of the openGL texture @@ -228,13 +224,24 @@ struct gl_render_target_traits static void prepare_ds_for_drawing(void *, gl::render_target *ds) { ds->reset_refs(); } static void prepare_ds_for_sampling(void *, gl::render_target*) {} - static void invalidate_rtt_surface_contents(void *, gl::render_target *rtt, gl::render_target* /*old*/, bool forced) { if (forced) rtt->set_cleared(false); } - static void invalidate_depth_surface_contents(void *, gl::render_target *ds, gl::render_target* /*old*/, bool) { ds->set_cleared(false); } + static + void invalidate_surface_contents(void *, gl::render_target *surface, gl::render_target* old_surface) + { + surface->set_cleared(false); + surface->old_contents = old_surface; + surface->reset_aa_mode(); + } static void notify_surface_invalidated(const std::unique_ptr&) {} + static + void notify_surface_persist(const std::unique_ptr& surface) + { + surface->save_aa_mode(); + } + static bool rtt_has_format_width_height(const std::unique_ptr &rtt, rsx::surface_color_format format, size_t width, size_t height, bool check_refs=false) { diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 7562b83ead..bd2a1fb981 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -265,7 +265,7 @@ namespace gl if (pbo_id == 0) init_buffer(); - aa_mode = static_cast(image)->aa_mode; + aa_mode = static_cast(image)->read_aa_mode; } flushed = false; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index a3506f845f..3ed4cc81ff 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1115,7 +1115,6 @@ void VKGSRender::end() VkClearValue clear_value = {}; clear_value.depthStencil = { 1.f, 255 }; buffers_to_clear.push_back({ vk::get_aspect_flags(ds->info.format), 0, clear_value }); - ds->dirty = false; } for (u32 index = 0; index < targets.size(); ++index) @@ -1125,7 +1124,6 @@ void VKGSRender::end() if (rtt->dirty) { buffers_to_clear.push_back({ VK_IMAGE_ASPECT_COLOR_BIT, index, {} }); - rtt->dirty = false; } } } @@ -1148,14 +1146,9 @@ void VKGSRender::end() { auto rp = vk::get_render_pass_location(VK_FORMAT_UNDEFINED, ds->info.format, 0); auto render_pass = m_render_passes[rp]; - m_depth_converter->run(*m_current_command_buffer, ds->width(), ds->height(), ds, ds->old_contents->get_view(0xAAE4, rsx::default_remap_vector), render_pass, m_framebuffers_to_clean); - - ds->old_contents = nullptr; - } - else if (!g_cfg.video.strict_rendering_mode) - { - //Clear this to avoid dereferencing stale ptr - ds->old_contents = nullptr; + m_depth_converter->run(*m_current_command_buffer, ds->width(), ds->height(), ds, + static_cast(ds->old_contents)->get_view(0xAAE4, rsx::default_remap_vector), + render_pass, m_framebuffers_to_clean); } } @@ -1187,14 +1180,9 @@ void VKGSRender::end() vk::change_image_layout(*m_current_command_buffer, surface->old_contents, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_depth_scaler->run(*m_current_command_buffer, { 0, 0, (f32)src_w, (f32)src_h }, { 0, 0, (f32)dst_w, (f32)dst_h }, surface, - surface->old_contents, surface->old_contents->get_view(0xAAE4, rsx::default_remap_vector), render_pass, m_framebuffers_to_clean); + surface->old_contents, static_cast(surface->old_contents)->get_view(0xAAE4, rsx::default_remap_vector), render_pass, m_framebuffers_to_clean); } - - surface->dirty = false; } - //TODO: download image contents and reupload them or do a memory cast to copy memory contents if not compatible - - surface->old_contents = nullptr; }; //Prepare surfaces if needed @@ -1519,6 +1507,8 @@ void VKGSRender::end() close_render_pass(); vk::leave_uninterruptible(); + m_rtts.on_write(); + std::chrono::time_point draw_end = steady_clock::now(); m_draw_time += std::chrono::duration_cast(draw_end - textures_end).count(); @@ -1792,10 +1782,9 @@ void VKGSRender::clear_surface(u32 mask) for (auto &rtt : m_rtts.m_bound_render_targets) { - if (std::get<0>(rtt) != 0) + if (auto surface = std::get<1>(rtt)) { - std::get<1>(rtt)->dirty = false; - std::get<1>(rtt)->old_contents = nullptr; + surface->on_write(); } } } @@ -1804,11 +1793,9 @@ void VKGSRender::clear_surface(u32 mask) if (mask & 0x3) { - if (std::get<0>(m_rtts.m_bound_depth_stencil) != 0) + if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil)) { - std::get<1>(m_rtts.m_bound_depth_stencil)->dirty = false; - std::get<1>(m_rtts.m_bound_depth_stencil)->old_contents = nullptr; - + ds->on_write(); clear_descriptors.push_back({ (VkImageAspectFlags)depth_stencil_mask, 0, depth_stencil_clear_values }); } } @@ -2744,13 +2731,13 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context) { if (auto surface = std::get<1>(m_rtts.m_bound_render_targets[index])) { - surface->aa_mode = aa_mode; + surface->write_aa_mode = aa_mode; } } if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil)) { - ds->aa_mode = aa_mode; + ds->write_aa_mode = aa_mode; } return; @@ -2820,7 +2807,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context) m_surface_info[index].pitch = surface_pitchs[index]; surface->rsx_pitch = surface_pitchs[index]; - surface->aa_mode = aa_mode; + surface->write_aa_mode = aa_mode; m_texture_cache.notify_surface_changed(surface_addresses[index]); m_texture_cache.tag_framebuffer(surface_addresses[index]); @@ -2837,7 +2824,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context) m_depth_surface_info.pitch = rsx::method_registers.surface_z_pitch(); ds->rsx_pitch = m_depth_surface_info.pitch; - ds->aa_mode = aa_mode; + ds->write_aa_mode = aa_mode; m_texture_cache.notify_surface_changed(zeta_address); m_texture_cache.tag_framebuffer(zeta_address); diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.h b/rpcs3/Emu/RSX/VK/VKRenderTargets.h index ec49deec02..232a9cc842 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.h +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.h @@ -12,7 +12,6 @@ namespace vk { struct render_target : public image, public rsx::ref_counted, public rsx::render_target_descriptor { - bool dirty = false; u16 native_pitch = 0; u16 rsx_pitch = 0; @@ -22,7 +21,6 @@ namespace vk VkImageAspectFlags attachment_aspect_flag = VK_IMAGE_ASPECT_COLOR_BIT; std::unordered_map> views; - render_target *old_contents = nullptr; //Data occupying the memory location that this surface is replacing u64 frame_tag = 0; //frame id when invalidated, 0 if not invalid render_target(vk::render_device &dev, @@ -240,19 +238,12 @@ namespace rsx change_image_layout(*pcmd, surface, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range); } - static void invalidate_rtt_surface_contents(vk::command_buffer* /*pcmd*/, vk::render_target *rtt, vk::render_target *old_surface, bool forced) + static + void invalidate_surface_contents(vk::command_buffer* /*pcmd*/, vk::render_target *surface, vk::render_target *old_surface) { - if (forced) - { - rtt->old_contents = old_surface; - rtt->dirty = true; - } - } - - static void invalidate_depth_surface_contents(vk::command_buffer* /*pcmd*/, vk::render_target *ds, vk::render_target *old_surface, bool /*forced*/) - { - ds->dirty = true; - ds->old_contents = old_surface; + surface->old_contents = old_surface; + surface->dirty = true; + surface->reset_aa_mode(); } static @@ -262,6 +253,12 @@ namespace rsx if (!surface->frame_tag) surface->frame_tag = 1; } + static + void notify_surface_persist(const std::unique_ptr &surface) + { + surface->save_aa_mode(); + } + static bool rtt_has_format_width_height(const std::unique_ptr &rtt, surface_color_format format, size_t width, size_t height, bool check_refs=false) { if (check_refs && rtt->deref_count == 0) //Surface may still have read refs from data 'copy' diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 3ca5cda174..fc9a7fff2d 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -296,7 +296,7 @@ namespace vk //Scale image to fit //usually we can just get away with nearest filtering u8 samples_u = 1, samples_v = 1; - switch (static_cast(vram_texture)->aa_mode) + switch (static_cast(vram_texture)->read_aa_mode) { case rsx::surface_antialiasing::diagonal_centered_2_samples: samples_u = 2; diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index 4d3b7401e2..b6d43363a8 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -597,7 +597,7 @@ namespace rsx u16 dst_w = src_w; u16 dst_h = src_h; - switch (surface->old_contents->aa_mode) + switch (static_cast(surface->old_contents)->read_aa_mode) { case rsx::surface_antialiasing::center_1_sample: break; @@ -611,7 +611,7 @@ namespace rsx break; } - switch (surface->aa_mode) + switch (surface->write_aa_mode) { case rsx::surface_antialiasing::center_1_sample: break;