#include "stdafx.h" #include "program_util.h" namespace rsx { // Convert u16 to u32 static u32 duplicate_and_extend(u16 bits) { u32 x = bits; x = (x | (x << 8)) & 0x00FF00FF; x = (x | (x << 4)) & 0x0F0F0F0F; x = (x | (x << 2)) & 0x33333333; x = (x | (x << 1)) & 0x55555555; return x | (x << 1); } void fragment_program_texture_config::masked_transfer(void* dst, const void* src, u16 mask) { // Try to optimize for the very common case (first 4 slots used) switch (mask) { case 0: return; case 1: std::memcpy(dst, src, sizeof(TIU_slot)); return; case 3: std::memcpy(dst, src, sizeof(TIU_slot) * 2); return; case 7: std::memcpy(dst, src, sizeof(TIU_slot) * 3); return; case 15: std::memcpy(dst, src, sizeof(TIU_slot) * 4); return; default: break; }; const auto start = std::countr_zero(mask); const auto end = 16 - std::countl_zero(mask); const auto mem_offset = (start * sizeof(TIU_slot)); const auto mem_size = (end - start) * sizeof(TIU_slot); std::memcpy(static_cast(dst) + mem_offset, reinterpret_cast(src) + mem_offset, mem_size); } void fragment_program_texture_config::write_to(void* dst, u16 mask) { masked_transfer(dst, slots_, mask); } void fragment_program_texture_config::load_from(const void* src, u16 mask) { masked_transfer(slots_, src, mask); } void fragment_program_texture_state::clear(u32 index) { const u16 clear_mask = ~(static_cast(1 << index)); redirected_textures &= clear_mask; shadow_textures &= clear_mask; multisampled_textures &= clear_mask; } void fragment_program_texture_state::import(const fragment_program_texture_state& other, u16 mask) { redirected_textures = other.redirected_textures & mask; shadow_textures = other.shadow_textures & mask; multisampled_textures = other.multisampled_textures & mask; texture_dimensions = other.texture_dimensions & duplicate_and_extend(mask); } void fragment_program_texture_state::set_dimension(texture_dimension_extended type, u32 index) { const auto offset = (index * 2); const auto mask = 3 << offset; texture_dimensions &= ~mask; texture_dimensions |= static_cast(type) << offset; } bool fragment_program_texture_state::operator == (const fragment_program_texture_state& other) const { return texture_dimensions == other.texture_dimensions && redirected_textures == other.redirected_textures && shadow_textures == other.shadow_textures && multisampled_textures == other.multisampled_textures; } void vertex_program_texture_state::clear(u32 index) { const u16 clear_mask = ~(static_cast(1 << index)); multisampled_textures &= clear_mask; } void vertex_program_texture_state::import(const vertex_program_texture_state& other, u16 mask) { multisampled_textures = other.multisampled_textures & mask; texture_dimensions = other.texture_dimensions & duplicate_and_extend(mask); } void vertex_program_texture_state::set_dimension(texture_dimension_extended type, u32 index) { const auto offset = (index * 2); const auto mask = 3 << offset; texture_dimensions &= ~mask; texture_dimensions |= static_cast(type) << offset; } bool vertex_program_texture_state::operator == (const vertex_program_texture_state& other) const { return texture_dimensions == other.texture_dimensions && multisampled_textures == other.multisampled_textures; } }