Compare commits
29 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3841ec4200 | ||
|
|
17ad56c1dc | ||
|
|
f633b0c875 | ||
|
|
e3b6f6c016 | ||
|
|
412b31ad72 | ||
|
|
aa26baa3db | ||
|
|
4ef392906b | ||
|
|
3f49210234 | ||
|
|
fe84842137 | ||
|
|
5367935d35 | ||
|
|
8a47e7e493 | ||
|
|
e90a12f80c | ||
|
|
d019bb16f6 | ||
|
|
057170928c | ||
|
|
de18592179 | ||
|
|
60e6e8953e | ||
|
|
2985056340 | ||
|
|
ce4f159b1c | ||
|
|
6a999cf800 | ||
|
|
43d98ca8fe | ||
|
|
5b3fab6766 | ||
|
|
b2c1672e10 | ||
|
|
d3f9ea90e7 | ||
|
|
48d4efbd69 | ||
|
|
a3e82e8e1f | ||
|
|
ac09b5a2e9 | ||
|
|
6b63aaa5b4 | ||
|
|
db5f2bfa7e | ||
|
|
f600f6eebd |
@@ -7,7 +7,7 @@ yuzu is an experimental open-source emulator for the Nintendo Switch from the cr
|
||||
|
||||
It is written in C++ with portability in mind, with builds actively maintained for Windows, Linux and macOS. The emulator is currently only useful for homebrew development and research purposes.
|
||||
|
||||
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu does not run any commercial Switch games. yuzu can boot some games, to varying degrees of success, but does not implement any of the necessary GPU features to render 3D graphics.
|
||||
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu cannot play any commercial games without major problems. yuzu can boot some games, to varying degrees of success, but does not implement any of the necessary GPU features to render 3D graphics.
|
||||
|
||||
yuzu is licensed under the GPLv2 (or any later version). Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
@@ -128,6 +129,8 @@ void NVFlinger::Compose() {
|
||||
// Search for a queued buffer and acquire it
|
||||
auto buffer = buffer_queue->AcquireBuffer();
|
||||
|
||||
MicroProfileFlip();
|
||||
|
||||
if (buffer == boost::none) {
|
||||
// There was no queued buffer to draw, render previous frame
|
||||
Core::System::GetInstance().perf_stats.EndGameFrame();
|
||||
|
||||
@@ -218,6 +218,10 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
|
||||
Texture::TICEntry tic_entry;
|
||||
Memory::ReadBlock(tic_address_cpu, &tic_entry, sizeof(Texture::TICEntry));
|
||||
|
||||
ASSERT_MSG(tic_entry.header_version == Texture::TICHeaderVersion::BlockLinear ||
|
||||
tic_entry.header_version == Texture::TICHeaderVersion::Pitch,
|
||||
"TIC versions other than BlockLinear or Pitch are unimplemented");
|
||||
|
||||
ASSERT_MSG((tic_entry.texture_type == Texture::TextureType::Texture2D) ||
|
||||
(tic_entry.texture_type == Texture::TextureType::Texture2DNoMipmap),
|
||||
"Texture types other than Texture2D are unimplemented");
|
||||
|
||||
@@ -319,14 +319,15 @@ public:
|
||||
}
|
||||
} rt[NumRenderTargets];
|
||||
|
||||
f32 viewport_scale_x;
|
||||
f32 viewport_scale_y;
|
||||
f32 viewport_scale_z;
|
||||
u32 viewport_translate_x;
|
||||
u32 viewport_translate_y;
|
||||
u32 viewport_translate_z;
|
||||
|
||||
INSERT_PADDING_WORDS(0x7A);
|
||||
struct {
|
||||
f32 scale_x;
|
||||
f32 scale_y;
|
||||
f32 scale_z;
|
||||
u32 translate_x;
|
||||
u32 translate_y;
|
||||
u32 translate_z;
|
||||
INSERT_PADDING_WORDS(2);
|
||||
} viewport_transform[NumViewports];
|
||||
|
||||
struct {
|
||||
union {
|
||||
@@ -656,12 +657,7 @@ private:
|
||||
"Field " #field_name " has invalid position")
|
||||
|
||||
ASSERT_REG_POSITION(rt, 0x200);
|
||||
ASSERT_REG_POSITION(viewport_scale_x, 0x280);
|
||||
ASSERT_REG_POSITION(viewport_scale_y, 0x281);
|
||||
ASSERT_REG_POSITION(viewport_scale_z, 0x282);
|
||||
ASSERT_REG_POSITION(viewport_translate_x, 0x283);
|
||||
ASSERT_REG_POSITION(viewport_translate_y, 0x284);
|
||||
ASSERT_REG_POSITION(viewport_translate_z, 0x285);
|
||||
ASSERT_REG_POSITION(viewport_transform[0], 0x280);
|
||||
ASSERT_REG_POSITION(viewport, 0x300);
|
||||
ASSERT_REG_POSITION(vertex_buffer, 0x35D);
|
||||
ASSERT_REG_POSITION(zeta, 0x3F8);
|
||||
|
||||
@@ -90,6 +90,7 @@ union OpCode {
|
||||
enum class Id : u64 {
|
||||
TEXS = 0x6C,
|
||||
IPA = 0xE0,
|
||||
FMUL32_IMM = 0x1E,
|
||||
FFMA_IMM = 0x65,
|
||||
FFMA_CR = 0x93,
|
||||
FFMA_RC = 0xA3,
|
||||
@@ -142,6 +143,7 @@ union OpCode {
|
||||
|
||||
switch (op2) {
|
||||
case Id::IPA:
|
||||
case Id::FMUL32_IMM:
|
||||
return op2;
|
||||
}
|
||||
|
||||
@@ -235,6 +237,7 @@ union OpCode {
|
||||
info_table[Id::FMUL_R] = {Type::Arithmetic, "fmul_r"};
|
||||
info_table[Id::FMUL_C] = {Type::Arithmetic, "fmul_c"};
|
||||
info_table[Id::FMUL_IMM] = {Type::Arithmetic, "fmul_imm"};
|
||||
info_table[Id::FMUL32_IMM] = {Type::Arithmetic, "fmul32_imm"};
|
||||
info_table[Id::FSETP_C] = {Type::Arithmetic, "fsetp_c"};
|
||||
info_table[Id::FSETP_R] = {Type::Arithmetic, "fsetp_r"};
|
||||
info_table[Id::EXIT] = {Type::Trivial, "exit"};
|
||||
@@ -309,7 +312,8 @@ union Instruction {
|
||||
BitField<39, 8, Register> gpr39;
|
||||
|
||||
union {
|
||||
BitField<20, 19, u64> imm20;
|
||||
BitField<20, 19, u64> imm20_19;
|
||||
BitField<20, 32, u64> imm20_32;
|
||||
BitField<45, 1, u64> negate_b;
|
||||
BitField<46, 1, u64> abs_a;
|
||||
BitField<48, 1, u64> negate_a;
|
||||
@@ -317,14 +321,21 @@ union Instruction {
|
||||
BitField<50, 1, u64> abs_d;
|
||||
BitField<56, 1, u64> negate_imm;
|
||||
|
||||
float GetImm20() const {
|
||||
float GetImm20_19() const {
|
||||
float result{};
|
||||
u32 imm{static_cast<u32>(imm20)};
|
||||
u32 imm{static_cast<u32>(imm20_19)};
|
||||
imm <<= 12;
|
||||
imm |= negate_imm ? 0x80000000 : 0;
|
||||
std::memcpy(&result, &imm, sizeof(imm));
|
||||
return result;
|
||||
}
|
||||
|
||||
float GetImm20_32() const {
|
||||
float result{};
|
||||
u32 imm{static_cast<u32>(imm20_32)};
|
||||
std::memcpy(&result, &imm, sizeof(imm));
|
||||
return result;
|
||||
}
|
||||
} alu;
|
||||
|
||||
union {
|
||||
|
||||
@@ -524,8 +524,11 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebu
|
||||
src_params.height = framebuffer.height;
|
||||
src_params.stride = pixel_stride;
|
||||
src_params.is_tiled = true;
|
||||
src_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight;
|
||||
src_params.pixel_format =
|
||||
SurfaceParams::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format);
|
||||
src_params.component_type =
|
||||
SurfaceParams::ComponentTypeFromGPUPixelFormat(framebuffer.pixel_format);
|
||||
src_params.UpdateParams();
|
||||
|
||||
MathUtil::Rectangle<u32> src_rect;
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "common/math_util.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/swap.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
@@ -37,6 +36,7 @@
|
||||
|
||||
using SurfaceType = SurfaceParams::SurfaceType;
|
||||
using PixelFormat = SurfaceParams::PixelFormat;
|
||||
using ComponentType = SurfaceParams::ComponentType;
|
||||
|
||||
struct FormatTuple {
|
||||
GLint internal_format;
|
||||
@@ -48,31 +48,24 @@ struct FormatTuple {
|
||||
u32 compression_factor;
|
||||
};
|
||||
|
||||
static constexpr std::array<FormatTuple, 1> fb_format_tuples = {{
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8
|
||||
static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false, 1}, // ABGR8
|
||||
{GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false, 1}, // B5G6R5
|
||||
{GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1
|
||||
{GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT23
|
||||
{GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT45
|
||||
}};
|
||||
|
||||
static constexpr std::array<FormatTuple, 7> tex_format_tuples = {{
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8
|
||||
{GL_RGB5_A1, GL_RGB, GL_UNSIGNED_SHORT_5_5_5_1, false, 1}, // RGB5A1
|
||||
{GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false, 1}, // RGB565
|
||||
{GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT, false, 1}, // R11FG11FB10F
|
||||
{GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // BC1
|
||||
{GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // BC2
|
||||
{GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // BC3
|
||||
}};
|
||||
|
||||
static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) {
|
||||
static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
|
||||
const SurfaceType type = SurfaceParams::GetFormatType(pixel_format);
|
||||
if (type == SurfaceType::Color) {
|
||||
ASSERT(static_cast<size_t>(pixel_format) < fb_format_tuples.size());
|
||||
return fb_format_tuples[static_cast<unsigned int>(pixel_format)];
|
||||
if (type == SurfaceType::ColorTexture) {
|
||||
ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
|
||||
// For now only UNORM components are supported
|
||||
ASSERT(component_type == ComponentType::UNorm);
|
||||
return tex_format_tuples[static_cast<unsigned int>(pixel_format)];
|
||||
} else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) {
|
||||
// TODO(Subv): Implement depth formats
|
||||
ASSERT_MSG(false, "Unimplemented");
|
||||
} else if (type == SurfaceType::Texture) {
|
||||
ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
|
||||
return tex_format_tuples[static_cast<unsigned int>(pixel_format)];
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
@@ -91,80 +84,42 @@ static u16 GetResolutionScaleFactor() {
|
||||
}
|
||||
|
||||
template <bool morton_to_gl, PixelFormat format>
|
||||
void MortonCopy(u32 stride, u32 height, u32 block_height, u8* gl_buffer, VAddr base, VAddr start,
|
||||
void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, VAddr base, VAddr start,
|
||||
VAddr end) {
|
||||
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
|
||||
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
|
||||
|
||||
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the
|
||||
// configuration for this and perform more generic un/swizzle
|
||||
LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
|
||||
VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
|
||||
Memory::GetPointer(base), gl_buffer, morton_to_gl);
|
||||
if (morton_to_gl) {
|
||||
auto data = Tegra::Texture::UnswizzleTexture(
|
||||
base, SurfaceParams::TextureFormatFromPixelFormat(format), stride, height,
|
||||
block_height);
|
||||
std::memcpy(gl_buffer, data.data(), data.size());
|
||||
} else {
|
||||
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check
|
||||
// the configuration for this and perform more generic un/swizzle
|
||||
LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
|
||||
VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
|
||||
Memory::GetPointer(base), gl_buffer, morton_to_gl);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void MortonCopy<true, PixelFormat::BC1>(u32 stride, u32 height, u32 block_height, u8* gl_buffer,
|
||||
VAddr base, VAddr start, VAddr end) {
|
||||
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::BC1) / 8;
|
||||
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::BC1);
|
||||
|
||||
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the
|
||||
// configuration for this and perform more generic un/swizzle
|
||||
LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
|
||||
auto data = Tegra::Texture::UnswizzleTexture(base, Tegra::Texture::TextureFormat::BC1, stride,
|
||||
height, block_height);
|
||||
std::memcpy(gl_buffer, data.data(), data.size());
|
||||
}
|
||||
|
||||
template <>
|
||||
void MortonCopy<true, PixelFormat::BC2>(u32 stride, u32 height, u32 block_height, u8* gl_buffer,
|
||||
VAddr base, VAddr start, VAddr end) {
|
||||
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::BC2) / 8;
|
||||
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::BC2);
|
||||
|
||||
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the
|
||||
// configuration for this and perform more generic un/swizzle
|
||||
LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
|
||||
auto data = Tegra::Texture::UnswizzleTexture(base, Tegra::Texture::TextureFormat::BC2, stride,
|
||||
height, block_height);
|
||||
std::memcpy(gl_buffer, data.data(), data.size());
|
||||
}
|
||||
|
||||
template <>
|
||||
void MortonCopy<true, PixelFormat::BC3>(u32 stride, u32 height, u32 block_height, u8* gl_buffer,
|
||||
VAddr base, VAddr start, VAddr end) {
|
||||
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::BC3) / 8;
|
||||
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::BC3);
|
||||
|
||||
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the
|
||||
// configuration for this and perform more generic un/swizzle
|
||||
// NGLOG_CRITICAL(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
|
||||
auto data = Tegra::Texture::UnswizzleTexture(base, Tegra::Texture::TextureFormat::BC3, stride,
|
||||
height, block_height);
|
||||
std::memcpy(gl_buffer, data.data(), data.size());
|
||||
}
|
||||
|
||||
static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr), 7> morton_to_gl_fns =
|
||||
{
|
||||
MortonCopy<true, PixelFormat::RGBA8>, // RGBA8
|
||||
MortonCopy<true, PixelFormat::RGB5A1>, // RGB5A1
|
||||
MortonCopy<true, PixelFormat::RGB565>, // RGB565
|
||||
MortonCopy<true, PixelFormat::RG11FB10F>, // RG11FB10F
|
||||
MortonCopy<true, PixelFormat::BC1>, // BC1
|
||||
MortonCopy<true, PixelFormat::BC2>, // BC2
|
||||
MortonCopy<true, PixelFormat::BC3>, // BC3
|
||||
static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
|
||||
SurfaceParams::MaxPixelFormat>
|
||||
morton_to_gl_fns = {
|
||||
MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>,
|
||||
MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
|
||||
MortonCopy<true, PixelFormat::DXT45>,
|
||||
};
|
||||
|
||||
static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr), 7> gl_to_morton_fns =
|
||||
{
|
||||
MortonCopy<false, PixelFormat::RGBA8>, // RGBA8
|
||||
MortonCopy<false, PixelFormat::RGB5A1>, // RGB5A1
|
||||
MortonCopy<false, PixelFormat::RGB565>, // RGB565
|
||||
MortonCopy<false, PixelFormat::RG11FB10F>, // RG11FB10F
|
||||
MortonCopy<false, PixelFormat::BC1>, // BC1
|
||||
MortonCopy<false, PixelFormat::BC2>, // BC2
|
||||
MortonCopy<false, PixelFormat::BC3>, // BC3
|
||||
static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
|
||||
SurfaceParams::MaxPixelFormat>
|
||||
gl_to_morton_fns = {
|
||||
MortonCopy<false, PixelFormat::ABGR8>,
|
||||
MortonCopy<false, PixelFormat::B5G6R5>,
|
||||
// TODO(Subv): Swizzling the DXT1/DXT23/DXT45 formats is not yet supported
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
};
|
||||
|
||||
// Allocate an uninitialized texture of appropriate size and format for the surface
|
||||
@@ -213,7 +168,7 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec
|
||||
|
||||
u32 buffers = 0;
|
||||
|
||||
if (type == SurfaceType::Color || type == SurfaceType::Texture) {
|
||||
if (type == SurfaceType::ColorTexture) {
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex,
|
||||
0);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
||||
@@ -341,15 +296,18 @@ MathUtil::Rectangle<u32> SurfaceParams::GetScaledSubRect(const SurfaceParams& su
|
||||
|
||||
bool SurfaceParams::ExactMatch(const SurfaceParams& other_surface) const {
|
||||
return std::tie(other_surface.addr, other_surface.width, other_surface.height,
|
||||
other_surface.stride, other_surface.pixel_format, other_surface.is_tiled) ==
|
||||
std::tie(addr, width, height, stride, pixel_format, is_tiled) &&
|
||||
other_surface.stride, other_surface.block_height, other_surface.pixel_format,
|
||||
other_surface.component_type,
|
||||
other_surface.is_tiled) == std::tie(addr, width, height, stride, block_height,
|
||||
pixel_format, component_type, is_tiled) &&
|
||||
pixel_format != PixelFormat::Invalid;
|
||||
}
|
||||
|
||||
bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const {
|
||||
return sub_surface.addr >= addr && sub_surface.end <= end &&
|
||||
sub_surface.pixel_format == pixel_format && pixel_format != PixelFormat::Invalid &&
|
||||
sub_surface.is_tiled == is_tiled &&
|
||||
sub_surface.is_tiled == is_tiled && sub_surface.block_height == block_height &&
|
||||
sub_surface.component_type == component_type &&
|
||||
(sub_surface.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 &&
|
||||
(sub_surface.stride == stride || sub_surface.height <= (is_tiled ? 8u : 1u)) &&
|
||||
GetSubRect(sub_surface).left + sub_surface.width <= stride;
|
||||
@@ -358,7 +316,8 @@ bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const {
|
||||
bool SurfaceParams::CanExpand(const SurfaceParams& expanded_surface) const {
|
||||
return pixel_format != PixelFormat::Invalid && pixel_format == expanded_surface.pixel_format &&
|
||||
addr <= expanded_surface.end && expanded_surface.addr <= end &&
|
||||
is_tiled == expanded_surface.is_tiled && stride == expanded_surface.stride &&
|
||||
is_tiled == expanded_surface.is_tiled && block_height == expanded_surface.block_height &&
|
||||
component_type == expanded_surface.component_type && stride == expanded_surface.stride &&
|
||||
(std::max(expanded_surface.addr, addr) - std::min(expanded_surface.addr, addr)) %
|
||||
BytesInPixels(stride * (is_tiled ? 8 : 1)) ==
|
||||
0;
|
||||
@@ -369,6 +328,10 @@ bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const {
|
||||
end < texcopy_params.end) {
|
||||
return false;
|
||||
}
|
||||
if (texcopy_params.block_height != block_height ||
|
||||
texcopy_params.component_type != component_type)
|
||||
return false;
|
||||
|
||||
if (texcopy_params.width != texcopy_params.stride) {
|
||||
const u32 tile_stride = static_cast<u32>(BytesInPixels(stride * (is_tiled ? 8 : 1)));
|
||||
return (texcopy_params.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 &&
|
||||
@@ -511,20 +474,13 @@ void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) {
|
||||
const u64 start_offset = load_start - addr;
|
||||
|
||||
if (!is_tiled) {
|
||||
ASSERT(type == SurfaceType::Color);
|
||||
const u32 bytes_per_pixel{GetFormatBpp() >> 3};
|
||||
|
||||
std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset,
|
||||
bytes_per_pixel * width * height);
|
||||
|
||||
// TODO(bunnei): HACK HACK HACK - Remove before checkin!
|
||||
u32* gl_words = reinterpret_cast<u32*>(&gl_buffer[start_offset]);
|
||||
for (unsigned index = 0; index < width * height; ++index) {
|
||||
gl_words[index] = Common::swap32(gl_words[index]);
|
||||
}
|
||||
|
||||
} else {
|
||||
morton_to_gl_fns[static_cast<size_t>(pixel_format)](
|
||||
stride, height, block_height, &gl_buffer[0], addr, load_start, load_end);
|
||||
stride, block_height, height, &gl_buffer[0], addr, load_start, load_end);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,11 +521,10 @@ void CachedSurface::FlushGLBuffer(VAddr flush_start, VAddr flush_end) {
|
||||
if (backup_bytes)
|
||||
std::memcpy(&dst_buffer[coarse_start_offset], &backup_data[0], backup_bytes);
|
||||
} else if (!is_tiled) {
|
||||
ASSERT(type == SurfaceType::Color);
|
||||
std::memcpy(dst_buffer + start_offset, &gl_buffer[start_offset], flush_end - flush_start);
|
||||
} else {
|
||||
gl_to_morton_fns[static_cast<size_t>(pixel_format)](
|
||||
stride, height, block_height, &gl_buffer[0], addr, flush_start, flush_end);
|
||||
stride, block_height, height, &gl_buffer[0], addr, flush_start, flush_end);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,7 +543,7 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint
|
||||
GLint y0 = static_cast<GLint>(rect.bottom);
|
||||
size_t buffer_offset = (y0 * stride + x0) * GetGLBytesPerPixel(pixel_format);
|
||||
|
||||
const FormatTuple& tuple = GetFormatTuple(pixel_format);
|
||||
const FormatTuple& tuple = GetFormatTuple(pixel_format, component_type);
|
||||
GLuint target_tex = texture.handle;
|
||||
|
||||
// If not 1x scale, create 1x texture that we will blit from to replace texture subrect in
|
||||
@@ -661,7 +616,7 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
|
||||
OpenGLState prev_state = state;
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
|
||||
const FormatTuple& tuple = GetFormatTuple(pixel_format);
|
||||
const FormatTuple& tuple = GetFormatTuple(pixel_format, component_type);
|
||||
|
||||
// Ensure no bad interactions with GL_PACK_ALIGNMENT
|
||||
ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0);
|
||||
@@ -694,7 +649,7 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
|
||||
state.draw.read_framebuffer = read_fb_handle;
|
||||
state.Apply();
|
||||
|
||||
if (type == SurfaceType::Color || type == SurfaceType::Texture) {
|
||||
if (type == SurfaceType::ColorTexture) {
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
texture.handle, 0);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||
@@ -1072,11 +1027,26 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu
|
||||
params.width = config.tic.Width();
|
||||
params.height = config.tic.Height();
|
||||
params.is_tiled = config.tic.IsTiled();
|
||||
params.block_height = config.tic.BlockHeight();
|
||||
params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(config.tic.format);
|
||||
|
||||
// TODO(Subv): Different types per component are not supported.
|
||||
ASSERT(config.tic.r_type.Value() == config.tic.g_type.Value() &&
|
||||
config.tic.r_type.Value() == config.tic.b_type.Value() &&
|
||||
config.tic.r_type.Value() == config.tic.a_type.Value());
|
||||
|
||||
params.component_type = SurfaceParams::ComponentTypeFromTexture(config.tic.r_type.Value());
|
||||
|
||||
if (config.tic.IsTiled()) {
|
||||
params.block_height = config.tic.BlockHeight();
|
||||
} else {
|
||||
// Use the texture-provided stride value if the texture isn't tiled.
|
||||
params.stride = params.PixelsInBytes(config.tic.Pitch());
|
||||
}
|
||||
|
||||
params.UpdateParams();
|
||||
|
||||
if (config.tic.Width() % 8 != 0 || config.tic.Height() % 8 != 0) {
|
||||
if (config.tic.Width() % 8 != 0 || config.tic.Height() % 8 != 0 ||
|
||||
params.stride != params.width) {
|
||||
Surface src_surface;
|
||||
MathUtil::Rectangle<u32> rect;
|
||||
std::tie(src_surface, rect) = GetSurfaceSubRect(params, ScaleMatch::Ignore, true);
|
||||
@@ -1127,10 +1097,13 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
||||
color_params.res_scale = resolution_scale_factor;
|
||||
color_params.width = config.width;
|
||||
color_params.height = config.height;
|
||||
// TODO(Subv): Can framebuffers use a different block height?
|
||||
color_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight;
|
||||
SurfaceParams depth_params = color_params;
|
||||
|
||||
color_params.addr = memory_manager->PhysicalToVirtualAddress(config.Address());
|
||||
color_params.pixel_format = SurfaceParams::PixelFormatFromRenderTargetFormat(config.format);
|
||||
color_params.component_type = SurfaceParams::ComponentTypeFromRenderTarget(config.format);
|
||||
color_params.UpdateParams();
|
||||
|
||||
ASSERT_MSG(!using_depth_fb, "depth buffer is unimplemented");
|
||||
@@ -1326,7 +1299,6 @@ void RasterizerCacheOpenGL::InvalidateRegion(VAddr addr, u64 size, const Surface
|
||||
const SurfaceInterval invalid_interval(addr, addr + size);
|
||||
|
||||
if (region_owner != nullptr) {
|
||||
ASSERT(region_owner->type != SurfaceType::Texture);
|
||||
ASSERT(addr >= region_owner->addr && addr + size <= region_owner->end);
|
||||
// Surfaces can't have a gap
|
||||
ASSERT(region_owner->width == region_owner->stride);
|
||||
@@ -1388,7 +1360,8 @@ Surface RasterizerCacheOpenGL::CreateSurface(const SurfaceParams& params) {
|
||||
|
||||
surface->gl_buffer_size = 0;
|
||||
surface->invalid_regions.insert(surface->GetInterval());
|
||||
AllocateSurfaceTexture(surface->texture.handle, GetFormatTuple(surface->pixel_format),
|
||||
AllocateSurfaceTexture(surface->texture.handle,
|
||||
GetFormatTuple(surface->pixel_format, surface->component_type),
|
||||
surface->GetScaledWidth(), surface->GetScaledHeight());
|
||||
|
||||
return surface;
|
||||
|
||||
@@ -52,41 +52,45 @@ enum class ScaleMatch {
|
||||
|
||||
struct SurfaceParams {
|
||||
enum class PixelFormat {
|
||||
// Texture and color buffer formats
|
||||
RGBA8 = 0,
|
||||
RGB5A1 = 1,
|
||||
RGB565 = 2,
|
||||
RG11FB10F = 3,
|
||||
|
||||
// Compressed Texture formats
|
||||
BC1 = 4,
|
||||
BC2 = 5,
|
||||
BC3 = 6,
|
||||
ABGR8 = 0,
|
||||
B5G6R5 = 1,
|
||||
DXT1 = 2,
|
||||
DXT23 = 3,
|
||||
DXT45 = 4,
|
||||
|
||||
Max,
|
||||
Invalid = 255,
|
||||
};
|
||||
|
||||
static constexpr size_t MaxPixelFormat = static_cast<size_t>(PixelFormat::Max);
|
||||
|
||||
enum class ComponentType {
|
||||
Invalid = 0,
|
||||
SNorm = 1,
|
||||
UNorm = 2,
|
||||
SInt = 3,
|
||||
UInt = 4,
|
||||
Float = 5,
|
||||
};
|
||||
|
||||
enum class SurfaceType {
|
||||
Color = 0,
|
||||
Texture = 1,
|
||||
Depth = 2,
|
||||
DepthStencil = 3,
|
||||
Fill = 4,
|
||||
Invalid = 5
|
||||
ColorTexture = 0,
|
||||
Depth = 1,
|
||||
DepthStencil = 2,
|
||||
Fill = 3,
|
||||
Invalid = 4,
|
||||
};
|
||||
|
||||
static constexpr unsigned int GetFormatBpp(PixelFormat format) {
|
||||
if (format == PixelFormat::Invalid)
|
||||
return 0;
|
||||
|
||||
constexpr std::array<unsigned int, 7> bpp_table = {
|
||||
32, // RGBA8
|
||||
16, // RGB5A1
|
||||
16, // RGB565
|
||||
32, // RG11FB10F
|
||||
64, // BC1
|
||||
128, // BC2
|
||||
128, // BC3
|
||||
constexpr std::array<unsigned int, MaxPixelFormat> bpp_table = {
|
||||
32, // ABGR8
|
||||
16, // B5G6R5
|
||||
64, // DXT1
|
||||
128, // DXT23
|
||||
128, // DXT45
|
||||
};
|
||||
|
||||
ASSERT(static_cast<size_t>(format) < bpp_table.size());
|
||||
@@ -99,7 +103,7 @@ struct SurfaceParams {
|
||||
static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
|
||||
switch (format) {
|
||||
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
||||
return PixelFormat::RGBA8;
|
||||
return PixelFormat::ABGR8;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
@@ -109,7 +113,7 @@ struct SurfaceParams {
|
||||
static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
|
||||
switch (format) {
|
||||
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
||||
return PixelFormat::RGBA8;
|
||||
return PixelFormat::ABGR8;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
@@ -120,13 +124,67 @@ struct SurfaceParams {
|
||||
// TODO(Subv): Properly implement this
|
||||
switch (format) {
|
||||
case Tegra::Texture::TextureFormat::A8R8G8B8:
|
||||
return PixelFormat::RGBA8;
|
||||
case Tegra::Texture::TextureFormat::BC1:
|
||||
return PixelFormat::BC1;
|
||||
case Tegra::Texture::TextureFormat::BC2:
|
||||
return PixelFormat::BC2;
|
||||
case Tegra::Texture::TextureFormat::BC3:
|
||||
return PixelFormat::BC3;
|
||||
return PixelFormat::ABGR8;
|
||||
case Tegra::Texture::TextureFormat::B5G6R5:
|
||||
return PixelFormat::B5G6R5;
|
||||
case Tegra::Texture::TextureFormat::DXT1:
|
||||
return PixelFormat::DXT1;
|
||||
case Tegra::Texture::TextureFormat::DXT23:
|
||||
return PixelFormat::DXT23;
|
||||
case Tegra::Texture::TextureFormat::DXT45:
|
||||
return PixelFormat::DXT45;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static Tegra::Texture::TextureFormat TextureFormatFromPixelFormat(PixelFormat format) {
|
||||
// TODO(Subv): Properly implement this
|
||||
switch (format) {
|
||||
case PixelFormat::ABGR8:
|
||||
return Tegra::Texture::TextureFormat::A8R8G8B8;
|
||||
case PixelFormat::B5G6R5:
|
||||
return Tegra::Texture::TextureFormat::B5G6R5;
|
||||
case PixelFormat::DXT1:
|
||||
return Tegra::Texture::TextureFormat::DXT1;
|
||||
case PixelFormat::DXT23:
|
||||
return Tegra::Texture::TextureFormat::DXT23;
|
||||
case PixelFormat::DXT45:
|
||||
return Tegra::Texture::TextureFormat::DXT45;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
|
||||
// TODO(Subv): Implement more component types
|
||||
switch (type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return ComponentType::UNorm;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
|
||||
// TODO(Subv): Implement more render targets
|
||||
switch (format) {
|
||||
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
||||
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
||||
return ComponentType::UNorm;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static ComponentType ComponentTypeFromGPUPixelFormat(
|
||||
Tegra::FramebufferConfig::PixelFormat format) {
|
||||
switch (format) {
|
||||
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
||||
return ComponentType::UNorm;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
@@ -137,8 +195,7 @@ struct SurfaceParams {
|
||||
SurfaceType a_type = GetFormatType(pixel_format_a);
|
||||
SurfaceType b_type = GetFormatType(pixel_format_b);
|
||||
|
||||
if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) &&
|
||||
(b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) {
|
||||
if (a_type == SurfaceType::ColorTexture && b_type == SurfaceType::ColorTexture) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -154,12 +211,8 @@ struct SurfaceParams {
|
||||
}
|
||||
|
||||
static SurfaceType GetFormatType(PixelFormat pixel_format) {
|
||||
if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::RGBA8)) {
|
||||
return SurfaceType::Color;
|
||||
}
|
||||
|
||||
if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::BC3)) {
|
||||
return SurfaceType::Texture;
|
||||
if (static_cast<size_t>(pixel_format) < MaxPixelFormat) {
|
||||
return SurfaceType::ColorTexture;
|
||||
}
|
||||
|
||||
// TODO(Subv): Implement the other formats
|
||||
@@ -234,9 +287,10 @@ struct SurfaceParams {
|
||||
u32 block_height = 0;
|
||||
u16 res_scale = 1;
|
||||
|
||||
bool is_tiled = true;
|
||||
bool is_tiled = false;
|
||||
PixelFormat pixel_format = PixelFormat::Invalid;
|
||||
SurfaceType type = SurfaceType::Invalid;
|
||||
ComponentType component_type = ComponentType::Invalid;
|
||||
};
|
||||
|
||||
struct CachedSurface : SurfaceParams {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/engines/shader_bytecode.h"
|
||||
@@ -109,12 +110,25 @@ private:
|
||||
|
||||
class ShaderWriter {
|
||||
public:
|
||||
void AddLine(const std::string& text) {
|
||||
void AddLine(std::string_view text) {
|
||||
DEBUG_ASSERT(scope >= 0);
|
||||
if (!text.empty()) {
|
||||
shader_source += std::string(static_cast<size_t>(scope) * 4, ' ');
|
||||
AppendIndentation();
|
||||
}
|
||||
shader_source += text + '\n';
|
||||
shader_source += text;
|
||||
AddNewLine();
|
||||
}
|
||||
|
||||
void AddLine(char character) {
|
||||
DEBUG_ASSERT(scope >= 0);
|
||||
AppendIndentation();
|
||||
shader_source += character;
|
||||
AddNewLine();
|
||||
}
|
||||
|
||||
void AddNewLine() {
|
||||
DEBUG_ASSERT(scope >= 0);
|
||||
shader_source += '\n';
|
||||
}
|
||||
|
||||
std::string GetResult() {
|
||||
@@ -124,6 +138,10 @@ public:
|
||||
int scope = 0;
|
||||
|
||||
private:
|
||||
void AppendIndentation() {
|
||||
shader_source.append(static_cast<size_t>(scope) * 4, ' ');
|
||||
}
|
||||
|
||||
std::string shader_source;
|
||||
};
|
||||
|
||||
@@ -190,9 +208,14 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates code representing an immediate value
|
||||
static std::string GetImmediate(const Instruction& instr) {
|
||||
return std::to_string(instr.alu.GetImm20());
|
||||
/// Generates code representing a 19-bit immediate value
|
||||
static std::string GetImmediate19(const Instruction& instr) {
|
||||
return std::to_string(instr.alu.GetImm20_19());
|
||||
}
|
||||
|
||||
/// Generates code representing a 32-bit immediate value
|
||||
static std::string GetImmediate32(const Instruction& instr) {
|
||||
return std::to_string(instr.alu.GetImm20_32());
|
||||
}
|
||||
|
||||
/// Generates code representing a temporary (GPR) register.
|
||||
@@ -276,7 +299,7 @@ private:
|
||||
std::string op_b = instr.alu.negate_b ? "-" : "";
|
||||
|
||||
if (instr.is_b_imm) {
|
||||
op_b += GetImmediate(instr);
|
||||
op_b += GetImmediate19(instr);
|
||||
} else {
|
||||
if (instr.is_b_gpr) {
|
||||
op_b += GetRegister(instr.gpr20);
|
||||
@@ -296,6 +319,11 @@ private:
|
||||
SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FMUL32_IMM: {
|
||||
// fmul32i doesn't have abs or neg bits.
|
||||
SetDest(0, dest, GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FADD_C:
|
||||
case OpCode::Id::FADD_R:
|
||||
case OpCode::Id::FADD_IMM: {
|
||||
@@ -336,7 +364,7 @@ private:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {} ({}): {}",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name, instr.hex);
|
||||
// UNREACHABLE();
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -364,7 +392,7 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FFMA_IMM: {
|
||||
op_b += GetImmediate(instr);
|
||||
op_b += GetImmediate19(instr);
|
||||
op_c += GetRegister(instr.gpr39);
|
||||
break;
|
||||
}
|
||||
@@ -399,11 +427,18 @@ private:
|
||||
const std::string op_a = GetRegister(instr.gpr8);
|
||||
const std::string op_b = GetRegister(instr.gpr20);
|
||||
const std::string sampler = GetSampler(instr.sampler);
|
||||
const std::string coord = "vec2(" + op_a + ", " + op_b + ")";
|
||||
const std::string texture = "texture(" + sampler + ", " + coord + ")";
|
||||
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
||||
// Add an extra scope and declare the texture coords inside to prevent overwriting
|
||||
// them in case they are used as outputs of the texs instruction.
|
||||
shader.AddLine("{");
|
||||
++shader.scope;
|
||||
shader.AddLine(coord);
|
||||
const std::string texture = "texture(" + sampler + ", coords)";
|
||||
for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
|
||||
SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4);
|
||||
}
|
||||
--shader.scope;
|
||||
shader.AddLine("}");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -433,7 +468,7 @@ private:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {} ({}): {}",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name, instr.hex);
|
||||
// UNREACHABLE();
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,7 +499,7 @@ private:
|
||||
for (const auto& subroutine : subroutines) {
|
||||
shader.AddLine("bool " + subroutine.GetName() + "();");
|
||||
}
|
||||
shader.AddLine("");
|
||||
shader.AddNewLine();
|
||||
|
||||
// Add the main entry point
|
||||
shader.AddLine("bool exec_shader() {");
|
||||
@@ -507,14 +542,14 @@ private:
|
||||
}
|
||||
|
||||
--shader.scope;
|
||||
shader.AddLine("}");
|
||||
shader.AddLine('}');
|
||||
}
|
||||
|
||||
shader.AddLine("default: return false;");
|
||||
shader.AddLine("}");
|
||||
shader.AddLine('}');
|
||||
|
||||
--shader.scope;
|
||||
shader.AddLine("}");
|
||||
shader.AddLine('}');
|
||||
|
||||
shader.AddLine("return false;");
|
||||
}
|
||||
@@ -541,7 +576,7 @@ private:
|
||||
for (const auto& reg : declr_register) {
|
||||
declarations.AddLine("float " + reg + " = 0.0;");
|
||||
}
|
||||
declarations.AddLine("");
|
||||
declarations.AddNewLine();
|
||||
|
||||
for (const auto& index : declr_input_attribute) {
|
||||
// TODO(bunnei): Use proper number of elements for these
|
||||
@@ -550,7 +585,7 @@ private:
|
||||
static_cast<u32>(Attribute::Index::Attribute_0)) +
|
||||
") in vec4 " + GetInputAttribute(index) + ";");
|
||||
}
|
||||
declarations.AddLine("");
|
||||
declarations.AddNewLine();
|
||||
|
||||
for (const auto& index : declr_output_attribute) {
|
||||
// TODO(bunnei): Use proper number of elements for these
|
||||
@@ -559,15 +594,15 @@ private:
|
||||
static_cast<u32>(Attribute::Index::Attribute_0)) +
|
||||
") out vec4 " + GetOutputAttribute(index) + ";");
|
||||
}
|
||||
declarations.AddLine("");
|
||||
declarations.AddNewLine();
|
||||
|
||||
unsigned const_buffer_layout = 0;
|
||||
for (const auto& entry : GetConstBuffersDeclarations()) {
|
||||
declarations.AddLine("layout(std430) buffer " + entry.GetName());
|
||||
declarations.AddLine("{");
|
||||
declarations.AddLine('{');
|
||||
declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];");
|
||||
declarations.AddLine("};");
|
||||
declarations.AddLine("");
|
||||
declarations.AddNewLine();
|
||||
++const_buffer_layout;
|
||||
}
|
||||
}
|
||||
@@ -586,7 +621,7 @@ private:
|
||||
std::set<Attribute::Index> declr_input_attribute;
|
||||
std::set<Attribute::Index> declr_output_attribute;
|
||||
std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;
|
||||
};
|
||||
}; // namespace Decompiler
|
||||
|
||||
std::string GetCommonDeclarations() {
|
||||
return "bool exec_shader();";
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
@@ -55,8 +55,10 @@ void SetShaderSamplerBindings(GLuint shader) {
|
||||
|
||||
void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage) {
|
||||
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
|
||||
viewport_flip[0] = regs.viewport_scale_x < 0.0 ? -1.0 : 1.0;
|
||||
viewport_flip[1] = regs.viewport_scale_y < 0.0 ? -1.0 : 1.0;
|
||||
|
||||
// TODO(bunnei): Support more than one viewport
|
||||
viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0 : 1.0;
|
||||
viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
} // namespace GLShader
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <glad/glad.h>
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -45,18 +45,17 @@ static void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out
|
||||
|
||||
u32 BytesPerPixel(TextureFormat format) {
|
||||
switch (format) {
|
||||
case TextureFormat::DXT1:
|
||||
// In this case a 'pixel' actually refers to a 4x4 tile.
|
||||
return 8;
|
||||
case TextureFormat::DXT23:
|
||||
case TextureFormat::DXT45:
|
||||
// In this case a 'pixel' actually refers to a 4x4 tile.
|
||||
return 16;
|
||||
case TextureFormat::A8R8G8B8:
|
||||
case TextureFormat::BF10GF11RF11:
|
||||
return 4;
|
||||
case TextureFormat::A1B5G5R5:
|
||||
case TextureFormat::B5G6R5:
|
||||
return 2;
|
||||
// In this case a 'pixel' actually refers to a 4x4 tile.
|
||||
case TextureFormat::BC1:
|
||||
return 8;
|
||||
case TextureFormat::BC2:
|
||||
case TextureFormat::BC3:
|
||||
return 16;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Format not implemented");
|
||||
break;
|
||||
@@ -68,29 +67,20 @@ std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width,
|
||||
u8* data = Memory::GetPointer(address);
|
||||
u32 bytes_per_pixel = BytesPerPixel(format);
|
||||
|
||||
static constexpr u32 DefaultBlockHeight = 16;
|
||||
|
||||
std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
|
||||
|
||||
switch (format) {
|
||||
case TextureFormat::BC1:
|
||||
// In the BC1 format, each 4x4 tile is swizzled instead of just individual pixel values.
|
||||
CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data,
|
||||
unswizzled_data.data(), true, DefaultBlockHeight);
|
||||
break;
|
||||
case TextureFormat::BC2:
|
||||
// TODO
|
||||
CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data,
|
||||
unswizzled_data.data(), true, DefaultBlockHeight);
|
||||
break;
|
||||
case TextureFormat::BC3:
|
||||
// TODO
|
||||
case TextureFormat::DXT1:
|
||||
case TextureFormat::DXT23:
|
||||
case TextureFormat::DXT45:
|
||||
// In the DXT formats, each 4x4 tile is swizzled instead of just individual pixel values.
|
||||
CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data,
|
||||
unswizzled_data.data(), true, block_height);
|
||||
break;
|
||||
case TextureFormat::A8R8G8B8:
|
||||
case TextureFormat::B5G6R5:
|
||||
CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data,
|
||||
unswizzled_data.data(), true, DefaultBlockHeight);
|
||||
unswizzled_data.data(), true, block_height);
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Format not implemented");
|
||||
@@ -106,13 +96,11 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
|
||||
|
||||
// TODO(Subv): Implement.
|
||||
switch (format) {
|
||||
case TextureFormat::BC1:
|
||||
case TextureFormat::BC2:
|
||||
case TextureFormat::BC3:
|
||||
case TextureFormat::DXT1:
|
||||
case TextureFormat::DXT23:
|
||||
case TextureFormat::DXT45:
|
||||
case TextureFormat::A8R8G8B8:
|
||||
case TextureFormat::A1B5G5R5:
|
||||
case TextureFormat::B5G6R5:
|
||||
case TextureFormat::BF10GF11RF11:
|
||||
// TODO(Subv): For the time being just forward the same data without any decoding.
|
||||
rgba_data = texture_data;
|
||||
break;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Texture {
|
||||
* Unswizzles a swizzled texture without changing its format.
|
||||
*/
|
||||
std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
|
||||
u32 block_height);
|
||||
u32 block_height = TICEntry::DefaultBlockHeight);
|
||||
|
||||
/**
|
||||
* Decodes an unswizzled texture into a A8R8G8B8 texture.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
@@ -14,13 +15,10 @@ namespace Texture {
|
||||
|
||||
enum class TextureFormat : u32 {
|
||||
A8R8G8B8 = 0x8,
|
||||
A1B5G5R5 = 0x14,
|
||||
B5G6R5 = 0x15,
|
||||
BF10GF11RF11 = 0x21,
|
||||
// Compressed Textures
|
||||
BC1 = 0x24,
|
||||
BC2 = 0x25,
|
||||
BC3 = 0x26,
|
||||
DXT1 = 0x24,
|
||||
DXT23 = 0x25,
|
||||
DXT45 = 0x26,
|
||||
};
|
||||
|
||||
enum class TextureType : u32 {
|
||||
@@ -61,6 +59,8 @@ union TextureHandle {
|
||||
static_assert(sizeof(TextureHandle) == 4, "TextureHandle has wrong size");
|
||||
|
||||
struct TICEntry {
|
||||
static constexpr u32 DefaultBlockHeight = 16;
|
||||
|
||||
union {
|
||||
u32 raw;
|
||||
BitField<0, 7, TextureFormat> format;
|
||||
@@ -75,9 +75,11 @@ struct TICEntry {
|
||||
BitField<21, 3, TICHeaderVersion> header_version;
|
||||
};
|
||||
union {
|
||||
BitField<3, 3, u8> gobs_per_block;
|
||||
BitField<3, 3, u32> block_height;
|
||||
|
||||
// High 16 bits of the pitch value
|
||||
BitField<0, 16, u32> pitch_high;
|
||||
};
|
||||
INSERT_PADDING_BYTES(3);
|
||||
union {
|
||||
BitField<0, 16, u32> width_minus_1;
|
||||
BitField<23, 4, TextureType> texture_type;
|
||||
@@ -89,6 +91,13 @@ struct TICEntry {
|
||||
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low);
|
||||
}
|
||||
|
||||
u32 Pitch() const {
|
||||
ASSERT(header_version == TICHeaderVersion::Pitch ||
|
||||
header_version == TICHeaderVersion::PitchColorKey);
|
||||
// The pitch value is 21 bits, and is 32B aligned.
|
||||
return pitch_high << 5;
|
||||
}
|
||||
|
||||
u32 Width() const {
|
||||
return width_minus_1 + 1;
|
||||
}
|
||||
@@ -97,14 +106,17 @@ struct TICEntry {
|
||||
return height_minus_1 + 1;
|
||||
}
|
||||
|
||||
u32 BlockHeight() const {
|
||||
ASSERT(header_version == TICHeaderVersion::BlockLinear ||
|
||||
header_version == TICHeaderVersion::BlockLinearColorKey);
|
||||
// The block height is stored in log2 format.
|
||||
return 1 << block_height;
|
||||
}
|
||||
|
||||
bool IsTiled() const {
|
||||
return header_version == TICHeaderVersion::BlockLinear ||
|
||||
header_version == TICHeaderVersion::BlockLinearColorKey;
|
||||
}
|
||||
|
||||
u32 BlockHeight() const {
|
||||
return 1 << gobs_per_block;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size");
|
||||
|
||||
|
||||
@@ -378,8 +378,8 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
||||
QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
|
||||
VAddr address = gpu.memory_manager->PhysicalToVirtualAddress(surface_address);
|
||||
|
||||
auto unswizzled_data = Tegra::Texture::UnswizzleTexture(address, surface_format, surface_width,
|
||||
surface_height, 16);
|
||||
auto unswizzled_data =
|
||||
Tegra::Texture::UnswizzleTexture(address, surface_format, surface_width, surface_height);
|
||||
|
||||
auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format,
|
||||
surface_width, surface_height);
|
||||
|
||||
@@ -44,6 +44,15 @@
|
||||
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C" {
|
||||
// tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable
|
||||
// graphics
|
||||
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* "Callouts" are one-time instructional messages shown to the user. In the config settings, there
|
||||
* is a bitfield "callout_flags" options, used to track if a message has already been shown to the
|
||||
|
||||
@@ -37,6 +37,15 @@
|
||||
#include "yuzu_cmd/config.h"
|
||||
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C" {
|
||||
// tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable
|
||||
// graphics
|
||||
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void PrintHelp(const char* argv0) {
|
||||
std::cout << "Usage: " << argv0
|
||||
<< " [options] <filename>\n"
|
||||
|
||||
Reference in New Issue
Block a user