mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-03-10 07:24:54 +01:00
vk: De-sphaggetify texture handling
This commit is contained in:
parent
9e7268ed6d
commit
b9bdbfa55b
|
|
@ -263,7 +263,7 @@ void VKGSRender::load_texture_env()
|
|||
{
|
||||
// Load textures
|
||||
bool check_for_cyclic_refs = false;
|
||||
auto check_surface_cache_sampler = [&](auto descriptor, const auto& tex)
|
||||
auto check_surface_cache_sampler_valid = [&](auto descriptor, const auto& tex)
|
||||
{
|
||||
if (!m_texture_cache.test_if_descriptor_expired(*m_current_command_buffer, m_rtts, descriptor, tex))
|
||||
{
|
||||
|
|
@ -286,242 +286,259 @@ void VKGSRender::load_texture_env()
|
|||
for (u32 textures_ref = current_fp_metadata.referenced_textures_mask, i = 0; textures_ref; textures_ref >>= 1, ++i)
|
||||
{
|
||||
if (!(textures_ref & 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fs_sampler_state[i])
|
||||
{
|
||||
fs_sampler_state[i] = std::make_unique<vk::texture_cache::sampled_image_descriptor>();
|
||||
}
|
||||
|
||||
auto sampler_state = static_cast<vk::texture_cache::sampled_image_descriptor*>(fs_sampler_state[i].get());
|
||||
const auto& tex = rsx::method_registers.fragment_textures[i];
|
||||
const auto previous_format_class = fs_sampler_state[i]->format_class;
|
||||
|
||||
if (m_samplers_dirty || m_textures_dirty[i] || !check_surface_cache_sampler(sampler_state, tex))
|
||||
if (!m_samplers_dirty &&
|
||||
!m_textures_dirty[i] &&
|
||||
check_surface_cache_sampler_valid(sampler_state, tex))
|
||||
{
|
||||
if (tex.enabled())
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool is_sampler_dirty = m_textures_dirty[i];
|
||||
m_textures_dirty[i] = false;
|
||||
|
||||
if (!tex.enabled())
|
||||
{
|
||||
*sampler_state = {};
|
||||
continue;
|
||||
}
|
||||
|
||||
*sampler_state = m_texture_cache.upload_texture(*m_current_command_buffer, tex, m_rtts);
|
||||
if (!sampler_state->validate())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sampler_state->format_ex = tex.format_ex();
|
||||
|
||||
if (sampler_state->is_cyclic_reference)
|
||||
{
|
||||
check_for_cyclic_refs |= true;
|
||||
}
|
||||
|
||||
if (!is_sampler_dirty && sampler_state->format_class != previous_format_class)
|
||||
{
|
||||
// Host details changed but RSX is not aware
|
||||
m_graphics_state |= rsx::fragment_program_state_dirty;
|
||||
}
|
||||
|
||||
if (!is_sampler_dirty && fs_sampler_handles[i])
|
||||
{
|
||||
// Nothing to change, use cached sampler
|
||||
continue;
|
||||
}
|
||||
|
||||
VkFilter mag_filter;
|
||||
vk::minification_filter min_filter;
|
||||
f32 min_lod = 0.f, max_lod = 0.f;
|
||||
f32 lod_bias = 0.f;
|
||||
|
||||
const u32 texture_format = sampler_state->format_ex.format();
|
||||
VkBool32 compare_enabled = VK_FALSE;
|
||||
VkCompareOp depth_compare_mode = VK_COMPARE_OP_NEVER;
|
||||
|
||||
if (texture_format >= CELL_GCM_TEXTURE_DEPTH24_D8 && texture_format <= CELL_GCM_TEXTURE_DEPTH16_FLOAT)
|
||||
{
|
||||
compare_enabled = VK_TRUE;
|
||||
depth_compare_mode = vk::get_compare_func(tex.zfunc(), true);
|
||||
}
|
||||
|
||||
const f32 af_level = vk::max_aniso(tex.max_aniso());
|
||||
const auto wrap_s = vk::vk_wrap_mode(tex.wrap_s());
|
||||
const auto wrap_t = vk::vk_wrap_mode(tex.wrap_t());
|
||||
const auto wrap_r = vk::vk_wrap_mode(tex.wrap_r());
|
||||
|
||||
// NOTE: In vulkan, the border color can bypass the sample swizzle stage.
|
||||
// Check the device properties to determine whether to pre-swizzle the colors or not.
|
||||
const auto border_color = rsx::is_border_clamped_texture(tex)
|
||||
? vk::border_color_t(get_border_color(tex))
|
||||
: vk::border_color_t(VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK);
|
||||
|
||||
// Check if non-point filtering can even be used on this format
|
||||
bool can_sample_linear;
|
||||
if (sampler_state->format_class == RSX_FORMAT_CLASS_COLOR) [[likely]]
|
||||
{
|
||||
// Most PS3-like formats can be linearly filtered without problem
|
||||
// Exclude textures that require SNORM conversion however
|
||||
can_sample_linear = (sampler_state->format_ex.texel_remap_control & rsx::texture_control_bits::SEXT_MASK) == 0;
|
||||
}
|
||||
else if (sampler_state->format_class != rsx::classify_format(texture_format) &&
|
||||
(texture_format == CELL_GCM_TEXTURE_A8R8G8B8 || texture_format == CELL_GCM_TEXTURE_D8R8G8B8))
|
||||
{
|
||||
// Depth format redirected to BGRA8 resample stage. Do not filter to avoid bits leaking
|
||||
can_sample_linear = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not all GPUs support linear filtering of depth formats
|
||||
const auto vk_format = sampler_state->image_handle ? sampler_state->image_handle->image()->format() :
|
||||
vk::get_compatible_sampler_format(m_device->get_formats_support(), sampler_state->external_subresource_desc.gcm_format);
|
||||
|
||||
can_sample_linear = m_device->get_format_properties(vk_format).optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
||||
}
|
||||
|
||||
const auto mipmap_count = tex.get_exact_mipmap_count();
|
||||
min_filter = vk::get_min_filter(tex.min_filter());
|
||||
|
||||
if (can_sample_linear)
|
||||
{
|
||||
mag_filter = vk::get_mag_filter(tex.mag_filter());
|
||||
}
|
||||
else
|
||||
{
|
||||
mag_filter = VK_FILTER_NEAREST;
|
||||
min_filter.filter = VK_FILTER_NEAREST;
|
||||
}
|
||||
|
||||
if (min_filter.sample_mipmaps && mipmap_count > 1)
|
||||
{
|
||||
f32 actual_mipmaps;
|
||||
if (sampler_state->upload_context == rsx::texture_upload_context::shader_read)
|
||||
{
|
||||
*sampler_state = m_texture_cache.upload_texture(*m_current_command_buffer, tex, m_rtts);
|
||||
actual_mipmaps = static_cast<f32>(mipmap_count);
|
||||
}
|
||||
else if (sampler_state->external_subresource_desc.op == rsx::deferred_request_command::mipmap_gather)
|
||||
{
|
||||
// Clamp min and max lod
|
||||
actual_mipmaps = static_cast<f32>(sampler_state->external_subresource_desc.sections_to_copy.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
*sampler_state = {};
|
||||
actual_mipmaps = 1.f;
|
||||
}
|
||||
|
||||
if (sampler_state->validate())
|
||||
if (actual_mipmaps > 1.f)
|
||||
{
|
||||
sampler_state->format_ex = tex.format_ex();
|
||||
min_lod = tex.min_lod();
|
||||
max_lod = tex.max_lod();
|
||||
lod_bias = tex.bias();
|
||||
|
||||
if (sampler_state->is_cyclic_reference)
|
||||
min_lod = std::min(min_lod, actual_mipmaps - 1.f);
|
||||
max_lod = std::min(max_lod, actual_mipmaps - 1.f);
|
||||
|
||||
if (min_filter.mipmap_mode == VK_SAMPLER_MIPMAP_MODE_NEAREST)
|
||||
{
|
||||
check_for_cyclic_refs |= true;
|
||||
}
|
||||
|
||||
if (!m_textures_dirty[i] && sampler_state->format_class != previous_format_class)
|
||||
{
|
||||
// Host details changed but RSX is not aware
|
||||
m_graphics_state |= rsx::fragment_program_state_dirty;
|
||||
}
|
||||
|
||||
bool replace = !fs_sampler_handles[i];
|
||||
VkFilter mag_filter;
|
||||
vk::minification_filter min_filter;
|
||||
f32 min_lod = 0.f, max_lod = 0.f;
|
||||
f32 lod_bias = 0.f;
|
||||
|
||||
const u32 texture_format = sampler_state->format_ex.format();
|
||||
VkBool32 compare_enabled = VK_FALSE;
|
||||
VkCompareOp depth_compare_mode = VK_COMPARE_OP_NEVER;
|
||||
|
||||
if (texture_format >= CELL_GCM_TEXTURE_DEPTH24_D8 && texture_format <= CELL_GCM_TEXTURE_DEPTH16_FLOAT)
|
||||
{
|
||||
compare_enabled = VK_TRUE;
|
||||
depth_compare_mode = vk::get_compare_func(tex.zfunc(), true);
|
||||
}
|
||||
|
||||
const f32 af_level = vk::max_aniso(tex.max_aniso());
|
||||
const auto wrap_s = vk::vk_wrap_mode(tex.wrap_s());
|
||||
const auto wrap_t = vk::vk_wrap_mode(tex.wrap_t());
|
||||
const auto wrap_r = vk::vk_wrap_mode(tex.wrap_r());
|
||||
|
||||
// NOTE: In vulkan, the border color can bypass the sample swizzle stage.
|
||||
// Check the device properties to determine whether to pre-swizzle the colors or not.
|
||||
const auto border_color = rsx::is_border_clamped_texture(tex)
|
||||
? vk::border_color_t(get_border_color(tex))
|
||||
: vk::border_color_t(VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK);
|
||||
|
||||
// Check if non-point filtering can even be used on this format
|
||||
bool can_sample_linear;
|
||||
if (sampler_state->format_class == RSX_FORMAT_CLASS_COLOR) [[likely]]
|
||||
{
|
||||
// Most PS3-like formats can be linearly filtered without problem
|
||||
// Exclude textures that require SNORM conversion however
|
||||
can_sample_linear = (sampler_state->format_ex.texel_remap_control & rsx::texture_control_bits::SEXT_MASK) == 0;
|
||||
}
|
||||
else if (sampler_state->format_class != rsx::classify_format(texture_format) &&
|
||||
(texture_format == CELL_GCM_TEXTURE_A8R8G8B8 || texture_format == CELL_GCM_TEXTURE_D8R8G8B8))
|
||||
{
|
||||
// Depth format redirected to BGRA8 resample stage. Do not filter to avoid bits leaking
|
||||
can_sample_linear = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not all GPUs support linear filtering of depth formats
|
||||
const auto vk_format = sampler_state->image_handle ? sampler_state->image_handle->image()->format() :
|
||||
vk::get_compatible_sampler_format(m_device->get_formats_support(), sampler_state->external_subresource_desc.gcm_format);
|
||||
|
||||
can_sample_linear = m_device->get_format_properties(vk_format).optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
||||
}
|
||||
|
||||
const auto mipmap_count = tex.get_exact_mipmap_count();
|
||||
min_filter = vk::get_min_filter(tex.min_filter());
|
||||
|
||||
if (can_sample_linear)
|
||||
{
|
||||
mag_filter = vk::get_mag_filter(tex.mag_filter());
|
||||
}
|
||||
else
|
||||
{
|
||||
mag_filter = VK_FILTER_NEAREST;
|
||||
min_filter.filter = VK_FILTER_NEAREST;
|
||||
}
|
||||
|
||||
if (min_filter.sample_mipmaps && mipmap_count > 1)
|
||||
{
|
||||
f32 actual_mipmaps;
|
||||
if (sampler_state->upload_context == rsx::texture_upload_context::shader_read)
|
||||
{
|
||||
actual_mipmaps = static_cast<f32>(mipmap_count);
|
||||
}
|
||||
else if (sampler_state->external_subresource_desc.op == rsx::deferred_request_command::mipmap_gather)
|
||||
{
|
||||
// Clamp min and max lod
|
||||
actual_mipmaps = static_cast<f32>(sampler_state->external_subresource_desc.sections_to_copy.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
actual_mipmaps = 1.f;
|
||||
}
|
||||
|
||||
if (actual_mipmaps > 1.f)
|
||||
{
|
||||
min_lod = tex.min_lod();
|
||||
max_lod = tex.max_lod();
|
||||
lod_bias = tex.bias();
|
||||
|
||||
min_lod = std::min(min_lod, actual_mipmaps - 1.f);
|
||||
max_lod = std::min(max_lod, actual_mipmaps - 1.f);
|
||||
|
||||
if (min_filter.mipmap_mode == VK_SAMPLER_MIPMAP_MODE_NEAREST)
|
||||
{
|
||||
// Round to nearest 0.5 to work around some broken games
|
||||
// Unlike openGL, sampler parameters cannot be dynamically changed on vulkan, leading to many permutations
|
||||
lod_bias = std::floor(lod_bias * 2.f + 0.5f) * 0.5f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
min_lod = max_lod = lod_bias = 0.f;
|
||||
min_filter.mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
if (fs_sampler_handles[i] && m_textures_dirty[i])
|
||||
{
|
||||
if (!fs_sampler_handles[i]->matches(wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod,
|
||||
min_filter.filter, mag_filter, min_filter.mipmap_mode, border_color, compare_enabled, depth_compare_mode))
|
||||
{
|
||||
replace = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (replace)
|
||||
{
|
||||
fs_sampler_handles[i] = vk::get_resource_manager()->get_sampler(
|
||||
*m_device,
|
||||
fs_sampler_handles[i],
|
||||
wrap_s, wrap_t, wrap_r,
|
||||
false,
|
||||
lod_bias, af_level, min_lod, max_lod,
|
||||
min_filter.filter, mag_filter, min_filter.mipmap_mode,
|
||||
border_color, compare_enabled, depth_compare_mode);
|
||||
// Round to nearest 0.5 to work around some broken games
|
||||
// Unlike openGL, sampler parameters cannot be dynamically changed on vulkan, leading to many permutations
|
||||
lod_bias = std::floor(lod_bias * 2.f + 0.5f) * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
m_textures_dirty[i] = false;
|
||||
else
|
||||
{
|
||||
min_lod = max_lod = lod_bias = 0.f;
|
||||
min_filter.mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
if (fs_sampler_handles[i] &&
|
||||
fs_sampler_handles[i]->matches(wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod,
|
||||
min_filter.filter, mag_filter, min_filter.mipmap_mode, border_color, compare_enabled, depth_compare_mode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
fs_sampler_handles[i] = vk::get_resource_manager()->get_sampler(
|
||||
*m_device,
|
||||
fs_sampler_handles[i],
|
||||
wrap_s, wrap_t, wrap_r,
|
||||
false,
|
||||
lod_bias, af_level, min_lod, max_lod,
|
||||
min_filter.filter, mag_filter, min_filter.mipmap_mode,
|
||||
border_color, compare_enabled, depth_compare_mode);
|
||||
}
|
||||
|
||||
for (u32 textures_ref = current_vp_metadata.referenced_textures_mask, i = 0; textures_ref; textures_ref >>= 1, ++i)
|
||||
{
|
||||
if (!(textures_ref & 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!vs_sampler_state[i])
|
||||
{
|
||||
vs_sampler_state[i] = std::make_unique<vk::texture_cache::sampled_image_descriptor>();
|
||||
}
|
||||
|
||||
auto sampler_state = static_cast<vk::texture_cache::sampled_image_descriptor*>(vs_sampler_state[i].get());
|
||||
const auto& tex = rsx::method_registers.vertex_textures[i];
|
||||
const auto previous_format_class = sampler_state->format_class;
|
||||
|
||||
if (m_samplers_dirty || m_vertex_textures_dirty[i] || !check_surface_cache_sampler(sampler_state, tex))
|
||||
if (!m_samplers_dirty &&
|
||||
!m_vertex_textures_dirty[i] &&
|
||||
check_surface_cache_sampler_valid(sampler_state, tex))
|
||||
{
|
||||
if (rsx::method_registers.vertex_textures[i].enabled())
|
||||
{
|
||||
*sampler_state = m_texture_cache.upload_texture(*m_current_command_buffer, tex, m_rtts);
|
||||
}
|
||||
else
|
||||
{
|
||||
*sampler_state = {};
|
||||
}
|
||||
|
||||
if (sampler_state->validate())
|
||||
{
|
||||
if (sampler_state->is_cyclic_reference || sampler_state->external_subresource_desc.do_not_cache)
|
||||
{
|
||||
check_for_cyclic_refs |= true;
|
||||
}
|
||||
|
||||
if (!m_vertex_textures_dirty[i] && sampler_state->format_class != previous_format_class)
|
||||
{
|
||||
// Host details changed but RSX is not aware
|
||||
m_graphics_state |= rsx::vertex_program_state_dirty;
|
||||
}
|
||||
|
||||
bool replace = !vs_sampler_handles[i];
|
||||
const VkBool32 unnormalized_coords = !!(tex.format() & CELL_GCM_TEXTURE_UN);
|
||||
const auto min_lod = tex.min_lod();
|
||||
const auto max_lod = tex.max_lod();
|
||||
const auto wrap_s = vk::vk_wrap_mode(tex.wrap_s());
|
||||
const auto wrap_t = vk::vk_wrap_mode(tex.wrap_t());
|
||||
|
||||
// NOTE: In vulkan, the border color can bypass the sample swizzle stage.
|
||||
// Check the device properties to determine whether to pre-swizzle the colors or not.
|
||||
const auto border_color = is_border_clamped_texture(tex)
|
||||
? vk::border_color_t(get_border_color(tex))
|
||||
: vk::border_color_t(VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK);
|
||||
|
||||
if (vs_sampler_handles[i])
|
||||
{
|
||||
if (!vs_sampler_handles[i]->matches(wrap_s, wrap_t, VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
unnormalized_coords, 0.f, 1.f, min_lod, max_lod, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, border_color))
|
||||
{
|
||||
replace = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (replace)
|
||||
{
|
||||
vs_sampler_handles[i] = vk::get_resource_manager()->get_sampler(
|
||||
*m_device,
|
||||
vs_sampler_handles[i],
|
||||
wrap_s, wrap_t, VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
unnormalized_coords,
|
||||
0.f, 1.f, min_lod, max_lod,
|
||||
VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, border_color);
|
||||
}
|
||||
}
|
||||
|
||||
m_vertex_textures_dirty[i] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool is_sampler_dirty = m_vertex_textures_dirty[i];
|
||||
m_vertex_textures_dirty[i] = false;
|
||||
|
||||
if (!rsx::method_registers.vertex_textures[i].enabled())
|
||||
{
|
||||
*sampler_state = {};
|
||||
continue;
|
||||
}
|
||||
|
||||
*sampler_state = m_texture_cache.upload_texture(*m_current_command_buffer, tex, m_rtts);
|
||||
if (!sampler_state->validate())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sampler_state->is_cyclic_reference || sampler_state->external_subresource_desc.do_not_cache)
|
||||
{
|
||||
check_for_cyclic_refs |= true;
|
||||
}
|
||||
|
||||
if (!is_sampler_dirty && sampler_state->format_class != previous_format_class)
|
||||
{
|
||||
// Host details changed but RSX is not aware
|
||||
m_graphics_state |= rsx::vertex_program_state_dirty;
|
||||
}
|
||||
|
||||
if (!is_sampler_dirty && vs_sampler_handles[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const VkBool32 unnormalized_coords = !!(tex.format() & CELL_GCM_TEXTURE_UN);
|
||||
const auto min_lod = tex.min_lod();
|
||||
const auto max_lod = tex.max_lod();
|
||||
const auto wrap_s = vk::vk_wrap_mode(tex.wrap_s());
|
||||
const auto wrap_t = vk::vk_wrap_mode(tex.wrap_t());
|
||||
|
||||
// NOTE: In vulkan, the border color can bypass the sample swizzle stage.
|
||||
// Check the device properties to determine whether to pre-swizzle the colors or not.
|
||||
const auto border_color = is_border_clamped_texture(tex)
|
||||
? vk::border_color_t(get_border_color(tex))
|
||||
: vk::border_color_t(VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK);
|
||||
|
||||
if (vs_sampler_handles[i] &&
|
||||
vs_sampler_handles[i]->matches(wrap_s, wrap_t, VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
unnormalized_coords, 0.f, 1.f, min_lod, max_lod, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, border_color))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
vs_sampler_handles[i] = vk::get_resource_manager()->get_sampler(
|
||||
*m_device,
|
||||
vs_sampler_handles[i],
|
||||
wrap_s, wrap_t, VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
unnormalized_coords,
|
||||
0.f, 1.f, min_lod, max_lod,
|
||||
VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, border_color);
|
||||
}
|
||||
|
||||
m_samplers_dirty.store(false);
|
||||
|
|
@ -557,7 +574,9 @@ bool VKGSRender::bind_texture_env()
|
|||
for (u32 textures_ref = current_fp_metadata.referenced_textures_mask, i = 0; textures_ref; textures_ref >>= 1, ++i)
|
||||
{
|
||||
if (!(textures_ref & 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
vk::image_view* view = nullptr;
|
||||
auto sampler_state = static_cast<vk::texture_cache::sampled_image_descriptor*>(fs_sampler_state[i].get());
|
||||
|
|
@ -627,7 +646,9 @@ bool VKGSRender::bind_texture_env()
|
|||
for (u32 textures_ref = current_vp_metadata.referenced_textures_mask, i = 0; textures_ref; textures_ref >>= 1, ++i)
|
||||
{
|
||||
if (!(textures_ref & 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rsx::method_registers.vertex_textures[i].enabled())
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue