@ -9,9 +9,52 @@
# include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
namespace Shader : : Maxwell {
namespace {
enum class Mode : u64 {
Default ,
Patch ,
Prim ,
Attr ,
} ;
enum class SZ : u64 {
U8 ,
U16 ,
U32 ,
F32
} ;
enum class Shift : u64 {
Default ,
U16 ,
B32 ,
} ;
IR : : U32 scaleIndex ( IR : : IREmitter & ir , IR : : U32 index , Shift shift ) {
switch ( shift ) {
case Shift : : Default : return index ;
case Shift : : U16 : return ir . ShiftLeftLogical ( index , ir . Imm32 ( 1 ) ) ;
case Shift : : B32 : return ir . ShiftLeftLogical ( index , ir . Imm32 ( 2 ) ) ;
default : UNREACHABLE ( ) ;
}
}
IR : : U32 skewBytes ( IR : : IREmitter & ir , SZ sizeRead ) {
const IR : : U32 lane = ir . LaneId ( ) ;
switch ( sizeRead ) {
case SZ : : U8 : return lane ;
case SZ : : U16 : return ir . ShiftLeftLogical ( lane , ir . Imm32 ( 1 ) ) ;
case SZ : : U32 :
case SZ : : F32 : return ir . ShiftLeftLogical ( lane , ir . Imm32 ( 2 ) ) ;
default : UNREACHABLE ( ) ;
}
}
} // Anonymous namespace
// Valid only for GS, TI, VS and trap
void TranslatorVisitor : : ISBERD ( u64 insn ) {
LOG_DEBUG ( Shader , " called with insn={:#X} " , insn ) ;
union {
u64 raw ;
BitField < 0 , 8 , IR : : Reg > dest_reg ;
@ -20,49 +63,66 @@ void TranslatorVisitor::ISBERD(u64 insn) {
BitField < 24 , 8 , u32 > imm ;
BitField < 31 , 1 , u64 > skew ;
BitField < 32 , 1 , u64 > o ;
BitField < 33 , 2 , Isberd : : Mode > mode ;
BitField < 36 , 4 , Isberd : : SZ > sz ;
BitField < 47 , 2 , Isberd : : Shift > shift ;
BitField < 33 , 2 , Mode > mode ;
BitField < 36 , 4 , SZ > sz ;
BitField < 47 , 2 , Shift > shift ;
} const isberd { insn } ;
auto address = compute_ISBERD_address ( isberd . src_reg , isberd . src_reg_num , isberd . imm , isberd . skew ) ;
if ( isberd . o ! = 0 ) {
auto result = apply_ISBERD_size_read ( address , isberd . sz . Value ( ) ) ;
X ( isberd . dest_reg , apply_ISBERD_shift ( result , isberd . shift . Value ( ) ) ) ;
IR : : U32 index { } ;
if ( isberd . src_reg_num . Value ( ) = = 0xFF ) {
index = ir . Imm32 ( isberd . imm . Value ( ) ) ;
} else {
const IR : : U32 scaledIndex = scaleIndex ( ir , X ( isberd . src_reg . Value ( ) ) , isberd . shift . Value ( ) ) ;
index = ir . IAdd ( scaledIndex , ir . Imm32 ( isberd . imm . Value ( ) ) ) ;
}
if ( isberd . o . Value ( ) ) {
if ( isberd . skew . Value ( ) ) {
index = ir . IAdd ( index , skewBytes ( ir , isberd . sz . Value ( ) ) ) ;
}
const IR : : U64 index64 = ir . UConvert ( 64 , index ) ;
IR : : U32 globalLoaded { } ;
switch ( isberd . sz . Value ( ) ) {
case SZ : : U8 : globalLoaded = ir . LoadGlobalU8 ( index64 ) ; break ;
case SZ : : U16 : globalLoaded = ir . LoadGlobalU16 ( index64 ) ; break ;
case SZ : : U32 :
case SZ : : F32 : globalLoaded = ir . LoadGlobal32 ( index64 ) ; break ;
default : UNREACHABLE ( ) ;
}
X ( isberd . dest_reg . Value ( ) , globalLoaded ) ;
return ;
}
if ( isberd . mode ! = Isberd : : Mode : : Default ) {
IR : : F32 result_f32 { } ;
if ( isberd . mode . Value ( ) ! = Mode : : Default ) {
if ( isberd . skew . Value ( ) ) {
index = ir . IAdd ( index , skewBytes ( ir , SZ : : U32 ) ) ;
}
IR : : F32 float_index { } ;
switch ( isberd . mode . Value ( ) ) {
case Isberd : : Mode : : Patch :
result_f32 = ir . GetPatch ( address . Patch ( ) ) ;
case Mode : : Patch : float_index = ir . GetPatch ( index . Patch ( ) ) ;
break ;
case Isberd : : Mode : : Prim :
result_f32 = ir . GetAttribute ( address . Attribute ( ) ) ;
case Mode : : Prim : float_index = ir . GetAttribute ( index . Attribute ( ) ) ;
break ;
case Isberd : : Mode : : Attr :
result_f32 = ir . GetAttributeIndexed ( address ) ;
case Mode : : Attr : float_index = ir . GetAttributeIndexed ( index ) ;
break ;
default :
UNREACHABLE ( ) ;
default : UNREACHABLE ( ) ;
}
X ( isberd . dest_reg . Value ( ) , ir . BitCast < IR : : U32 > ( float_index ) ) ;
auto result_u32 = ir . BitCast < IR : : U32 > ( result_f32 ) ;
X ( isberd . dest_reg , apply_ISBERD_shift ( result_u32 , isberd . shift . Value ( ) ) ) ;
return ;
}
if ( isberd . skew ! = 0 ) {
auto result = ir . IAdd ( X ( isberd . src_reg ) , ir . LaneId ( ) ) ;
X ( isberd . dest_reg , result ) ;
if ( isberd . skew . Value ( ) ) {
X ( isberd . dest_reg . Value ( ) , ir . IAdd ( X ( isberd . src_reg . Value ( ) ) , ir . LaneId ( ) ) ) ;
return ;
}
// Fallback if nothing else applies
X ( isberd . dest_reg , X ( isberd . src_reg ) ) ;
// Fallback copy
X ( isberd . dest_reg . Value ( ) , X ( isberd . src_reg . Value ( ) ) ) ;
}
} // namespace Shader::Maxwell