diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index 1199876b47..88435164e3 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -5,12 +5,11 @@ #include "FragmentProgramDecompiler.h" FragmentProgramDecompiler::FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size) : - m_addr(prog.addr), + m_prog(prog), m_size(size), m_const_index(0), m_location(0), - m_ctrl(prog.ctrl), - m_texture_dimensions(prog.texture_dimensions) + m_ctrl(prog.ctrl) { m_size = 0; } @@ -114,7 +113,7 @@ std::string FragmentProgramDecompiler::AddConst() return name; } - auto data = vm::ps3::ptr::make(m_addr + m_size + 4 * SIZE_32(u32)); + auto data = vm::ps3::ptr::make(m_prog.addr + m_size + 4 * SIZE_32(u32)); m_offset = 2 * 4 * sizeof(u32); u32 x = GetData(data[0]); @@ -128,7 +127,20 @@ std::string FragmentProgramDecompiler::AddConst() std::string FragmentProgramDecompiler::AddTex() { - return m_parr.AddParam(PF_PARAM_UNIFORM, (m_texture_dimensions[dst.tex_num] == texture_dimension::texture_dimension_cubemap) ? "samplerCube" : "sampler2D", std::string("tex") + std::to_string(dst.tex_num)); + std::string sampler; + switch (m_prog.get_texture_dimension(dst.tex_num)) + { + case texture_dimension::texture_dimension_cubemap: + sampler = "samplerCube"; + break; + case texture_dimension::texture_dimension_2d: + sampler = "sampler2D"; + break; + case texture_dimension::texture_dimension_3d: + sampler = "sampler3D"; + break; + } + return m_parr.AddParam(PF_PARAM_UNIFORM, sampler, std::string("tex") + std::to_string(dst.tex_num)); } std::string FragmentProgramDecompiler::Format(const std::string& code) @@ -425,12 +437,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) case RSX_FP_OPCODE_NRM: SetDst("normalize($0)"); return true; case RSX_FP_OPCODE_BEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: BEM"); return true; case RSX_FP_OPCODE_TEX: - if (dst.tex_num >= m_texture_dimensions.size()) - { - SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE)); - return true; - } - switch (m_texture_dimensions[dst.tex_num]) + switch (m_prog.get_texture_dimension(dst.tex_num)) { case texture_dimension::texture_dimension_2d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE)); @@ -438,16 +445,14 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) case texture_dimension::texture_dimension_cubemap: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE)); return true; + case texture_dimension::texture_dimension_3d: + SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D)); + return true; } return false; case RSX_FP_OPCODE_TEXBEM: SetDst("texture($t, $0.xy, $1.x)"); return true; case RSX_FP_OPCODE_TXP: - if (dst.tex_num >= m_texture_dimensions.size()) - { - SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ)); - return true; - } - switch (m_texture_dimensions[dst.tex_num]) + switch (m_prog.get_texture_dimension(dst.tex_num)) { case texture_dimension::texture_dimension_2d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ)); @@ -455,18 +460,16 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) case texture_dimension::texture_dimension_cubemap: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ)); return true; + case texture_dimension::texture_dimension_3d: + SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ)); + return true; } return false; 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: - if (dst.tex_num >= m_texture_dimensions.size()) - { - SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD)); - return true; - } - switch (m_texture_dimensions[dst.tex_num]) + switch (m_prog.get_texture_dimension(dst.tex_num)) { case texture_dimension::texture_dimension_2d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD)); @@ -474,6 +477,9 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) case texture_dimension::texture_dimension_cubemap: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_CUBE_SAMPLE_LOD)); return true; + case texture_dimension::texture_dimension_3d: + SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_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)) @@ -487,7 +493,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) std::string FragmentProgramDecompiler::Decompile() { - auto data = vm::ps3::ptr::make(m_addr); + auto data = vm::ps3::ptr::make(m_prog.addr); m_size = 0; m_location = 0; m_loop_count = 0; diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h index 95d7075bb7..81279fde0e 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h @@ -25,9 +25,8 @@ class FragmentProgramDecompiler SRC2 src2; std::string main; - u32 m_addr; u32& m_size; - const std::vector m_texture_dimensions; + const RSXFragmentProgram &m_prog; u32 m_const_index; u32 m_offset; u32 m_location; diff --git a/rpcs3/Emu/RSX/Common/ShaderParam.h b/rpcs3/Emu/RSX/Common/ShaderParam.h index d04f89f6c3..a53e83cd0a 100644 --- a/rpcs3/Emu/RSX/Common/ShaderParam.h +++ b/rpcs3/Emu/RSX/Common/ShaderParam.h @@ -19,6 +19,9 @@ enum class FUNCTION { FUNCTION_TEXTURE_CUBE_SAMPLE, FUNCTION_TEXTURE_CUBE_SAMPLE_PROJ, FUNCTION_TEXTURE_CUBE_SAMPLE_LOD, + FUNCTION_TEXTURE_SAMPLE3D, + FUNCTION_TEXTURE_SAMPLE3D_PROJ, + FUNCTION_TEXTURE_SAMPLE3D_LOD, }; enum class COMPARE { diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.cpp b/rpcs3/Emu/RSX/Common/TextureUtils.cpp index a54297475b..514f91b861 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.cpp +++ b/rpcs3/Emu/RSX/Common/TextureUtils.cpp @@ -14,9 +14,9 @@ namespace struct texel_rgba { template - static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block) + static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block) { - for (unsigned row = 0; row < row_count; row++) + for (unsigned row = 0; row < row_count * depth; row++) memcpy((char*)dst + row * dst_pitch_in_block * block_size, (char*)src + row * src_pitch_in_block * block_size, width_in_block * block_size); } }; @@ -28,13 +28,13 @@ struct texel_rgba struct texel_16b_swizzled { template - static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block) + static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block) { u16 *castedSrc = static_cast(src), *castedDst = static_cast(dst); std::unique_ptr temp_swizzled(new u16[row_count * width_in_block]); rsx::convert_linear_swizzle(castedSrc, temp_swizzled.get(), src_pitch_in_block, row_count, true); - for (unsigned row = 0; row < row_count; row++) + for (unsigned row = 0; row < row_count * depth; row++) for (int j = 0; j < width_in_block; j++) { u16 tmp = temp_swizzled[row * src_pitch_in_block + j]; @@ -49,14 +49,14 @@ struct texel_16b_swizzled struct texel_rgba_swizzled { template - static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block) + static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block) { u32 *castedSrc, *castedDst; castedSrc = (u32*)src; castedDst = (u32*)dst ; std::unique_ptr temp_swizzled(new u32[src_pitch_in_block * row_count]); rsx::convert_linear_swizzle(castedSrc, temp_swizzled.get(), src_pitch_in_block, row_count, true); - for (unsigned row = 0; row < row_count; row++) + for (unsigned row = 0; row < row_count * depth; row++) memcpy((char*)dst + row * dst_pitch_in_block * block_size, (char*)temp_swizzled.get() + row * src_pitch_in_block * block_size, width_in_block * block_size); } }; @@ -67,9 +67,9 @@ struct texel_rgba_swizzled */ struct texel_bc_format { template - static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block) + static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block) { - for (unsigned row = 0; row < row_count; row++) + for (unsigned row = 0; row < row_count * depth; row++) memcpy((char*)dst + row * dst_pitch_in_block * block_size, (char*)src + row * src_pitch_in_block * block_size, width_in_block * block_size); } }; @@ -79,11 +79,11 @@ struct texel_bc_format { */ struct texel_16b_format { template - static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block) + static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block) { unsigned short *castedDst = (unsigned short *)dst, *castedSrc = (unsigned short *)src; - for (unsigned row = 0; row < row_count; row++) + for (unsigned row = 0; row < row_count * depth; row++) for (int j = 0; j < width_in_block; j++) { u16 tmp = castedSrc[row * src_pitch_in_block + j]; @@ -97,10 +97,10 @@ struct texel_16b_format { */ struct texel_16bX4_format { template - static void copy_mipmap_level(void *dst, void *src, size_t row_count, size_t width_in_block, size_t dst_pitch_in_block, size_t src_pitch_in_block) + static void copy_mipmap_level(void *dst, void *src, u16 row_count, u16 width_in_block, u16 depth, size_t dst_pitch_in_block, size_t src_pitch_in_block) { unsigned short *casted_dst = (unsigned short *)dst, *casted_src = (unsigned short *)src; - for (unsigned row = 0; row < row_count; row++) + for (unsigned row = 0; row < row_count * depth; row++) for (int j = 0; j < width_in_block * 4; j++) { u16 tmp = casted_src[row * src_pitch_in_block * 4 + j]; @@ -124,13 +124,13 @@ struct texel_16bX4_format { * mipmap level (to allow same code for packed/non packed texels) */ template -std::vector copy_texture_data(void *dst, const void *src, size_t width_in_texel, size_t height_in_texel, size_t depth, size_t mipmap_count) +std::vector copy_texture_data(void *dst, const void *src, u16 width_in_texel, u16 height_in_texel, u16 depth, u8 layer_count, u16 mipmap_count) { std::vector Result; size_t offsetInDst = 0, offsetInSrc = 0; size_t texture_height_in_block = (height_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; size_t texture_width_in_block = (width_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; - for (unsigned depth_level = 0; depth_level < depth; depth_level++) + for (unsigned layer = 0; layer < layer_count; layer++) { size_t miplevel_height_in_block = texture_height_in_block, miplevel_width_in_block = texture_width_in_block; for (unsigned mip_level = 0; mip_level < mipmap_count; mip_level++) @@ -141,18 +141,19 @@ std::vector copy_texture_data(void *dst, const void *src, size_ currentMipmapLevelInfo.offset = offsetInDst; currentMipmapLevelInfo.height = miplevel_height_in_block * block_edge_in_texel; currentMipmapLevelInfo.width = miplevel_width_in_block * block_edge_in_texel; + currentMipmapLevelInfo.depth = depth; currentMipmapLevelInfo.rowPitch = dst_pitch * block_size_in_bytes; Result.push_back(currentMipmapLevelInfo); if (!padded_row) { - T::template copy_mipmap_level((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, dst_pitch, miplevel_width_in_block); - offsetInSrc += miplevel_height_in_block * miplevel_width_in_block * block_size_in_bytes; + T::template copy_mipmap_level((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, depth, dst_pitch, miplevel_width_in_block); + offsetInSrc += miplevel_height_in_block * miplevel_width_in_block * block_size_in_bytes * depth; } else { - T::template copy_mipmap_level((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, dst_pitch, texture_width_in_block); - offsetInSrc += miplevel_height_in_block * texture_width_in_block * block_size_in_bytes; + T::template copy_mipmap_level((char*)dst + offsetInDst, (char*)src + offsetInSrc, miplevel_height_in_block, miplevel_width_in_block, depth, dst_pitch, texture_width_in_block); + offsetInSrc += miplevel_height_in_block * texture_width_in_block * block_size_in_bytes * depth; } offsetInDst += align(miplevel_height_in_block * dst_pitch * block_size_in_bytes, 512); miplevel_height_in_block = MAX2(miplevel_height_in_block / 2, 1); @@ -265,10 +266,22 @@ size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t rowPi std::vector upload_placed_texture(const rsx::texture &texture, size_t rowPitchAlignement, void* textureData) { - size_t w = texture.width(), h = texture.height(); - size_t depth = texture.depth(); - if (depth == 0) depth = 1; - if (texture.cubemap()) depth *= 6; + u16 w = texture.width(), h = texture.height(); + u16 depth; + u8 layer; + + if (texture.dimension() == 2) + { + depth = 1; + layer = texture.cubemap() ? 6 : 1; + } + else if (texture.dimension() == 3) + { + depth = texture.depth(); + layer = 1; + } + else + throw EXCEPTION("Unsupported texture dimension %d", texture.dimension()); int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); @@ -281,37 +294,37 @@ std::vector upload_placed_texture(const rsx::texture &texture, { case CELL_GCM_TEXTURE_A8R8G8B8: if (is_swizzled) - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); else - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); case CELL_GCM_TEXTURE_A1R5G5B5: case CELL_GCM_TEXTURE_A4R4G4B4: case CELL_GCM_TEXTURE_R5G6B5: if (is_swizzled) - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); else - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); case CELL_GCM_TEXTURE_COMPRESSED_DXT1: if (is_swizzled) - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); else - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); case CELL_GCM_TEXTURE_COMPRESSED_DXT23: if (is_swizzled) - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); else - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); case CELL_GCM_TEXTURE_COMPRESSED_DXT45: if (is_swizzled) - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); else - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); case CELL_GCM_TEXTURE_B8: - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); default: - return copy_texture_data(textureData, pixels, w, h, depth, texture.mipmap()); + return copy_texture_data(textureData, pixels, w, h, depth, layer, texture.mipmap()); } } diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.h b/rpcs3/Emu/RSX/Common/TextureUtils.h index 28e1fad5b8..4ba3a86549 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.h +++ b/rpcs3/Emu/RSX/Common/TextureUtils.h @@ -5,9 +5,10 @@ struct MipmapLevelInfo { size_t offset; - size_t width; - size_t height; - size_t rowPitch; + u16 width; + u16 height; + u16 depth; + u16 rowPitch; }; /** diff --git a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp index 2cfcacc802..6ba264aed9 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp @@ -47,13 +47,19 @@ std::string getFunctionImp(FUNCTION f) case FUNCTION::FUNCTION_TEXTURE_SAMPLE_PROJ: return "$t.Sample($tsampler, ($0.xy / $0.w) * $t_scale)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE_LOD: - return "$t.SampleLevel($tsampler, ($0.xy / $0.w) * $t_scale, $1)"; + return "$t.SampleLevel($tsampler, $0.xy * $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)"; + return "$t.SampleLevel($tsampler, $0.xyz, $1)"; + case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D: + return "$t.Sample($tsampler, $0.xyz)"; + case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ: + return "$t.Sample($tsampler, ($0.xyz / $0.w))"; + case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD: + return "$t.SampleLevel($tsampler, $0.xyz, $1)"; case FUNCTION::FUNCTION_DFDX: return "ddx($0)"; case FUNCTION::FUNCTION_DFDY: diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp index 33b36ffe2a..d6f55d2fd6 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp @@ -107,16 +107,16 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS) { OS << "cbuffer CONSTANT : register(b2)" << std::endl; OS << "{" << std::endl; - for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM]) + for (const ParamType &PT : m_parr.params[PF_PARAM_UNIFORM]) { - if (PT.type == "sampler2D" || PT.type == "samplerCube") + if (PT.type == "sampler2D" || PT.type == "samplerCube" || PT.type == "sampler3D") continue; for (ParamItem PI : PT.items) OS << " " << PT.type << " " << PI.name << ";" << std::endl; } OS << "};" << std::endl << std::endl; - for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM]) + for (const ParamType &PT : m_parr.params[PF_PARAM_UNIFORM]) { if (PT.type == "sampler2D") { @@ -127,9 +127,18 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS) OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl; } } + else if (PT.type == "sampler3D") + { + for (const ParamItem &PI : PT.items) + { + size_t textureIndex = atoi(PI.name.data() + 3); + OS << "Texture3D " << PI.name << " : register(t" << textureIndex + 16 << ");" << std::endl; + OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl; + } + } else if (PT.type == "samplerCube") { - for (ParamItem PI : PT.items) + for (const ParamItem &PI : PT.items) { size_t textureIndex = atoi(PI.name.data() + 3); OS << "TextureCube " << PI.name << " : register(t" << textureIndex << ");" << std::endl; @@ -166,23 +175,23 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS) }; OS << "void ps_impl(PixelInput In, inout float4 r0, inout float4 h0, inout float4 r1, inout float4 h2, inout float4 r2, inout float4 h4, inout float4 r3, inout float4 h6, inout float4 r4, inout float4 h8)" << std::endl; OS << "{" << std::endl; - for (ParamType PT : m_parr.params[PF_PARAM_IN]) + for (const ParamType &PT : m_parr.params[PF_PARAM_IN]) { - for (ParamItem PI : PT.items) + for (const ParamItem &PI : PT.items) OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl; } // A bit unclean, but works. OS << " " << "float4 gl_Position = In.Position;" << std::endl; // Declare output - for (ParamType PT : m_parr.params[PF_PARAM_NONE]) + for (const ParamType &PT : m_parr.params[PF_PARAM_NONE]) { - for (ParamItem PI : PT.items) + for (const ParamItem &PI : PT.items) if (output_value.find(PI.name) == output_value.end()) OS << " " << PT.type << " " << PI.name << " = float4(0., 0., 0., 0.);" << std::endl; } // Declare texture coordinate scaling component (to handle unormalized texture coordinates) - for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM]) + for (const ParamType &PT : m_parr.params[PF_PARAM_UNIFORM]) { if (PT.type != "sampler2D") continue; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index dab3df407d..291b578867 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -44,17 +44,20 @@ void D3D12GSRender::load_program() m_fragment_program.offset = shader_program & ~0x3; m_fragment_program.addr = rsx::get_address(m_fragment_program.offset, (shader_program & 0x3) - 1); m_fragment_program.ctrl = rsx::method_registers[NV4097_SET_SHADER_CONTROL]; - m_fragment_program.texture_dimensions.clear(); + std::array texture_dimensions; for (u32 i = 0; i < rsx::limits::textures_count; ++i) { if (!textures[i].enabled()) - m_fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d); + texture_dimensions[i] = texture_dimension::texture_dimension_2d; else if (textures[i].cubemap()) - m_fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_cubemap); + texture_dimensions[i] = texture_dimension::texture_dimension_cubemap; + else if (textures[i].dimension() == 3) + texture_dimensions[i] = texture_dimension::texture_dimension_3d; else - m_fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d); + texture_dimensions[i] = texture_dimension::texture_dimension_2d; } + m_fragment_program.set_texture_dimension(texture_dimensions); D3D12PipelineProperties prop = {}; prop.Topology = get_primitive_topology_type(draw_mode); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h index 831146f246..c2c771e45a 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h @@ -155,7 +155,7 @@ struct D3D12Traits { for (const ParamItem PI : PT.items) { - if (PT.type == "sampler2D" || PT.type == "samplerCube") + if (PT.type == "sampler2D" || PT.type == "samplerCube" || PT.type == "sampler3D") { size_t texture_unit = atoi(PI.name.c_str() + 3); fragmentProgramData.m_textureCount = std::max(texture_unit + 1, fragmentProgramData.m_textureCount); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp index 59a9674950..1d183d4042 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -40,6 +40,27 @@ D3D12_SAMPLER_DESC get_sampler_desc(const rsx::texture &texture) return samplerDesc; } +namespace +{ + CD3DX12_RESOURCE_DESC get_texture_description(const rsx::texture &texture) + { + const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + DXGI_FORMAT dxgi_format = get_texture_format(format); + + if (texture.dimension() == 2) // 2D texture or cubemap + { +// if (texture.depth() < 2); + size_t depth = (texture.cubemap()) ? 6 : 1; + return CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, texture.width(), texture.height(), (UINT)depth, texture.mipmap()); + } + else if (texture.dimension() == 3) // 3d texture + { + return CD3DX12_RESOURCE_DESC::Tex3D(dxgi_format, texture.width(), texture.height(), texture.depth(), texture.mipmap()); + } + throw EXCEPTION("Unknow texture dimension"); + } +} + /** * Create a texture residing in default heap and generate uploads commands in commandList, @@ -51,14 +72,6 @@ ComPtr upload_single_texture( ID3D12GraphicsCommandList *command_list, data_heap &texture_buffer_heap) { - size_t w = texture.width(), h = texture.height(); - size_t depth = texture.depth(); - if (depth == 0) depth = 1; - if (texture.cubemap()) depth *= 6; - - const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); - DXGI_FORMAT dxgi_format = get_texture_format(format); - size_t buffer_size = get_placed_texture_storage_size(texture, 256); size_t heap_offset = texture_buffer_heap.alloc(buffer_size); @@ -70,17 +83,19 @@ ComPtr upload_single_texture( CHECK_HRESULT(device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)w, (UINT)h, (UINT)depth, texture.mipmap()), + &get_texture_description(texture), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(result.GetAddressOf()) )); + const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + DXGI_FORMAT dxgi_format = get_texture_format(format); size_t mip_level = 0; for (const MipmapLevelInfo mli : mipInfos) { command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(result.Get(), (UINT)mip_level), 0, 0, 0, - &CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset, { dxgi_format, (UINT)mli.width, (UINT)mli.height, 1, (UINT)mli.rowPitch } }), nullptr); + &CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset, { dxgi_format, (UINT)mli.width, (UINT)mli.height, (UINT)mli.depth, (UINT)mli.rowPitch } }), nullptr); mip_level++; } @@ -114,7 +129,7 @@ void update_existing_texture( for (const MipmapLevelInfo mli : mipInfos) { command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(existing_texture, (UINT)miplevel), 0, 0, 0, - &CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset,{ dxgi_format, (UINT)mli.width, (UINT)mli.height, 1, (UINT)mli.rowPitch } }), nullptr); + &CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset,{ dxgi_format, (UINT)mli.width, (UINT)mli.height, (UINT)mli.depth, (UINT)mli.rowPitch } }), nullptr); miplevel++; } @@ -204,11 +219,16 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_ shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; shared_resource_view_desc.TextureCube.MipLevels = textures[i].mipmap(); } - else + else if (textures[i].dimension() == 2) { shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; shared_resource_view_desc.Texture2D.MipLevels = textures[i].mipmap(); } + else if (textures[i].dimension() == 3) + { + shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; + shared_resource_view_desc.Texture2D.MipLevels = textures[i].mipmap(); + } shared_resource_view_desc.Format = get_texture_format(format); switch (format) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 81e6d43978..a2ebfe5a9d 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -745,15 +745,19 @@ bool GLGSRender::load_program() fragment_program.addr = rsx::get_address(fragment_program.offset, (shader_program & 0x3) - 1); fragment_program.ctrl = rsx::method_registers[NV4097_SET_SHADER_CONTROL]; + std::array texture_dimensions; for (u32 i = 0; i < rsx::limits::textures_count; ++i) { if (!textures[i].enabled()) - fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d); + texture_dimensions[i] = texture_dimension::texture_dimension_2d; else if (textures[i].cubemap()) - fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_cubemap); + texture_dimensions[i] = texture_dimension::texture_dimension_cubemap; + else if (textures[i].dimension() == 3) + texture_dimensions[i] = texture_dimension::texture_dimension_3d; else - fragment_program.texture_dimensions.push_back(texture_dimension::texture_dimension_2d); + texture_dimensions[i] = texture_dimension::texture_dimension_2d; } + fragment_program.set_texture_dimension(texture_dimensions); __glcheck m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, nullptr); __glcheck m_program->use(); diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index 6ef842d959..a07064c192 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -204,11 +204,11 @@ static const std::string rsx_fp_op_names[] = "NULL", "BRK", "CAL", "IFE", "LOOP", "REP", "RET" }; -enum class texture_dimension +enum class texture_dimension : u8 { - texture_dimension_2d, - texture_dimension_2d_array, - texture_dimension_cubemap, + texture_dimension_2d = 0, + texture_dimension_cubemap = 1, + texture_dimension_3d = 2, }; struct RSXFragmentProgram @@ -217,13 +217,33 @@ struct RSXFragmentProgram u32 addr; u32 offset; u32 ctrl; - std::vector texture_dimensions; + u16 unnormalized_coords; + u32 texture_dimensions; + + texture_dimension get_texture_dimension(u8 id) const + { + return (texture_dimension)((texture_dimensions >> (id * 2)) & 0x3); + } + + void set_texture_dimension(const std::array &dimensions) + { + size_t id = 0; + for (const texture_dimension &dim : dimensions) + { + texture_dimensions &= ~(0x3 << (id * 2)); + u8 d = (u8)dim; + texture_dimensions |= ((d & 0x3) << (id * 2)); + id++; + } + } RSXFragmentProgram() : size(0) , addr(0) , offset(0) , ctrl(0) + , unnormalized_coords(0) + , texture_dimensions(0) { } };