mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-29 22:20:48 +00:00
gl: Use the GPU to scale textures; use ARB_sampler_object
Improve scaling and separate sampler state from texture state gl: Unify all texture cache objects under one structure separate by use case gl: Texture cache fixes - Acquire lock when finding matching textures - Account for swizzled surfaces when deciding whether to cpu memcpy - Handle swizzled images on the GPU
This commit is contained in:
parent
d94986ff0d
commit
6d6d0e4e36
@ -408,6 +408,7 @@ void GLGSRender::end()
|
|||||||
std::chrono::time_point<steady_clock> textures_start = steady_clock::now();
|
std::chrono::time_point<steady_clock> textures_start = steady_clock::now();
|
||||||
|
|
||||||
//Setup textures
|
//Setup textures
|
||||||
|
//Setting unused texture to 0 is not needed, but makes program validation happy if we choose to enforce it
|
||||||
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
|
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
|
||||||
{
|
{
|
||||||
int location;
|
int location;
|
||||||
@ -422,6 +423,7 @@ void GLGSRender::end()
|
|||||||
{
|
{
|
||||||
m_gl_textures[i].set_target(get_gl_target_for_texture(rsx::method_registers.fragment_textures[i]));
|
m_gl_textures[i].set_target(get_gl_target_for_texture(rsx::method_registers.fragment_textures[i]));
|
||||||
__glcheck m_gl_texture_cache.upload_texture(i, rsx::method_registers.fragment_textures[i], m_gl_textures[i], m_rtts);
|
__glcheck m_gl_texture_cache.upload_texture(i, rsx::method_registers.fragment_textures[i], m_gl_textures[i], m_rtts);
|
||||||
|
__glcheck m_gl_sampler_states[i].apply(rsx::method_registers.fragment_textures[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,6 +574,12 @@ void GLGSRender::on_init_thread()
|
|||||||
if (g_cfg_rsx_overlay)
|
if (g_cfg_rsx_overlay)
|
||||||
m_text_printer.init();
|
m_text_printer.init();
|
||||||
|
|
||||||
|
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
|
||||||
|
{
|
||||||
|
m_gl_sampler_states[i].create();
|
||||||
|
m_gl_sampler_states[i].bind(i);
|
||||||
|
}
|
||||||
|
|
||||||
m_gl_texture_cache.initialize(this);
|
m_gl_texture_cache.initialize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,6 +614,11 @@ void GLGSRender::on_exit()
|
|||||||
tex.remove();
|
tex.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto &sampler : m_gl_sampler_states)
|
||||||
|
{
|
||||||
|
sampler.remove();
|
||||||
|
}
|
||||||
|
|
||||||
m_attrib_ring_buffer->remove();
|
m_attrib_ring_buffer->remove();
|
||||||
m_transform_constants_buffer->remove();
|
m_transform_constants_buffer->remove();
|
||||||
m_fragment_constants_buffer->remove();
|
m_fragment_constants_buffer->remove();
|
||||||
@ -879,7 +892,7 @@ void GLGSRender::flip(int buffer)
|
|||||||
|
|
||||||
gl::screen.clear(gl::buffers::color_depth_stencil);
|
gl::screen.clear(gl::buffers::color_depth_stencil);
|
||||||
|
|
||||||
__glcheck flip_fbo->blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical());
|
__glcheck flip_fbo->blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical(), gl::buffers::color, gl::filter::linear);
|
||||||
|
|
||||||
if (g_cfg_rsx_overlay)
|
if (g_cfg_rsx_overlay)
|
||||||
{
|
{
|
||||||
@ -960,7 +973,7 @@ void GLGSRender::do_local_task()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
work_item& GLGSRender::post_flush_request(u32 address, gl::texture_cache::cached_rtt_section *section)
|
work_item& GLGSRender::post_flush_request(u32 address, gl::texture_cache::cached_texture_section *section)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(queue_guard);
|
std::lock_guard<std::mutex> lock(queue_guard);
|
||||||
|
|
||||||
@ -979,3 +992,8 @@ void GLGSRender::synchronize_buffers()
|
|||||||
flush_draw_buffers = false;
|
flush_draw_buffers = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GLGSRender::scaled_image_from_memory(rsx::blit_src_info& src, rsx::blit_dst_info& dst, bool interpolate)
|
||||||
|
{
|
||||||
|
return m_gl_texture_cache.upload_scaled_image(src, dst, interpolate, m_rtts);
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "define_new_memleakdetect.h"
|
#include "define_new_memleakdetect.h"
|
||||||
#include "GLProgramBuffer.h"
|
#include "GLProgramBuffer.h"
|
||||||
#include "GLTextOut.h"
|
#include "GLTextOut.h"
|
||||||
|
#include "../rsx_cache.h"
|
||||||
|
|
||||||
#pragma comment(lib, "opengl32.lib")
|
#pragma comment(lib, "opengl32.lib")
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ struct work_item
|
|||||||
std::mutex guard_mutex;
|
std::mutex guard_mutex;
|
||||||
|
|
||||||
u32 address_to_flush = 0;
|
u32 address_to_flush = 0;
|
||||||
gl::texture_cache::cached_rtt_section *section_to_flush = nullptr;
|
gl::texture_cache::cached_texture_section *section_to_flush = nullptr;
|
||||||
|
|
||||||
volatile bool processed = false;
|
volatile bool processed = false;
|
||||||
volatile bool result = false;
|
volatile bool result = false;
|
||||||
@ -57,6 +58,7 @@ private:
|
|||||||
|
|
||||||
rsx::gl::texture m_gl_textures[rsx::limits::fragment_textures_count];
|
rsx::gl::texture m_gl_textures[rsx::limits::fragment_textures_count];
|
||||||
rsx::gl::texture m_gl_vertex_textures[rsx::limits::vertex_textures_count];
|
rsx::gl::texture m_gl_vertex_textures[rsx::limits::vertex_textures_count];
|
||||||
|
gl::sampler_state m_gl_sampler_states[rsx::limits::fragment_textures_count];
|
||||||
|
|
||||||
gl::glsl::program *m_program;
|
gl::glsl::program *m_program;
|
||||||
|
|
||||||
@ -129,7 +131,9 @@ public:
|
|||||||
void set_viewport();
|
void set_viewport();
|
||||||
|
|
||||||
void synchronize_buffers();
|
void synchronize_buffers();
|
||||||
work_item& post_flush_request(u32 address, gl::texture_cache::cached_rtt_section *section);
|
work_item& post_flush_request(u32 address, gl::texture_cache::cached_texture_section *section);
|
||||||
|
|
||||||
|
bool scaled_image_from_memory(rsx::blit_src_info& src_info, rsx::blit_dst_info& dst_info, bool interpolate) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void begin() override;
|
void begin() override;
|
||||||
|
@ -172,6 +172,13 @@ OPENGL_PROC(PFNGLMULTIDRAWARRAYSPROC, MultiDrawArrays);
|
|||||||
|
|
||||||
OPENGL_PROC(PFNGLGETTEXTUREIMAGEEXTPROC, GetTextureImageEXT);
|
OPENGL_PROC(PFNGLGETTEXTUREIMAGEEXTPROC, GetTextureImageEXT);
|
||||||
|
|
||||||
|
//Sampler Objects
|
||||||
|
OPENGL_PROC(PFNGLGENSAMPLERSPROC, GenSamplers);
|
||||||
|
OPENGL_PROC(PFNGLDELETESAMPLERSPROC, DeleteSamplers);
|
||||||
|
OPENGL_PROC(PFNGLBINDSAMPLERPROC, BindSampler);
|
||||||
|
OPENGL_PROC(PFNGLSAMPLERPARAMETERIPROC, SamplerParameteri);
|
||||||
|
OPENGL_PROC(PFNGLSAMPLERPARAMETERFVPROC, SamplerParameterfv);
|
||||||
|
|
||||||
//Texture Buffers
|
//Texture Buffers
|
||||||
OPENGL_PROC(PFNGLTEXBUFFERPROC, TexBuffer);
|
OPENGL_PROC(PFNGLTEXBUFFERPROC, TexBuffer);
|
||||||
OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEEXTPROC, TextureBufferRangeEXT);
|
OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEEXTPROC, TextureBufferRangeEXT);
|
||||||
|
@ -116,7 +116,9 @@ namespace gl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For an address within the texture, extract this sub-section's rect origin
|
// For an address within the texture, extract this sub-section's rect origin
|
||||||
std::tuple<bool, u16, u16> get_texture_subresource(u32 offset)
|
// Checks whether we need to scale the subresource if it is not handled in shader
|
||||||
|
// NOTE1: When surface->real_pitch < rsx_pitch, the surface is assumed to have been scaled to fill the rsx_region
|
||||||
|
std::tuple<bool, u16, u16> get_texture_subresource(u32 offset, bool scale_to_fit)
|
||||||
{
|
{
|
||||||
if (!offset)
|
if (!offset)
|
||||||
{
|
{
|
||||||
@ -132,9 +134,14 @@ namespace gl
|
|||||||
if (!surface_pixel_size)
|
if (!surface_pixel_size)
|
||||||
surface_pixel_size = native_pitch / surface_width;
|
surface_pixel_size = native_pitch / surface_width;
|
||||||
|
|
||||||
u32 pixel_offset = (offset / surface_pixel_size);
|
const u32 y = (offset / rsx_pitch);
|
||||||
u32 y = (pixel_offset / surface_width);
|
u32 x = (offset % rsx_pitch) / surface_pixel_size;
|
||||||
u32 x = (pixel_offset % surface_width);
|
|
||||||
|
if (scale_to_fit)
|
||||||
|
{
|
||||||
|
const f32 x_scale = (f32)rsx_pitch / native_pitch;
|
||||||
|
x = (u32)((f32)x / x_scale);
|
||||||
|
}
|
||||||
|
|
||||||
return std::make_tuple(true, (u16)x, (u16)y);
|
return std::make_tuple(true, (u16)x, (u16)y);
|
||||||
}
|
}
|
||||||
@ -291,18 +298,19 @@ struct surface_subresource
|
|||||||
|
|
||||||
bool is_bound = false;
|
bool is_bound = false;
|
||||||
bool is_depth_surface = false;
|
bool is_depth_surface = false;
|
||||||
|
bool is_clipped = false;
|
||||||
|
|
||||||
surface_subresource() {}
|
surface_subresource() {}
|
||||||
|
|
||||||
surface_subresource(gl::render_target *src, u16 X, u16 Y, u16 W, u16 H, bool _Bound, bool _Depth)
|
surface_subresource(gl::render_target *src, u16 X, u16 Y, u16 W, u16 H, bool _Bound, bool _Depth, bool _Clipped = false)
|
||||||
: surface(src), x(X), y(Y), w(W), h(H), is_bound(_Bound), is_depth_surface(_Depth)
|
: surface(src), x(X), y(Y), w(W), h(H), is_bound(_Bound), is_depth_surface(_Depth), is_clipped(_Clipped)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
class gl_render_targets : public rsx::surface_store<gl_render_target_traits>
|
class gl_render_targets : public rsx::surface_store<gl_render_target_traits>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool surface_overlaps(gl::render_target *surface, u32 surface_address, u32 texaddr, u16 *x, u16 *y)
|
bool surface_overlaps(gl::render_target *surface, u32 surface_address, u32 texaddr, u16 *x, u16 *y, bool scale_to_fit)
|
||||||
{
|
{
|
||||||
bool is_subslice = false;
|
bool is_subslice = false;
|
||||||
u16 x_offset = 0;
|
u16 x_offset = 0;
|
||||||
@ -314,7 +322,7 @@ private:
|
|||||||
u32 offset = texaddr - surface_address;
|
u32 offset = texaddr - surface_address;
|
||||||
if (offset >= 0)
|
if (offset >= 0)
|
||||||
{
|
{
|
||||||
std::tie(is_subslice, x_offset, y_offset) = surface->get_texture_subresource(offset);
|
std::tie(is_subslice, x_offset, y_offset) = surface->get_texture_subresource(offset, scale_to_fit);
|
||||||
if (is_subslice)
|
if (is_subslice)
|
||||||
{
|
{
|
||||||
*x = x_offset;
|
*x = x_offset;
|
||||||
@ -354,7 +362,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
surface_subresource get_surface_subresource_if_applicable(u32 texaddr, u16 requested_width, u16 requested_height, u16 requested_pitch)
|
surface_subresource get_surface_subresource_if_applicable(u32 texaddr, u16 requested_width, u16 requested_height, u16 requested_pitch, bool scale_to_fit =false, bool crop=false)
|
||||||
{
|
{
|
||||||
gl::render_target *surface = nullptr;
|
gl::render_target *surface = nullptr;
|
||||||
bool is_subslice = false;
|
bool is_subslice = false;
|
||||||
@ -366,21 +374,35 @@ public:
|
|||||||
u32 this_address = std::get<0>(tex_info);
|
u32 this_address = std::get<0>(tex_info);
|
||||||
surface = std::get<1>(tex_info).get();
|
surface = std::get<1>(tex_info).get();
|
||||||
|
|
||||||
if (surface_overlaps(surface, this_address, texaddr, &x_offset, &y_offset))
|
if (surface_overlaps(surface, this_address, texaddr, &x_offset, &y_offset, scale_to_fit))
|
||||||
{
|
{
|
||||||
if (surface->get_rsx_pitch() != requested_pitch)
|
if (surface->get_rsx_pitch() != requested_pitch)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto dims = surface->get_dimensions();
|
auto dims = surface->get_dimensions();
|
||||||
|
|
||||||
|
if (scale_to_fit)
|
||||||
|
{
|
||||||
|
f32 pitch_scaling = (f32)requested_pitch / surface->get_native_pitch();
|
||||||
|
requested_width /= pitch_scaling;
|
||||||
|
}
|
||||||
|
|
||||||
if (fits(surface, dims, x_offset, y_offset, requested_width, requested_height))
|
if (fits(surface, dims, x_offset, y_offset, requested_width, requested_height))
|
||||||
return{ surface, x_offset, y_offset, requested_width, requested_height, is_bound(this_address, false), false };
|
return{ surface, x_offset, y_offset, requested_width, requested_height, is_bound(this_address, false), false };
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (crop) //Forcefully fit the requested region by clipping and scaling
|
||||||
|
{
|
||||||
|
u16 remaining_width = dims.first - x_offset;
|
||||||
|
u16 remaining_height = dims.second - y_offset;
|
||||||
|
|
||||||
|
return{ surface, x_offset, y_offset, remaining_width, remaining_height, is_bound(this_address, false), false, true };
|
||||||
|
}
|
||||||
|
|
||||||
if (dims.first >= requested_width && dims.second >= requested_height)
|
if (dims.first >= requested_width && dims.second >= requested_height)
|
||||||
{
|
{
|
||||||
LOG_WARNING(RSX, "Overlapping surface exceeds bounds; returning full surface region");
|
LOG_WARNING(RSX, "Overlapping surface exceeds bounds; returning full surface region");
|
||||||
return{ surface, 0, 0, requested_width, requested_height, is_bound(this_address, false), false };
|
return{ surface, 0, 0, requested_width, requested_height, is_bound(this_address, false), false, true };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,21 +414,35 @@ public:
|
|||||||
u32 this_address = std::get<0>(tex_info);
|
u32 this_address = std::get<0>(tex_info);
|
||||||
surface = std::get<1>(tex_info).get();
|
surface = std::get<1>(tex_info).get();
|
||||||
|
|
||||||
if (surface_overlaps(surface, this_address, texaddr, &x_offset, &y_offset))
|
if (surface_overlaps(surface, this_address, texaddr, &x_offset, &y_offset, scale_to_fit))
|
||||||
{
|
{
|
||||||
if (surface->get_rsx_pitch() != requested_pitch)
|
if (surface->get_rsx_pitch() != requested_pitch)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto dims = surface->get_dimensions();
|
auto dims = surface->get_dimensions();
|
||||||
|
|
||||||
|
if (scale_to_fit)
|
||||||
|
{
|
||||||
|
f32 pitch_scaling = (f32)requested_pitch / surface->get_native_pitch();
|
||||||
|
requested_width /= pitch_scaling;
|
||||||
|
}
|
||||||
|
|
||||||
if (fits(surface, dims, x_offset, y_offset, requested_width, requested_height))
|
if (fits(surface, dims, x_offset, y_offset, requested_width, requested_height))
|
||||||
return{ surface, x_offset, y_offset, requested_width, requested_height, is_bound(this_address, true), true };
|
return{ surface, x_offset, y_offset, requested_width, requested_height, is_bound(this_address, true), true };
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (crop) //Forcefully fit the requested region by clipping and scaling
|
||||||
|
{
|
||||||
|
u16 remaining_width = dims.first - x_offset;
|
||||||
|
u16 remaining_height = dims.second - y_offset;
|
||||||
|
|
||||||
|
return{ surface, x_offset, y_offset, remaining_width, remaining_height, is_bound(this_address, true), true, true };
|
||||||
|
}
|
||||||
|
|
||||||
if (dims.first >= requested_width && dims.second >= requested_height)
|
if (dims.first >= requested_width && dims.second >= requested_height)
|
||||||
{
|
{
|
||||||
LOG_WARNING(RSX, "Overlapping depth surface exceeds bounds; returning full surface region");
|
LOG_WARNING(RSX, "Overlapping depth surface exceeds bounds; returning full surface region");
|
||||||
return{ surface, 0, 0, requested_width, requested_height, is_bound(this_address, true), true };
|
return{ surface, 0, 0, requested_width, requested_height, is_bound(this_address, true), true, true };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,116 @@ namespace gl
|
|||||||
}
|
}
|
||||||
fmt::throw_exception("Compressed or unknown texture format 0x%x" HERE, texture_format);
|
fmt::throw_exception("Compressed or unknown texture format 0x%x" HERE, texture_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLenum wrap_mode(rsx::texture_wrap_mode wrap)
|
||||||
|
{
|
||||||
|
switch (wrap)
|
||||||
|
{
|
||||||
|
case rsx::texture_wrap_mode::wrap: return GL_REPEAT;
|
||||||
|
case rsx::texture_wrap_mode::mirror: return GL_MIRRORED_REPEAT;
|
||||||
|
case rsx::texture_wrap_mode::clamp_to_edge: return GL_CLAMP_TO_EDGE;
|
||||||
|
case rsx::texture_wrap_mode::border: return GL_CLAMP_TO_BORDER;
|
||||||
|
case rsx::texture_wrap_mode::clamp: return GL_CLAMP_TO_EDGE;
|
||||||
|
case rsx::texture_wrap_mode::mirror_once_clamp_to_edge: return GL_MIRROR_CLAMP_TO_EDGE_EXT;
|
||||||
|
case rsx::texture_wrap_mode::mirror_once_border: return GL_MIRROR_CLAMP_TO_BORDER_EXT;
|
||||||
|
case rsx::texture_wrap_mode::mirror_once_clamp: return GL_MIRROR_CLAMP_EXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_ERROR(RSX, "Texture wrap error: bad wrap (%d)", (u32)wrap);
|
||||||
|
return GL_REPEAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
float max_aniso(rsx::texture_max_anisotropy aniso)
|
||||||
|
{
|
||||||
|
switch (aniso)
|
||||||
|
{
|
||||||
|
case rsx::texture_max_anisotropy::x1: return 1.0f;
|
||||||
|
case rsx::texture_max_anisotropy::x2: return 2.0f;
|
||||||
|
case rsx::texture_max_anisotropy::x4: return 4.0f;
|
||||||
|
case rsx::texture_max_anisotropy::x6: return 6.0f;
|
||||||
|
case rsx::texture_max_anisotropy::x8: return 8.0f;
|
||||||
|
case rsx::texture_max_anisotropy::x10: return 10.0f;
|
||||||
|
case rsx::texture_max_anisotropy::x12: return 12.0f;
|
||||||
|
case rsx::texture_max_anisotropy::x16: return 16.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_ERROR(RSX, "Texture anisotropy error: bad max aniso (%d)", (u32)aniso);
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tex_min_filter(rsx::texture_minify_filter min_filter)
|
||||||
|
{
|
||||||
|
switch (min_filter)
|
||||||
|
{
|
||||||
|
case rsx::texture_minify_filter::nearest: return GL_NEAREST;
|
||||||
|
case rsx::texture_minify_filter::linear: return GL_LINEAR;
|
||||||
|
case rsx::texture_minify_filter::nearest_nearest: return GL_NEAREST_MIPMAP_NEAREST;
|
||||||
|
case rsx::texture_minify_filter::linear_nearest: return GL_LINEAR_MIPMAP_NEAREST;
|
||||||
|
case rsx::texture_minify_filter::nearest_linear: return GL_NEAREST_MIPMAP_LINEAR;
|
||||||
|
case rsx::texture_minify_filter::linear_linear: return GL_LINEAR_MIPMAP_LINEAR;
|
||||||
|
case rsx::texture_minify_filter::convolution_min: return GL_LINEAR_MIPMAP_LINEAR;
|
||||||
|
}
|
||||||
|
fmt::throw_exception("Unknow min filter" HERE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tex_mag_filter(rsx::texture_magnify_filter mag_filter)
|
||||||
|
{
|
||||||
|
switch (mag_filter)
|
||||||
|
{
|
||||||
|
case rsx::texture_magnify_filter::nearest: return GL_NEAREST;
|
||||||
|
case rsx::texture_magnify_filter::linear: return GL_LINEAR;
|
||||||
|
case rsx::texture_magnify_filter::convolution_mag: return GL_LINEAR;
|
||||||
|
}
|
||||||
|
fmt::throw_exception("Unknow mag filter" HERE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Apply sampler state settings
|
||||||
|
void sampler_state::apply(rsx::fragment_texture& tex)
|
||||||
|
{
|
||||||
|
const f32 border_color = (f32)tex.border_color() / 255;
|
||||||
|
const f32 border_color_array[] = { border_color, border_color, border_color, border_color };
|
||||||
|
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_S, wrap_mode(tex.wrap_s()));
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_T, wrap_mode(tex.wrap_t()));
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_R, wrap_mode(tex.wrap_r()));
|
||||||
|
glSamplerParameterfv(samplerHandle, GL_TEXTURE_BORDER_COLOR, border_color_array);
|
||||||
|
|
||||||
|
if (tex.get_exact_mipmap_count() <= 1)
|
||||||
|
{
|
||||||
|
GLint min_filter = tex_min_filter(tex.min_filter());
|
||||||
|
|
||||||
|
if (min_filter != GL_LINEAR && min_filter != GL_NEAREST)
|
||||||
|
{
|
||||||
|
switch (min_filter)
|
||||||
|
{
|
||||||
|
case GL_NEAREST_MIPMAP_NEAREST:
|
||||||
|
case GL_NEAREST_MIPMAP_LINEAR:
|
||||||
|
min_filter = GL_NEAREST; break;
|
||||||
|
case GL_LINEAR_MIPMAP_NEAREST:
|
||||||
|
case GL_LINEAR_MIPMAP_LINEAR:
|
||||||
|
min_filter = GL_LINEAR; break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR(RSX, "No mipmap fallback defined for rsx_min_filter = 0x%X", (u32)tex.min_filter());
|
||||||
|
min_filter = GL_NEAREST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_FILTER, min_filter);
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_LOD_BIAS, 0.);
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_LOD, 0);
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_MAX_LOD, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_FILTER, tex_min_filter(tex.min_filter()));
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_LOD_BIAS, tex.bias());
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_LOD, (tex.min_lod() >> 8));
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_MAX_LOD, (tex.max_lod() >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_MAG_FILTER, tex_mag_filter(tex.mag_filter()));
|
||||||
|
glSamplerParameteri(samplerHandle, GL_TEXTURE_MAX_ANISOTROPY_EXT, ::gl::max_aniso(tex.max_aniso()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -182,32 +292,6 @@ namespace rsx
|
|||||||
{
|
{
|
||||||
namespace gl
|
namespace gl
|
||||||
{
|
{
|
||||||
int gl_tex_min_filter(rsx::texture_minify_filter min_filter)
|
|
||||||
{
|
|
||||||
switch (min_filter)
|
|
||||||
{
|
|
||||||
case rsx::texture_minify_filter::nearest: return GL_NEAREST;
|
|
||||||
case rsx::texture_minify_filter::linear: return GL_LINEAR;
|
|
||||||
case rsx::texture_minify_filter::nearest_nearest: return GL_NEAREST_MIPMAP_NEAREST;
|
|
||||||
case rsx::texture_minify_filter::linear_nearest: return GL_LINEAR_MIPMAP_NEAREST;
|
|
||||||
case rsx::texture_minify_filter::nearest_linear: return GL_NEAREST_MIPMAP_LINEAR;
|
|
||||||
case rsx::texture_minify_filter::linear_linear: return GL_LINEAR_MIPMAP_LINEAR;
|
|
||||||
case rsx::texture_minify_filter::convolution_min: return GL_LINEAR_MIPMAP_LINEAR;
|
|
||||||
}
|
|
||||||
fmt::throw_exception("Unknow min filter" HERE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int gl_tex_mag_filter(rsx::texture_magnify_filter mag_filter)
|
|
||||||
{
|
|
||||||
switch (mag_filter)
|
|
||||||
{
|
|
||||||
case rsx::texture_magnify_filter::nearest: return GL_NEAREST;
|
|
||||||
case rsx::texture_magnify_filter::linear: return GL_LINEAR;
|
|
||||||
case rsx::texture_magnify_filter::convolution_mag: return GL_LINEAR;
|
|
||||||
}
|
|
||||||
fmt::throw_exception("Unknow mag filter" HERE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const int gl_tex_zfunc[] =
|
static const int gl_tex_zfunc[] =
|
||||||
{
|
{
|
||||||
GL_NEVER,
|
GL_NEVER,
|
||||||
@ -230,42 +314,6 @@ namespace rsx
|
|||||||
glGenTextures(1, &m_id);
|
glGenTextures(1, &m_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
int texture::gl_wrap(rsx::texture_wrap_mode wrap)
|
|
||||||
{
|
|
||||||
switch (wrap)
|
|
||||||
{
|
|
||||||
case rsx::texture_wrap_mode::wrap: return GL_REPEAT;
|
|
||||||
case rsx::texture_wrap_mode::mirror: return GL_MIRRORED_REPEAT;
|
|
||||||
case rsx::texture_wrap_mode::clamp_to_edge: return GL_CLAMP_TO_EDGE;
|
|
||||||
case rsx::texture_wrap_mode::border: return GL_CLAMP_TO_BORDER;
|
|
||||||
case rsx::texture_wrap_mode::clamp: return GL_CLAMP_TO_EDGE;
|
|
||||||
case rsx::texture_wrap_mode::mirror_once_clamp_to_edge: return GL_MIRROR_CLAMP_TO_EDGE_EXT;
|
|
||||||
case rsx::texture_wrap_mode::mirror_once_border: return GL_MIRROR_CLAMP_TO_BORDER_EXT;
|
|
||||||
case rsx::texture_wrap_mode::mirror_once_clamp: return GL_MIRROR_CLAMP_EXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(RSX, "Texture wrap error: bad wrap (%d)", (u32)wrap);
|
|
||||||
return GL_REPEAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
float texture::max_aniso(rsx::texture_max_anisotropy aniso)
|
|
||||||
{
|
|
||||||
switch (aniso)
|
|
||||||
{
|
|
||||||
case rsx::texture_max_anisotropy::x1: return 1.0f;
|
|
||||||
case rsx::texture_max_anisotropy::x2: return 2.0f;
|
|
||||||
case rsx::texture_max_anisotropy::x4: return 4.0f;
|
|
||||||
case rsx::texture_max_anisotropy::x6: return 6.0f;
|
|
||||||
case rsx::texture_max_anisotropy::x8: return 8.0f;
|
|
||||||
case rsx::texture_max_anisotropy::x10: return 10.0f;
|
|
||||||
case rsx::texture_max_anisotropy::x12: return 12.0f;
|
|
||||||
case rsx::texture_max_anisotropy::x16: return 16.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR(RSX, "Texture anisotropy error: bad max aniso (%d)", (u32)aniso);
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 texture::get_pitch_modifier(u32 format)
|
u16 texture::get_pitch_modifier(u32 format)
|
||||||
{
|
{
|
||||||
switch (format)
|
switch (format)
|
||||||
@ -535,49 +583,7 @@ namespace rsx
|
|||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, remap_values[2]);
|
__glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, remap_values[2]);
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, remap_values[3]);
|
__glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, remap_values[3]);
|
||||||
|
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_S, gl_wrap(tex.wrap_s()));
|
//The rest of sampler state is now handled by sampler state objects
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_T, gl_wrap(tex.wrap_t()));
|
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_R, gl_wrap(tex.wrap_r()));
|
|
||||||
|
|
||||||
if (tex.get_exact_mipmap_count() <= 1 || m_target == GL_TEXTURE_RECTANGLE)
|
|
||||||
{
|
|
||||||
GLint min_filter = gl_tex_min_filter(tex.min_filter());
|
|
||||||
|
|
||||||
if (min_filter != GL_LINEAR && min_filter != GL_NEAREST)
|
|
||||||
{
|
|
||||||
LOG_WARNING(RSX, "Texture %d, target 0x%x, requesting mipmap filtering without any mipmaps set!", m_id, m_target);
|
|
||||||
|
|
||||||
switch (min_filter)
|
|
||||||
{
|
|
||||||
case GL_NEAREST_MIPMAP_NEAREST:
|
|
||||||
case GL_NEAREST_MIPMAP_LINEAR:
|
|
||||||
min_filter = GL_NEAREST; break;
|
|
||||||
case GL_LINEAR_MIPMAP_NEAREST:
|
|
||||||
case GL_LINEAR_MIPMAP_LINEAR:
|
|
||||||
min_filter = GL_LINEAR; break;
|
|
||||||
default:
|
|
||||||
LOG_ERROR(RSX, "No mipmap fallback defined for rsx_min_filter = 0x%X", (u32)tex.min_filter());
|
|
||||||
min_filter = GL_NEAREST;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, min_filter);
|
|
||||||
|
|
||||||
__glcheck glTexParameterf(m_target, GL_TEXTURE_LOD_BIAS, 0.);
|
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_MIN_LOD, 0);
|
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_MAX_LOD, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, gl_tex_min_filter(tex.min_filter()));
|
|
||||||
|
|
||||||
__glcheck glTexParameterf(m_target, GL_TEXTURE_LOD_BIAS, tex.bias());
|
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_MIN_LOD, (tex.min_lod() >> 8));
|
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_MAX_LOD, (tex.max_lod() >> 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
__glcheck glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, gl_tex_mag_filter(tex.mag_filter()));
|
|
||||||
__glcheck glTexParameterf(m_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso(tex.max_aniso()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void texture::init(int index, rsx::vertex_texture& tex)
|
void texture::init(int index, rsx::vertex_texture& tex)
|
||||||
|
@ -5,7 +5,42 @@ namespace rsx
|
|||||||
{
|
{
|
||||||
class vertex_texture;
|
class vertex_texture;
|
||||||
class fragment_texture;
|
class fragment_texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace gl
|
||||||
|
{
|
||||||
|
GLenum get_sized_internal_format(u32 gcm_format);
|
||||||
|
std::tuple<GLenum, GLenum> get_format_type(u32 texture_format);
|
||||||
|
GLenum wrap_mode(rsx::texture_wrap_mode wrap);
|
||||||
|
float max_aniso(rsx::texture_max_anisotropy aniso);
|
||||||
|
|
||||||
|
class sampler_state
|
||||||
|
{
|
||||||
|
GLuint samplerHandle = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void create()
|
||||||
|
{
|
||||||
|
glGenSamplers(1, &samplerHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove()
|
||||||
|
{
|
||||||
|
glDeleteSamplers(1, &samplerHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind(int index)
|
||||||
|
{
|
||||||
|
glBindSampler(index, samplerHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply(rsx::fragment_texture& tex);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace rsx
|
||||||
|
{
|
||||||
namespace gl
|
namespace gl
|
||||||
{
|
{
|
||||||
class texture
|
class texture
|
||||||
@ -16,28 +51,6 @@ namespace rsx
|
|||||||
public:
|
public:
|
||||||
void create();
|
void create();
|
||||||
|
|
||||||
int gl_wrap(rsx::texture_wrap_mode in);
|
|
||||||
|
|
||||||
float max_aniso(rsx::texture_max_anisotropy aniso);
|
|
||||||
|
|
||||||
inline static u8 convert_4_to_8(u8 v)
|
|
||||||
{
|
|
||||||
// Swizzle bits: 00001234 -> 12341234
|
|
||||||
return (v << 4) | (v);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static u8 convert_5_to_8(u8 v)
|
|
||||||
{
|
|
||||||
// Swizzle bits: 00012345 -> 12345123
|
|
||||||
return (v << 3) | (v >> 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static u8 convert_6_to_8(u8 v)
|
|
||||||
{
|
|
||||||
// Swizzle bits: 00123456 -> 12345612
|
|
||||||
return (v << 2) | (v >> 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(int index, rsx::fragment_texture& tex);
|
void init(int index, rsx::fragment_texture& tex);
|
||||||
void init(int index, rsx::vertex_texture& tex);
|
void init(int index, rsx::vertex_texture& tex);
|
||||||
|
|
||||||
@ -64,9 +77,3 @@ namespace rsx
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace gl
|
|
||||||
{
|
|
||||||
GLenum get_sized_internal_format(u32 gcm_format);
|
|
||||||
std::tuple<GLenum, GLenum> get_format_type(u32 texture_format);
|
|
||||||
}
|
|
||||||
|
@ -9,25 +9,25 @@ namespace gl
|
|||||||
{
|
{
|
||||||
bool texture_cache::flush_section(u32 address)
|
bool texture_cache::flush_section(u32 address)
|
||||||
{
|
{
|
||||||
if (address < rtt_cache_range.first ||
|
if (address < no_access_range.first ||
|
||||||
address >= rtt_cache_range.second)
|
address >= no_access_range.second)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool post_task = false;
|
bool post_task = false;
|
||||||
cached_rtt_section* section_to_post = nullptr;
|
cached_texture_section* section_to_post = nullptr;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_section_mutex);
|
std::lock_guard<std::mutex> lock(m_section_mutex);
|
||||||
|
|
||||||
for (cached_rtt_section &rtt : m_rtt_cache)
|
for (cached_texture_section &tex : no_access_memory_sections)
|
||||||
{
|
{
|
||||||
if (rtt.is_dirty()) continue;
|
if (tex.is_dirty()) continue;
|
||||||
|
|
||||||
if (rtt.is_locked() && rtt.overlaps(address))
|
if (tex.is_locked() && tex.overlaps(address))
|
||||||
{
|
{
|
||||||
if (rtt.is_flushed())
|
if (tex.is_flushed())
|
||||||
{
|
{
|
||||||
LOG_WARNING(RSX, "Section matches range, but marked as already flushed!, 0x%X+0x%X", rtt.get_section_base(), rtt.get_section_size());
|
LOG_WARNING(RSX, "Section matches range, but marked as already flushed!, 0x%X+0x%X", tex.get_section_base(), tex.get_section_size());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,11 +36,11 @@ namespace gl
|
|||||||
if (std::this_thread::get_id() != m_renderer_thread)
|
if (std::this_thread::get_id() != m_renderer_thread)
|
||||||
{
|
{
|
||||||
post_task = true;
|
post_task = true;
|
||||||
section_to_post = &rtt;
|
section_to_post = &tex;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtt.flush();
|
tex.flush();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
|||||||
#include <rsx_decompiler.h>
|
#include <rsx_decompiler.h>
|
||||||
#include "Utilities/VirtualMemory.h"
|
#include "Utilities/VirtualMemory.h"
|
||||||
#include "Emu/Memory/vm.h"
|
#include "Emu/Memory/vm.h"
|
||||||
|
#include "gcm_enums.h"
|
||||||
|
|
||||||
namespace rsx
|
namespace rsx
|
||||||
{
|
{
|
||||||
@ -37,14 +38,18 @@ namespace rsx
|
|||||||
u16 offset_y;
|
u16 offset_y;
|
||||||
u16 width;
|
u16 width;
|
||||||
u16 height;
|
u16 height;
|
||||||
u16 slice;
|
u16 slice_h;
|
||||||
u16 pitch;
|
u16 pitch;
|
||||||
void *pixels;
|
void *pixels;
|
||||||
|
|
||||||
|
u32 rsx_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct blit_dst_info
|
struct blit_dst_info
|
||||||
{
|
{
|
||||||
blit_engine::transfer_destination_format format;
|
blit_engine::transfer_destination_format format;
|
||||||
|
u16 offset_x;
|
||||||
|
u16 offset_y;
|
||||||
u16 width;
|
u16 width;
|
||||||
u16 height;
|
u16 height;
|
||||||
u16 pitch;
|
u16 pitch;
|
||||||
@ -52,8 +57,11 @@ namespace rsx
|
|||||||
u16 clip_y;
|
u16 clip_y;
|
||||||
u16 clip_width;
|
u16 clip_width;
|
||||||
u16 clip_height;
|
u16 clip_height;
|
||||||
|
|
||||||
bool swizzled;
|
bool swizzled;
|
||||||
void *pixels;
|
void *pixels;
|
||||||
|
|
||||||
|
u32 rsx_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
class shaders_cache
|
class shaders_cache
|
||||||
@ -107,26 +115,9 @@ namespace rsx
|
|||||||
bool locked = false;
|
bool locked = false;
|
||||||
bool dirty = false;
|
bool dirty = false;
|
||||||
|
|
||||||
bool region_overlaps(u32 base1, u32 limit1, u32 base2, u32 limit2)
|
inline bool region_overlaps(u32 base1, u32 limit1, u32 base2, u32 limit2)
|
||||||
{
|
{
|
||||||
//Check for memory area overlap. unlock page(s) if needed and add this index to array.
|
return (base1 < limit2 && base2 < limit1);
|
||||||
//Axis separation test
|
|
||||||
const u32 &block_start = base1;
|
|
||||||
const u32 block_end = limit1;
|
|
||||||
|
|
||||||
if (limit2 < block_start) return false;
|
|
||||||
if (base2 > block_end) return false;
|
|
||||||
|
|
||||||
u32 min_separation = (limit2 - base2) + (limit1 - base1);
|
|
||||||
u32 range_limit = (block_end > limit2) ? block_end : limit2;
|
|
||||||
u32 range_base = (block_start < base2) ? block_start : base2;
|
|
||||||
|
|
||||||
u32 actual_separation = (range_limit - range_base);
|
|
||||||
|
|
||||||
if (actual_separation < min_separation)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -171,6 +162,19 @@ namespace rsx
|
|||||||
return (locked_address_base <= address && (address - locked_address_base) < locked_address_range);
|
return (locked_address_base <= address && (address - locked_address_base) < locked_address_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if range overlaps with this section.
|
||||||
|
* ignore_protection_range - if true, the test should not check against the aligned protection range, instead
|
||||||
|
* tests against actual range of contents in memory
|
||||||
|
*/
|
||||||
|
bool overlaps(std::pair<u32, u32> range, bool ignore_protection_range)
|
||||||
|
{
|
||||||
|
if (!ignore_protection_range)
|
||||||
|
return region_overlaps(locked_address_base, locked_address_base + locked_address_range, range.first, range.first + range.second);
|
||||||
|
else
|
||||||
|
return region_overlaps(cpu_address_base, cpu_address_base + cpu_address_range, range.first, range.first + range.second);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the page containing the address tramples this section. Also compares a former trampled page range to compare
|
* Check if the page containing the address tramples this section. Also compares a former trampled page range to compare
|
||||||
* If true, returns the range <min, max> with updated invalid range
|
* If true, returns the range <min, max> with updated invalid range
|
||||||
|
@ -573,29 +573,41 @@ namespace rsx
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blit_src_info src_info;
|
if (dst_dma == CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER)
|
||||||
blit_dst_info dst_info;
|
{
|
||||||
|
//For now, only use this for actual scaled images, there are use cases that should not go through 3d engine, e.g program ucode transfer
|
||||||
|
//TODO: Figure out more instances where we can use this without problems
|
||||||
|
|
||||||
src_info.format = src_color_format;
|
blit_src_info src_info;
|
||||||
src_info.width = in_w;
|
blit_dst_info dst_info;
|
||||||
src_info.height = in_h;
|
|
||||||
src_info.pitch = in_pitch;
|
|
||||||
src_info.slice = slice_h;
|
|
||||||
src_info.pixels = pixels_src;
|
|
||||||
|
|
||||||
dst_info.format = dst_color_format;
|
src_info.format = src_color_format;
|
||||||
dst_info.width = convert_w;
|
src_info.width = in_w;
|
||||||
dst_info.height = convert_h;
|
src_info.height = in_h;
|
||||||
dst_info.clip_x = clip_x;
|
src_info.pitch = in_pitch;
|
||||||
dst_info.clip_y = clip_y;
|
src_info.slice_h = slice_h;
|
||||||
dst_info.clip_width = clip_w;
|
src_info.offset_x = in_x;
|
||||||
dst_info.clip_height = clip_h;
|
src_info.offset_y = in_y;
|
||||||
dst_info.pitch = in_pitch;
|
src_info.pixels = pixels_src;
|
||||||
dst_info.pixels = pixels_dst;
|
src_info.rsx_address = get_address(src_offset, src_dma);
|
||||||
dst_info.swizzled = (method_registers.blit_engine_context_surface() == blit_engine::context_surface::swizzle2d);
|
|
||||||
|
|
||||||
if (rsx->scaled_image_from_memory(src_info, dst_info, in_inter == blit_engine::transfer_interpolator::foh))
|
dst_info.format = dst_color_format;
|
||||||
return;
|
dst_info.width = convert_w;
|
||||||
|
dst_info.height = convert_h;
|
||||||
|
dst_info.clip_x = clip_x;
|
||||||
|
dst_info.clip_y = clip_y;
|
||||||
|
dst_info.clip_width = clip_w;
|
||||||
|
dst_info.clip_height = clip_h;
|
||||||
|
dst_info.offset_x = out_x;
|
||||||
|
dst_info.offset_y = out_y;
|
||||||
|
dst_info.pitch = out_pitch;
|
||||||
|
dst_info.pixels = pixels_dst;
|
||||||
|
dst_info.rsx_address = get_address(dst_offset, dst_dma);
|
||||||
|
dst_info.swizzled = (method_registers.blit_engine_context_surface() == blit_engine::context_surface::swizzle2d);
|
||||||
|
|
||||||
|
if (rsx->scaled_image_from_memory(src_info, dst_info, in_inter == blit_engine::transfer_interpolator::foh))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (method_registers.blit_engine_context_surface() != blit_engine::context_surface::swizzle2d)
|
if (method_registers.blit_engine_context_surface() != blit_engine::context_surface::swizzle2d)
|
||||||
{
|
{
|
||||||
|
@ -30,12 +30,15 @@ namespace rsx
|
|||||||
|
|
||||||
void clip_image(u8 *dst, const u8 *src, int clip_x, int clip_y, int clip_w, int clip_h, int bpp, int src_pitch, int dst_pitch)
|
void clip_image(u8 *dst, const u8 *src, int clip_x, int clip_y, int clip_w, int clip_h, int bpp, int src_pitch, int dst_pitch)
|
||||||
{
|
{
|
||||||
|
u8 *pixels_src = (u8*)src + clip_y * src_pitch + clip_x * bpp;
|
||||||
|
u8 *pixels_dst = dst;
|
||||||
|
const u32 row_length = clip_w * bpp;
|
||||||
|
|
||||||
for (int y = 0; y < clip_h; ++y)
|
for (int y = 0; y < clip_h; ++y)
|
||||||
{
|
{
|
||||||
u8 *dst_row = dst + y * dst_pitch;
|
std::memmove(pixels_dst, pixels_src, row_length);
|
||||||
const u8 *src_row = src + (y + clip_y) * src_pitch + clip_x * bpp;
|
pixels_src += src_pitch;
|
||||||
|
pixels_dst += dst_pitch;
|
||||||
std::memmove(dst_row, src_row, clip_w * bpp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user