diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index e56253c4c9..8c0e6663be 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -31,6 +31,9 @@ add_library(video_core STATIC renderer_opengl/gl_stream_buffer.h renderer_opengl/renderer_opengl.cpp renderer_opengl/renderer_opengl.h + textures/decoders.cpp + textures/decoders.h + textures/texture.h utils.h video_core.cpp video_core.h diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 4d9745e48d..ca1b150a7f 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -2,8 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "common/assert.h" #include "video_core/engines/maxwell_3d.h" +#include "video_core/textures/decoders.h" +#include "video_core/textures/texture.h" namespace Tegra { namespace Engines { @@ -160,6 +163,48 @@ void Maxwell3D::ProcessQueryGet() { void Maxwell3D::DrawArrays() { LOG_WARNING(HW_GPU, "Game requested a DrawArrays, ignoring"); + + auto& fragment_shader = state.shader_stages[static_cast(Regs::ShaderStage::Fragment)]; + auto& tex_info_buffer = fragment_shader.const_buffers[regs.tex_cb_index]; + ASSERT(tex_info_buffer.enabled && tex_info_buffer.address != 0); + + GPUVAddr tic_base_address = regs.tic.TICAddress(); + + GPUVAddr tex_info_buffer_end = tex_info_buffer.address + tex_info_buffer.size; + + for (GPUVAddr current_texture = tex_info_buffer.address + 0x20; + current_texture < tex_info_buffer_end; current_texture += 4) { + + Texture::TextureHandle tex_info{ + Memory::Read32(memory_manager.PhysicalToVirtualAddress(current_texture))}; + + if (tex_info.tic_id != 0 || tex_info.tsc_id != 0) { + GPUVAddr tic_address_gpu = + tic_base_address + tex_info.tic_id * sizeof(Texture::TICEntry); + VAddr tic_address_cpu = memory_manager.PhysicalToVirtualAddress(tic_address_gpu); + + Texture::TICEntry tic_entry; + Memory::ReadBlock(tic_address_cpu, &tic_entry, sizeof(Texture::TICEntry)); + + auto r_type = tic_entry.r_type.Value(); + auto g_type = tic_entry.g_type.Value(); + auto b_type = tic_entry.b_type.Value(); + auto a_type = tic_entry.a_type.Value(); + + // TODO(Subv): Different data types for separate components are not supported + ASSERT(r_type == g_type && r_type == b_type && r_type == a_type); + + auto format = tic_entry.format.Value(); + + auto texture = Texture::DecodeTexture( + memory_manager.PhysicalToVirtualAddress(tic_entry.Address()), + tic_entry.format.Value(), tic_entry.Width(), tic_entry.Height()); + + LOG_CRITICAL(HW_GPU, + "Fragment shader using texture TIC %08X TSC %08X at address %016" PRIX64, + tex_info.tic_id.Value(), tex_info.tsc_id.Value(), tic_entry.Address()); + } + } } void Maxwell3D::BindTextureInfoBuffer(const std::vector& parameters) { diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp new file mode 100644 index 0000000000..705e2e0665 --- /dev/null +++ b/src/video_core/textures/decoders.cpp @@ -0,0 +1,14 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "video_core/textures/decoders.h" + +namespace Tegra { +namespace Texture { + +std::vector DecodeTexture(VAddr address, TextureFormat format, u32 width, u32 height) { + return {}; +} +} +} // namespace Tegra diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h new file mode 100644 index 0000000000..e0d55600e3 --- /dev/null +++ b/src/video_core/textures/decoders.h @@ -0,0 +1,20 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "common/common_types.h" +#include "video_core/textures/texture.h" + +namespace Tegra { +namespace Texture { + +/** + * Decodes a swizzled texture into a RGBA8888 texture. + */ +std::vector DecodeTexture(VAddr address, TextureFormat format, u32 width, u32 height); + +} // namespace Texture +} // namespace Tegra diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h new file mode 100644 index 0000000000..3306d2ab20 --- /dev/null +++ b/src/video_core/textures/texture.h @@ -0,0 +1,57 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "video_core/memory_manager.h" + +namespace Tegra { +namespace Texture { + +enum class TextureFormat : u32 { + DXT1 = 0x24, +}; + +union TextureHandle { + u32 raw; + BitField<0, 20, u32> tic_id; + BitField<20, 12, u32> tsc_id; +}; + +struct TICEntry { + union { + u32 raw; + BitField<0, 7, TextureFormat> format; + BitField<7, 3, u32> r_type; + BitField<10, 3, u32> g_type; + BitField<13, 3, u32> b_type; + BitField<16, 3, u32> a_type; + }; + u32 address_low; + u16 address_high; + INSERT_PADDING_BYTES(6); + u16 width_minus_1; + INSERT_PADDING_BYTES(2); + u16 height_minus_1; + INSERT_PADDING_BYTES(10); + + GPUVAddr Address() const { + return static_cast((static_cast(address_high) << 32) | address_low); + } + + u32 Width() const { + return width_minus_1 + 1; + } + + u32 Height() const { + return height_minus_1 + 1; + } +}; +static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size"); + +} // namespace Texture +} // namespace Tegra