diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.cpp b/rpcs3/Emu/RSX/Common/BufferUtils.cpp index 591da7b89b..ee36d55530 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.cpp +++ b/rpcs3/Emu/RSX/Common/BufferUtils.cpp @@ -5,6 +5,27 @@ #define MIN2(x, y) ((x) < (y)) ? (x) : (y) #define MAX2(x, y) ((x) > (y)) ? (x) : (y) + +namespace +{ + /** + * Convert CMP vector to RGBA16. + * A vector in CMP (compressed) format is stored as X11Y11Z10 and has a W component of 1. + * X11 and Y11 channels are int between -1024 and 1023 interpreted as -1.f, 1.f + * Z10 is int between -512 and 511 interpreted as -1.f, 1.f + */ + std::array decode_cmp_vector(u32 encoded_vector) + { + u16 Z = encoded_vector >> 22; + Z = Z << 6; + u16 Y = (encoded_vector >> 11) & 0x7FF; + Y = Y << 5; + u16 X = encoded_vector & 0x7FF; + X = X << 5; + return{ X, Y, Z, 1 }; + } +} + void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_t index, const rsx::data_array_format_info &vertex_array_desc) { assert(vertex_array_desc.size > 0); @@ -15,8 +36,7 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_ u32 offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + index]; u32 address = rsx::get_address(offset & 0x7fffffff, offset >> 31); - u32 type_size = rsx::get_vertex_type_size(vertex_array_desc.type); - u32 element_size = type_size * vertex_array_desc.size; + u32 element_size = rsx::get_vertex_type_size_on_host(vertex_array_desc.type, vertex_array_desc.size); u32 base_offset = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_OFFSET]; u32 base_index = rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX]; @@ -26,13 +46,14 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_ auto src = vm::ps3::_ptr(address + base_offset + vertex_array_desc.stride * (first + i + base_index)); u8* dst = (u8*)buffer + i * element_size; - switch (type_size) + switch (vertex_array_desc.type) { - case 1: + case Vertex_base_type::ub: memcpy(dst, src, vertex_array_desc.size); break; - case 2: + case Vertex_base_type::s1: + case Vertex_base_type::sf: { auto* c_src = (const be_t*)src; u16* c_dst = (u16*)dst; @@ -41,10 +62,14 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_ { *c_dst++ = *c_src++; } + if (vertex_array_desc.size * sizeof(u16) < element_size) + *c_dst++ = 0x3800; break; } - case 4: + case Vertex_base_type::f: + case Vertex_base_type::s32k: + case Vertex_base_type::ub256: { auto* c_src = (const be_t*)src; u32* c_dst = (u32*)dst; @@ -55,6 +80,17 @@ void write_vertex_array_data_to_buffer(void *buffer, u32 first, u32 count, size_ } break; } + case Vertex_base_type::cmp: + { + auto* c_src = (const be_t*)src; + const auto& decoded_vector = decode_cmp_vector(*c_src); + u16* c_dst = (u16*)dst; + c_dst[0] = decoded_vector[0]; + c_dst[1] = decoded_vector[1]; + c_dst[2] = decoded_vector[2]; + c_dst[3] = decoded_vector[3]; + break; + } } } } diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index 22a1b4503c..9d0a09efd9 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -341,7 +341,9 @@ bool FragmentProgramDecompiler::handle_sct(u32 opcode) { case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true; case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); return true; - case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1).xxxx)"); return true; + // Note: DIVSQ is not IEEE compliant. divsq(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix). + // sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven. + case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, $1)"); return true; case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2)); return true; case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3)); return true; case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4)); return true; @@ -351,8 +353,11 @@ bool FragmentProgramDecompiler::handle_sct(u32 opcode) case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); return true; case RSX_FP_OPCODE_MOV: SetDst("$0"); return true; case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); return true; - case RSX_FP_OPCODE_RCP: SetDst("1.0 / $0"); return true; - case RSX_FP_OPCODE_RSQ: SetDst("1.f / sqrt($0)"); return true; + // Note: It's higly likely that RCP is not IEEE compliant but a game that uses rcp(0) has to be found + case RSX_FP_OPCODE_RCP: SetDst("rcp_legacy($0)"); return true; + // Note: RSQ is not IEEE compliant. rsq(0) is some big number (Silent Hill 3 HD) + // It is not know what happens if 0 is negative. + case RSX_FP_OPCODE_RSQ: SetDst("rsq_legacy($0)"); return true; case RSX_FP_OPCODE_SEQ: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SEQ, "$0", "$1") + ")"); return true; case RSX_FP_OPCODE_SFL: SetDst(getFunction(FUNCTION::FUNCTION_SFL)); return true; case RSX_FP_OPCODE_SGE: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SGE, "$0", "$1") + ")"); return true; @@ -372,7 +377,9 @@ bool FragmentProgramDecompiler::handle_scb(u32 opcode) case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true; case RSX_FP_OPCODE_COS: SetDst("cos($0.xxxx)"); return true; case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); return true; - case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1).xxxx)"); return true; + // Note: DIVSQ is not IEEE compliant. sqrt(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix). + // sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven. + case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, sqrt($1).xxxx)"); return true; case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2)); return true; case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3)); return true; case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4)); return true; @@ -453,7 +460,22 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) case RSX_FP_OPCODE_TXPBEM: SetDst("textureProj($t, $0.xyz, $1.x)"); return true; case RSX_FP_OPCODE_TXD: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXD"); return true; case RSX_FP_OPCODE_TXB: SetDst("texture($t, $0.xy, $1.x)"); return true; - case RSX_FP_OPCODE_TXL: SetDst("textureLod($t, $0.xy, $1.x)"); return true; + case RSX_FP_OPCODE_TXL: + if (dst.tex_num >= m_texture_dimensions.size()) + { + SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD)); + return true; + } + switch (m_texture_dimensions[dst.tex_num]) + { + case texture_dimension::texture_dimension_2d: + SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD)); + return true; + case texture_dimension::texture_dimension_cubemap: + SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_LOD)); + return true; + } + return false; case RSX_FP_OPCODE_UP2: SetDst("unpackSnorm2x16($0)"); return true; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) case RSX_FP_OPCODE_UP4: SetDst("unpackSnorm4x8($0)"); return true; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) case RSX_FP_OPCODE_UP16: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UP16"); return true; diff --git a/rpcs3/Emu/RSX/Common/ShaderParam.h b/rpcs3/Emu/RSX/Common/ShaderParam.h index 69443dd6cb..d04f89f6c3 100644 --- a/rpcs3/Emu/RSX/Common/ShaderParam.h +++ b/rpcs3/Emu/RSX/Common/ShaderParam.h @@ -15,8 +15,10 @@ enum class FUNCTION { FUNCTION_DFDY, FUNCTION_TEXTURE_SAMPLE, FUNCTION_TEXTURE_SAMPLE_PROJ, + FUNCTION_TEXTURE_SAMPLE_LOD, FUNCTION_TEXTURE_CUBE_SAMPLE, FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ, + FUNCTION_TEXTURE_CUBE_SAMPLE_LOD, }; enum class COMPARE { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp index fc9c3b23a7..24a6e00af0 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp @@ -60,8 +60,7 @@ std::vector D3D12GSRender::upload_vertex_attributes(co // Active vertex array const rsx::data_array_format_info &info = vertex_arrays_info[index]; - u32 type_size = rsx::get_vertex_type_size(info.type); - u32 element_size = type_size * info.size; + u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size); size_t buffer_size = element_size * vertex_count; assert(m_vertex_index_data.can_alloc(buffer_size)); @@ -104,8 +103,7 @@ std::vector D3D12GSRender::upload_vertex_attributes(co const std::vector &data = register_vertex_data[index]; - u32 type_size = rsx::get_vertex_type_size(info.type); - u32 element_size = type_size * info.size; + u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size); size_t buffer_size = data.size(); assert(m_vertex_index_data.can_alloc(buffer_size)); @@ -253,7 +251,7 @@ std::tuple D3D12GSRender::upload_inlined_verte IAElement.InstanceDataStepRate = 0; m_IASet.push_back(IAElement); - offset += rsx::get_vertex_type_size(info.type) * info.size; + offset += rsx::get_vertex_type_size_on_host(info.type, info.size); } // Copy inline buffer diff --git a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp index 1c8f7e3c05..f484cd2d2b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp @@ -46,10 +46,14 @@ std::string getFunctionImp(FUNCTION f) return "$t.Sample($tsampler, $0.xy * $t_scale)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ: return "$t.Sample($tsampler, ($0.xy / $0.z) * $t_scale)"; + case FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD: + return "$t.SampleLevel($tsampler, ($0.xy / $0.z) * $t_scale, $1)"; case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE: return "$t.Sample($tsampler, $0.xyz)"; case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ: return "$t.Sample($tsampler, ($0.xyz / $0.w))"; + case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_LOD: + return "$t.SampleLevel($tsampler, ($0.xyz / $0.w), $1)"; case FUNCTION::FUNCTION_DFDX: return "ddx($0)"; case FUNCTION::FUNCTION_DFDY: diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp index eb76f61f64..1f85c020a2 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp @@ -372,11 +372,11 @@ DXGI_FORMAT get_index_type(u8 index_type) throw EXCEPTION("Invalid index_type (0x%x)", index_type); } -DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size) +DXGI_FORMAT get_vertex_attribute_format(Vertex_base_type type, u8 size) { switch (type) { - case CELL_GCM_VERTEX_S1: + case Vertex_base_type::s1: { switch (size) { @@ -387,7 +387,7 @@ DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size) } break; } - case CELL_GCM_VERTEX_F: + case Vertex_base_type::f: { switch (size) { @@ -398,7 +398,7 @@ DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size) } break; } - case CELL_GCM_VERTEX_SF: + case Vertex_base_type::sf: { switch (size) { @@ -409,7 +409,7 @@ DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size) } break; } - case CELL_GCM_VERTEX_UB: + case Vertex_base_type::ub: { switch (size) { @@ -420,7 +420,7 @@ DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size) } break; } - case CELL_GCM_VERTEX_S32K: + case Vertex_base_type::s32k: { switch (size) { @@ -431,18 +431,18 @@ DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size) } break; } - case CELL_GCM_VERTEX_CMP: + case Vertex_base_type::cmp: { switch (size) { - case 1: return DXGI_FORMAT_R32_FLOAT; - case 2: return DXGI_FORMAT_R32G32_FLOAT; - case 3: return DXGI_FORMAT_R32G32B32_FLOAT; - case 4: return DXGI_FORMAT_R32G32B32A32_FLOAT; + case 1: return DXGI_FORMAT_R16G16B16A16_SNORM; + case 2: + case 3: + case 4: throw EXCEPTION("Unsupported CMP vertex format with size > 1"); } break; } - case CELL_GCM_VERTEX_UB256: + case Vertex_base_type::ub256: { switch (size) { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Formats.h b/rpcs3/Emu/RSX/D3D12/D3D12Formats.h index b293683345..9df0944136 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Formats.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12Formats.h @@ -101,7 +101,7 @@ DXGI_FORMAT get_index_type(u8 index_type); /** * Convert vertex attribute format and size to DXGI_FORMAT */ -DXGI_FORMAT get_vertex_attribute_format(u8 type, u8 size); +DXGI_FORMAT get_vertex_attribute_format(Vertex_base_type type, u8 size); /** * Convert scissor register value to D3D12_RECT diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp index ec2094d3d6..43ae0dbf6b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp @@ -141,6 +141,24 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS) void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS) { + // "lib" function + // 0.00001 is used as "some non zero very little number" + OS << "float4 divsq_legacy(float4 num, float4 denum)\n"; + OS << "{\n"; + OS << " return num / sqrt(max(denum.xxxx, 0.00001));\n"; + OS << "}\n"; + + OS << "float4 rcp_legacy(float4 denum)\n"; + OS << "{\n"; + OS << " return 1. / denum;\n"; + OS << "}\n"; + + OS << "float4 rsq_legacy(float4 denum)\n"; + OS << "{\n"; + OS << " return 1. / sqrt(max(denum, 0.00001));\n"; + OS << "}\n"; + + const std::set output_value = { "r0", "r1", "r2", "r3", "r4", diff --git a/rpcs3/Emu/RSX/GCM.cpp b/rpcs3/Emu/RSX/GCM.cpp index 21fc8fadc2..0b886d861f 100644 --- a/rpcs3/Emu/RSX/GCM.cpp +++ b/rpcs3/Emu/RSX/GCM.cpp @@ -719,6 +719,21 @@ namespace }; } +Vertex_base_type to_vertex_base_type(u8 in) +{ + switch (in) + { + case 1: return Vertex_base_type::s1; + case 2: return Vertex_base_type::f; + case 3: return Vertex_base_type::sf; + case 4: return Vertex_base_type::ub; + case 5: return Vertex_base_type::s32k; + case 6: return Vertex_base_type::cmp; + case 7: return Vertex_base_type::ub256; + } + throw new EXCEPTION("Unknow vertex base type %d", in); +} + std::string rsx::get_method_name(const u32 id) { auto found = methods.find(id); @@ -926,17 +941,16 @@ namespace std::string get_vertex_attribute_format(u8 type) { - switch (type) + switch (to_vertex_base_type(type)) { - case CELL_GCM_VERTEX_S1: return "Short"; - case CELL_GCM_VERTEX_F: return "Float"; - case CELL_GCM_VERTEX_SF: return "Half float"; - case CELL_GCM_VERTEX_UB: return "Unsigned byte"; - case CELL_GCM_VERTEX_S32K: return "Signed int"; - case CELL_GCM_VERTEX_CMP: return "CMP"; - case CELL_GCM_VERTEX_UB256: return "UB256"; + case Vertex_base_type::s1: return "Short"; + case Vertex_base_type::f: return "Float"; + case Vertex_base_type::sf: return "Half float"; + case Vertex_base_type::ub: return "Unsigned byte"; + case Vertex_base_type::s32k: return "Signed int"; + case Vertex_base_type::cmp: return "CMP"; + case Vertex_base_type::ub256: return "UB256"; } - return "Error"; } std::string unpack_vertex_format(u32 arg) diff --git a/rpcs3/Emu/RSX/GCM.h b/rpcs3/Emu/RSX/GCM.h index c83a009943..e77bc2a965 100644 --- a/rpcs3/Emu/RSX/GCM.h +++ b/rpcs3/Emu/RSX/GCM.h @@ -23,17 +23,19 @@ enum CELL_GCM_DISPLAY_FREQUENCY_DISABLE = 3, }; -enum +enum class Vertex_base_type { - CELL_GCM_VERTEX_S1 = 1, - CELL_GCM_VERTEX_F = 2, - CELL_GCM_VERTEX_SF = 3, - CELL_GCM_VERTEX_UB = 4, - CELL_GCM_VERTEX_S32K = 5, - CELL_GCM_VERTEX_CMP = 6, - CELL_GCM_VERTEX_UB256 = 7, + s1, ///< signed byte + f, ///< float + sf, ///< half float + ub, ///< unsigned byte + s32k, ///< signed 32bits int + cmp, ///< compressed aka X11G11Z10 and always 1. W. + ub256, }; +Vertex_base_type to_vertex_base_type(u8 in); + enum { CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32 = 0, diff --git a/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp b/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp index 24a6167c0f..c8cde0fdf4 100644 --- a/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp @@ -44,10 +44,14 @@ std::string getFunctionImpl(FUNCTION f) return "texture($t, $0.xy)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ: return "textureProj($t, $0.xyz, $1.x)"; // Note: $1.x is bias + case FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD: + return "textureLod($t, $0.xy, $1)"; case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE: return "texture($t, $0.xyz)"; case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ: return "textureProj($t, $0.xyzw, $1.x)"; // Note: $1.x is bias + case FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_LOD: + return "textureLod($t, $0.xyz, $1)"; case FUNCTION::FUNCTION_DFDX: return "dFdx($0)"; case FUNCTION::FUNCTION_DFDY: diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index 24600c02eb..82814d861d 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -84,6 +84,23 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS) void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) { + // "lib" function + // 0.00001 is used as "some non zero very little number" + OS << "vec4 divsq_legacy(vec4 num, vec4 denum)\n"; + OS << "{\n"; + OS << " return num / sqrt(max(denum.xxxx, 0.00001));\n"; + OS << "}\n"; + + OS << "vec4 rcp_legacy(vec4 denum)\n"; + OS << "{\n"; + OS << " return 1. / denum;\n"; + OS << "}\n"; + + OS << "vec4 rsq_legacy(vec4 denum)\n"; + OS << "{\n"; + OS << " return 1. / sqrt(max(denum, 0.00001));\n"; + OS << "}\n"; + OS << "void main ()" << std::endl; OS << "{" << std::endl; diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 937afc4146..22f025d0bd 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -292,6 +292,39 @@ void apply_attrib_array(gl::glsl::program& program, int location, const std::vec } } +namespace +{ + gl::buffer_pointer::type gl_types(Vertex_base_type type) + { + switch (type) + { + case Vertex_base_type::s1: return gl::buffer_pointer::type::s16; + case Vertex_base_type::f: return gl::buffer_pointer::type::f32; + case Vertex_base_type::sf: return gl::buffer_pointer::type::f16; + case Vertex_base_type::ub: return gl::buffer_pointer::type::u8; + case Vertex_base_type::s32k: return gl::buffer_pointer::type::s32; + case Vertex_base_type::cmp: return gl::buffer_pointer::type::s16; // Needs conversion + case Vertex_base_type::ub256: gl::buffer_pointer::type::u8; + } + } + + bool gl_normalized(Vertex_base_type type) + { + switch (type) + { + case Vertex_base_type::s1: + case Vertex_base_type::ub: + case Vertex_base_type::cmp: + return true; + case Vertex_base_type::f: + case Vertex_base_type::sf: + case Vertex_base_type::ub256: + case Vertex_base_type::s32k: + return false; + } + } +} + void GLGSRender::end() { if (!draw_fbo || !vertex_draw_count) @@ -322,31 +355,9 @@ void GLGSRender::end() } //initialize vertex attributes - static const gl::buffer_pointer::type gl_types[] = - { - gl::buffer_pointer::type::f32, - gl::buffer_pointer::type::s16, - gl::buffer_pointer::type::f32, - gl::buffer_pointer::type::f16, - gl::buffer_pointer::type::u8, - gl::buffer_pointer::type::s16, - gl::buffer_pointer::type::f32, // Needs conversion - gl::buffer_pointer::type::u8 - }; - static const bool gl_normalized[] = - { - false, - true, - false, - false, - true, - false, - true, - false - }; //merge all vertex arrays std::vector vertex_arrays_data; @@ -382,8 +393,8 @@ void GLGSRender::end() __glcheck m_program->attribs[location] = (m_vao + offset) - .config(gl_types[vertex_info.type], vertex_info.size, gl_normalized[vertex_info.type]); - offset += rsx::get_vertex_type_size(vertex_info.type) * vertex_info.size; + .config(gl_types(vertex_info.type), vertex_info.size, gl_normalized(vertex_info.type)); + offset += rsx::get_vertex_type_size_on_host(vertex_info.type, vertex_info.size); } } else @@ -416,7 +427,7 @@ void GLGSRender::end() __glcheck m_program->attribs[location] = (m_vao + vertex_arrays_offsets[index]) - .config(gl_types[vertex_info.type], vertex_info.size, gl_normalized[vertex_info.type]); + .config(gl_types(vertex_info.type), vertex_info.size, gl_normalized(vertex_info.type)); } else if (register_vertex_info[index].size > 0) { @@ -425,7 +436,7 @@ void GLGSRender::end() switch (vertex_info.type) { - case CELL_GCM_VERTEX_F: + case Vertex_base_type::f: switch (register_vertex_info[index].size) { case 1: apply_attrib_array(*m_program, location, vertex_data); break; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index d3a016caa9..6d8bfd7b1c 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -120,22 +120,51 @@ namespace rsx return res; } - u32 get_vertex_type_size(u32 type) + u32 get_vertex_type_size_on_host(Vertex_base_type type, u32 size) { switch (type) { - case CELL_GCM_VERTEX_S1: return sizeof(u16); - case CELL_GCM_VERTEX_F: return sizeof(f32); - case CELL_GCM_VERTEX_SF: return sizeof(f16); - case CELL_GCM_VERTEX_UB: return sizeof(u8); - case CELL_GCM_VERTEX_S32K: return sizeof(u32); - case CELL_GCM_VERTEX_CMP: return sizeof(u32); - case CELL_GCM_VERTEX_UB256: return sizeof(u8) * 4; + case Vertex_base_type::s1: + switch (size) + { + case 1: + case 2: + case 4: + return sizeof(u16) * size; + case 3: + return sizeof(u16) * 4; + } + throw new EXCEPTION("Wrong vector size"); + case Vertex_base_type::f: return sizeof(f32) * size; + case Vertex_base_type::sf: + switch (size) + { + case 1: + case 2: + case 4: + return sizeof(f16) * size; + case 3: + return sizeof(f16) * 4; + } + throw new EXCEPTION("Wrong vector size"); + case Vertex_base_type::ub: + switch (size) + { + case 1: + case 2: + case 4: + return sizeof(u8) * size; + case 3: + return sizeof(u8) * 4; + } + throw new EXCEPTION("Wrong vector size"); + case Vertex_base_type::s32k: return sizeof(u32) * size; + case Vertex_base_type::cmp: return sizeof(u16) * 4; + case Vertex_base_type::ub256: return sizeof(u8) * 4; default: - LOG_ERROR(RSX, "RSXVertexData::GetTypeSize: Bad vertex data type (%d)!", type); - assert(0); - return 1; + throw new EXCEPTION("RSXVertexData::GetTypeSize: Bad vertex data type (%d)!", type); + return 0; } } @@ -254,8 +283,7 @@ namespace rsx auto &data = vertex_arrays[index]; - u32 type_size = get_vertex_type_size(info.type); - u32 element_size = type_size * info.size; + u32 element_size = get_vertex_type_size_on_host(info.type, info.size); u32 dst_position = (u32)data.size(); data.resize(dst_position + count * element_size); @@ -319,7 +347,7 @@ namespace rsx color_index_to_record = { 0, 1, 2, 3 }; break; } -/* for (size_t i : color_index_to_record) + for (size_t i : color_index_to_record) { draw_state.color_buffer[i].width = clip_w; draw_state.color_buffer[i].height = clip_h; @@ -336,7 +364,7 @@ namespace rsx draw_state.stencil.height = clip_h; draw_state.stencil.data.resize(clip_w * clip_h * 4); copy_stencil_buffer_to_memory(draw_state.stencil.data.data()); - }*/ + } draw_state.programs = get_programs(); draw_state.name = name; frame_debug.draw_calls.push_back(draw_state); @@ -537,10 +565,9 @@ namespace rsx if (!info.size) // disabled continue; - u32 type_size = rsx::get_vertex_type_size(info.type); - u32 element_size = type_size * info.size; + u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size); - if (type_size == 1 && info.size == 4) + if (info.type == Vertex_base_type::ub && info.size == 4) { dst[0] = src[3]; dst[1] = src[2]; diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 600719b90a..b80d89fbad 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -148,7 +148,7 @@ namespace rsx static std::string path_to_root(); }; - u32 get_vertex_type_size(u32 type); + u32 get_vertex_type_size_on_host(Vertex_base_type type, u32 size); u32 get_address(u32 offset, u32 location); @@ -195,14 +195,14 @@ namespace rsx u16 frequency = 0; u8 stride = 0; u8 size = 0; - u8 type = CELL_GCM_VERTEX_F; + Vertex_base_type type = Vertex_base_type::f; void unpack_array(u32 data_array_format) { frequency = data_array_format >> 16; stride = (data_array_format >> 8) & 0xff; size = (data_array_format >> 4) & 0xf; - type = data_array_format & 0xf; + type = to_vertex_base_type(data_array_format & 0xf); } }; diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 3529418999..cd18c7b6eb 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -14,10 +14,10 @@ namespace rsx rsx_method_t methods[0x10000 >> 2]{}; template struct vertex_data_type_from_element_type; - template<> struct vertex_data_type_from_element_type { enum { type = CELL_GCM_VERTEX_F }; }; - template<> struct vertex_data_type_from_element_type { enum { type = CELL_GCM_VERTEX_SF }; }; - template<> struct vertex_data_type_from_element_type { enum { type = CELL_GCM_VERTEX_UB }; }; - template<> struct vertex_data_type_from_element_type { enum { type = CELL_GCM_VERTEX_S1 }; }; + template<> struct vertex_data_type_from_element_type { static const Vertex_base_type type = Vertex_base_type::f; }; + template<> struct vertex_data_type_from_element_type { static const Vertex_base_type type = Vertex_base_type::sf; }; + template<> struct vertex_data_type_from_element_type { static const Vertex_base_type type = Vertex_base_type::ub; }; + template<> struct vertex_data_type_from_element_type { static const Vertex_base_type type = Vertex_base_type::s1; }; namespace nv406e { @@ -248,7 +248,7 @@ namespace rsx continue; u32 count = u32(rsx->register_vertex_data[i].size()) / - rsx::get_vertex_type_size(rsx->register_vertex_info[i].type) * rsx->register_vertex_info[i].size; + rsx::get_vertex_type_size_on_host(rsx->register_vertex_info[i].type, rsx->register_vertex_info[i].size); if (count < min_count) min_count = count;