Compare commits

..

1 Commits

Author SHA1 Message Date
FernandoS27
a4e68bbb32 Make Unimplemented Messages Log Error but not halt execution 2018-11-25 15:48:25 -04:00
28 changed files with 535 additions and 951 deletions

View File

@@ -41,6 +41,13 @@ __declspec(noinline, noreturn)
} \
while (0)
#define UNIMPLEMENTED_IF_MSG(_a_, ...) \
do \
if (!(_a_)) { \
LOG_CRITICAL(Debug, "Unimplemented Code:\n" __VA_ARGS__); \
} \
while (0)
#define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!")
#define UNREACHABLE_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
@@ -52,8 +59,7 @@ __declspec(noinline, noreturn)
#define DEBUG_ASSERT_MSG(_a_, _desc_, ...)
#endif
#define UNIMPLEMENTED() ASSERT_MSG(false, "Unimplemented code!")
#define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
#define UNIMPLEMENTED() UNIMPLEMENTED_IF_MSG(false, "Unimplemented code!")
#define UNIMPLEMENTED_MSG(...) UNIMPLEMENTED_IF_MSG(false, __VA_ARGS__)
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
#define UNIMPLEMENTED_IF(cond) UNIMPLEMENTED_IF_MSG(!(cond), "Unimplemented code!")

View File

@@ -671,8 +671,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
break;
}
default:
LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
return ERR_INVALID_ENUM_VALUE;
UNIMPLEMENTED();
}
return RESULT_SUCCESS;

View File

@@ -63,7 +63,7 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService
return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));
}
ResultCode ServiceManager::UnregisterService(const std::string& name) {
ResultCode ServiceManager::UnregisterService(std::string name) {
CASCADE_CODE(ValidateServiceName(name));
const auto iter = registered_services.find(name);

View File

@@ -50,7 +50,7 @@ public:
ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
unsigned int max_sessions);
ResultCode UnregisterService(const std::string& name);
ResultCode UnregisterService(std::string name);
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);

View File

@@ -21,8 +21,6 @@ add_library(video_core STATIC
macro_interpreter.h
memory_manager.cpp
memory_manager.h
morton.cpp
morton.h
rasterizer_cache.cpp
rasterizer_cache.h
rasterizer_interface.h
@@ -64,6 +62,7 @@ add_library(video_core STATIC
textures/decoders.cpp
textures/decoders.h
textures/texture.h
utils.h
video_core.cpp
video_core.h
)

View File

@@ -34,9 +34,6 @@ MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB
void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) {
MICROPROFILE_SCOPE(ProcessCommandLists);
// On entering GPU code, assume all memory may be touched by the ARM core.
maxwell_3d->dirty_flags.OnMemoryWrite();
auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) {
LOG_TRACE(HW_GPU,
"Processing method {:08X} on subchannel {} value "

View File

@@ -2,10 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/core.h"
#include "core/memory.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/textures/decoders.h"
@@ -49,9 +47,6 @@ void Fermi2D::HandleSurfaceCopy() {
u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format);
if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst)) {
// All copies here update the main memory, so mark all rasterizer states as invalid.
Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
rasterizer.FlushRegion(source_cpu, src_bytes_per_pixel * regs.src.width * regs.src.height);
// We have to invalidate the destination region to evict any outdated surfaces from the
// cache. We do this before actually writing the new data because the destination address

View File

@@ -3,10 +3,8 @@
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/core.h"
#include "core/memory.h"
#include "video_core/engines/kepler_memory.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/rasterizer_interface.h"
namespace Tegra::Engines {
@@ -49,7 +47,6 @@ void KeplerMemory::ProcessData(u32 data) {
rasterizer.InvalidateRegion(dest_address, sizeof(u32));
Memory::Write32(dest_address, data);
Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
state.write_offset++;
}

View File

@@ -135,24 +135,10 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
if (regs.reg_array[method] != value) {
regs.reg_array[method] = value;
// Vertex format
if (method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) &&
method < MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) {
dirty_flags.vertex_attrib_format = true;
}
// Vertex buffer
if (method >= MAXWELL3D_REG_INDEX(vertex_array) &&
method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * 32) {
dirty_flags.vertex_array |= 1u << ((method - MAXWELL3D_REG_INDEX(vertex_array)) >> 2);
} else if (method >= MAXWELL3D_REG_INDEX(vertex_array_limit) &&
method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * 32) {
dirty_flags.vertex_array |=
1u << ((method - MAXWELL3D_REG_INDEX(vertex_array_limit)) >> 1);
} else if (method >= MAXWELL3D_REG_INDEX(instanced_arrays) &&
method < MAXWELL3D_REG_INDEX(instanced_arrays) + 32) {
dirty_flags.vertex_array |= 1u << (method - MAXWELL3D_REG_INDEX(instanced_arrays));
}
}
switch (method) {
@@ -284,7 +270,6 @@ void Maxwell3D::ProcessQueryGet() {
query_result.timestamp = CoreTiming::GetTicks();
Memory::WriteBlock(*address, &query_result, sizeof(query_result));
}
dirty_flags.OnMemoryWrite();
break;
}
default:
@@ -361,7 +346,6 @@ void Maxwell3D::ProcessCBData(u32 value) {
memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos);
Memory::Write32(*address, value);
dirty_flags.OnMemoryWrite();
// Increment the current buffer position.
regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4;

View File

@@ -590,18 +590,10 @@ public:
float clear_color[4];
float clear_depth;
INSERT_PADDING_WORDS(0x3);
s32 clear_stencil;
INSERT_PADDING_WORDS(0x7);
u32 polygon_offset_point_enable;
u32 polygon_offset_line_enable;
u32 polygon_offset_fill_enable;
INSERT_PADDING_WORDS(0xD);
INSERT_PADDING_WORDS(0x17);
std::array<ScissorTest, NumViewports> scissor_test;
@@ -736,7 +728,6 @@ public:
u32 frag_color_clamp;
union {
BitField<0, 1, u32> y_negate;
BitField<4, 1, u32> triangle_rast_flip;
} screen_y_control;
@@ -770,11 +761,7 @@ public:
}
} tsc;
INSERT_PADDING_WORDS(0x1);
float polygon_offset_factor;
INSERT_PADDING_WORDS(0x1);
INSERT_PADDING_WORDS(0x3);
struct {
u32 tic_address_high;
@@ -799,9 +786,7 @@ public:
u32 framebuffer_srgb;
float polygon_offset_units;
INSERT_PADDING_WORDS(0x11);
INSERT_PADDING_WORDS(0x12);
union {
BitField<2, 1, u32> coord_origin;
@@ -878,9 +863,7 @@ public:
INSERT_PADDING_WORDS(0x7);
INSERT_PADDING_WORDS(0x1F);
float polygon_offset_clamp;
INSERT_PADDING_WORDS(0x20);
struct {
u32 is_instanced[NumVertexArrays];
@@ -896,13 +879,7 @@ public:
Cull cull;
u32 pixel_center_integer;
INSERT_PADDING_WORDS(0x1);
u32 viewport_transform_enabled;
INSERT_PADDING_WORDS(0x25);
INSERT_PADDING_WORDS(0x28);
struct {
u32 enable;
@@ -1067,11 +1044,6 @@ public:
struct DirtyFlags {
bool vertex_attrib_format = true;
u32 vertex_array = 0xFFFFFFFF;
void OnMemoryWrite() {
vertex_array = 0xFFFFFFFF;
}
};
DirtyFlags dirty_flags;
@@ -1164,9 +1136,6 @@ ASSERT_REG_POSITION(vertex_buffer, 0x35D);
ASSERT_REG_POSITION(clear_color[0], 0x360);
ASSERT_REG_POSITION(clear_depth, 0x364);
ASSERT_REG_POSITION(clear_stencil, 0x368);
ASSERT_REG_POSITION(polygon_offset_point_enable, 0x370);
ASSERT_REG_POSITION(polygon_offset_line_enable, 0x371);
ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372);
ASSERT_REG_POSITION(scissor_test, 0x380);
ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
@@ -1205,7 +1174,6 @@ ASSERT_REG_POSITION(point_size, 0x546);
ASSERT_REG_POSITION(zeta_enable, 0x54E);
ASSERT_REG_POSITION(multisample_control, 0x54F);
ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(polygon_offset_factor, 0x55b);
ASSERT_REG_POSITION(tic, 0x55D);
ASSERT_REG_POSITION(stencil_two_side_enable, 0x565);
ASSERT_REG_POSITION(stencil_back_op_fail, 0x566);
@@ -1213,17 +1181,13 @@ ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567);
ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568);
ASSERT_REG_POSITION(stencil_back_func_func, 0x569);
ASSERT_REG_POSITION(framebuffer_srgb, 0x56E);
ASSERT_REG_POSITION(polygon_offset_units, 0x56F);
ASSERT_REG_POSITION(point_coord_replace, 0x581);
ASSERT_REG_POSITION(code_address, 0x582);
ASSERT_REG_POSITION(draw, 0x585);
ASSERT_REG_POSITION(primitive_restart, 0x591);
ASSERT_REG_POSITION(index_array, 0x5F2);
ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F);
ASSERT_REG_POSITION(instanced_arrays, 0x620);
ASSERT_REG_POSITION(cull, 0x646);
ASSERT_REG_POSITION(pixel_center_integer, 0x649);
ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B);
ASSERT_REG_POSITION(logic_op, 0x671);
ASSERT_REG_POSITION(clear_buffers, 0x674);
ASSERT_REG_POSITION(color_mask, 0x680);

View File

@@ -2,9 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/core.h"
#include "core/memory.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/maxwell_dma.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/textures/decoders.h"
@@ -56,9 +54,6 @@ void MaxwellDMA::HandleCopy() {
return;
}
// All copies here update the main memory, so mark all rasterizer states as invalid.
Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
if (regs.exec.is_dst_linear && regs.exec.is_src_linear) {
// When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D
// buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count,

View File

@@ -82,8 +82,6 @@ union Attribute {
Position = 7,
Attribute_0 = 8,
Attribute_31 = 39,
ClipDistances0123 = 44,
ClipDistances4567 = 45,
PointCoord = 46,
// This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex
// shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval
@@ -368,11 +366,6 @@ enum class HalfPrecision : u64 {
FMZ = 2,
};
enum class R2pMode : u64 {
Pr = 0,
Cc = 1,
};
enum class IpaInterpMode : u64 {
Linear = 0,
Perspective = 1,
@@ -861,12 +854,6 @@ union Instruction {
BitField<39, 3, u64> pred39;
} hsetp2;
union {
BitField<40, 1, R2pMode> mode;
BitField<41, 2, u64> byte;
BitField<20, 7, u64> immediate_mask;
} r2p;
union {
BitField<39, 3, u64> pred39;
BitField<42, 1, u64> neg_pred;
@@ -1269,7 +1256,6 @@ public:
BFE_C,
BFE_R,
BFE_IMM,
BFI_IMM_R,
BRA,
PBK,
LD_A,
@@ -1395,7 +1381,6 @@ public:
PSETP,
PSET,
CSETP,
R2P_IMM,
XMAD_IMM,
XMAD_CR,
XMAD_RC,
@@ -1411,7 +1396,6 @@ public:
ArithmeticHalf,
ArithmeticHalfImmediate,
Bfe,
Bfi,
Shift,
Ffma,
Hfma2,
@@ -1426,7 +1410,6 @@ public:
HalfSetPredicate,
PredicateSetPredicate,
PredicateSetRegister,
RegisterSetPredicate,
Conversion,
Xmad,
Unknown,
@@ -1630,7 +1613,6 @@ private:
INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"),
INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"),
INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"),
INST("0011011-11110---", Id::BFI_IMM_R, Type::Bfi, "BFI_IMM_R"),
INST("0100110001000---", Id::LOP_C, Type::ArithmeticInteger, "LOP_C"),
INST("0101110001000---", Id::LOP_R, Type::ArithmeticInteger, "LOP_R"),
INST("0011100001000---", Id::LOP_IMM, Type::ArithmeticInteger, "LOP_IMM"),
@@ -1665,7 +1647,6 @@ private:
INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"),
INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"),
INST("0011100-11110---", Id::R2P_IMM, Type::RegisterSetPredicate, "R2P_IMM"),
INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"),

View File

@@ -62,16 +62,7 @@ struct Header {
INSERT_PADDING_BYTES(1); // ImapSystemValuesB
INSERT_PADDING_BYTES(16); // ImapGenericVector[32]
INSERT_PADDING_BYTES(2); // ImapColor
union {
BitField<0, 8, u16> clip_distances;
BitField<8, 1, u16> point_sprite_s;
BitField<9, 1, u16> point_sprite_t;
BitField<10, 1, u16> fog_coordinate;
BitField<12, 1, u16> tessellation_eval_point_u;
BitField<13, 1, u16> tessellation_eval_point_v;
BitField<14, 1, u16> instance_id;
BitField<15, 1, u16> vertex_id;
};
INSERT_PADDING_BYTES(2); // ImapSystemValuesC
INSERT_PADDING_BYTES(5); // ImapFixedFncTexture[10]
INSERT_PADDING_BYTES(1); // ImapReserved
INSERT_PADDING_BYTES(3); // OmapSystemValuesA

View File

@@ -1,354 +0,0 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include <cstring>
#include "common/assert.h"
#include "common/common_types.h"
#include "core/memory.h"
#include "video_core/morton.h"
#include "video_core/surface.h"
#include "video_core/textures/decoders.h"
namespace VideoCore {
using Surface::GetBytesPerPixel;
using Surface::PixelFormat;
using MortonCopyFn = void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr);
using ConversionArray = std::array<MortonCopyFn, Surface::MaxPixelFormat>;
template <bool morton_to_linear, PixelFormat format>
static void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth,
u8* buffer, std::size_t buffer_size, VAddr addr) {
constexpr u32 bytes_per_pixel = GetBytesPerPixel(format);
// With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
// pixel values.
const u32 tile_size_x{GetDefaultBlockWidth(format)};
const u32 tile_size_y{GetDefaultBlockHeight(format)};
if constexpr (morton_to_linear) {
Tegra::Texture::UnswizzleTexture(buffer, addr, tile_size_x, tile_size_y, bytes_per_pixel,
stride, height, depth, block_height, block_depth);
} else {
Tegra::Texture::CopySwizzledData((stride + tile_size_x - 1) / tile_size_x,
(height + tile_size_y - 1) / tile_size_y, depth,
bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr),
buffer, false, block_height, block_depth);
}
}
static constexpr ConversionArray morton_to_linear_fns = {
// clang-format off
MortonCopy<true, PixelFormat::ABGR8U>,
MortonCopy<true, PixelFormat::ABGR8S>,
MortonCopy<true, PixelFormat::ABGR8UI>,
MortonCopy<true, PixelFormat::B5G6R5U>,
MortonCopy<true, PixelFormat::A2B10G10R10U>,
MortonCopy<true, PixelFormat::A1B5G5R5U>,
MortonCopy<true, PixelFormat::R8U>,
MortonCopy<true, PixelFormat::R8UI>,
MortonCopy<true, PixelFormat::RGBA16F>,
MortonCopy<true, PixelFormat::RGBA16U>,
MortonCopy<true, PixelFormat::RGBA16UI>,
MortonCopy<true, PixelFormat::R11FG11FB10F>,
MortonCopy<true, PixelFormat::RGBA32UI>,
MortonCopy<true, PixelFormat::DXT1>,
MortonCopy<true, PixelFormat::DXT23>,
MortonCopy<true, PixelFormat::DXT45>,
MortonCopy<true, PixelFormat::DXN1>,
MortonCopy<true, PixelFormat::DXN2UNORM>,
MortonCopy<true, PixelFormat::DXN2SNORM>,
MortonCopy<true, PixelFormat::BC7U>,
MortonCopy<true, PixelFormat::BC6H_UF16>,
MortonCopy<true, PixelFormat::BC6H_SF16>,
MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
MortonCopy<true, PixelFormat::G8R8U>,
MortonCopy<true, PixelFormat::G8R8S>,
MortonCopy<true, PixelFormat::BGRA8>,
MortonCopy<true, PixelFormat::RGBA32F>,
MortonCopy<true, PixelFormat::RG32F>,
MortonCopy<true, PixelFormat::R32F>,
MortonCopy<true, PixelFormat::R16F>,
MortonCopy<true, PixelFormat::R16U>,
MortonCopy<true, PixelFormat::R16S>,
MortonCopy<true, PixelFormat::R16UI>,
MortonCopy<true, PixelFormat::R16I>,
MortonCopy<true, PixelFormat::RG16>,
MortonCopy<true, PixelFormat::RG16F>,
MortonCopy<true, PixelFormat::RG16UI>,
MortonCopy<true, PixelFormat::RG16I>,
MortonCopy<true, PixelFormat::RG16S>,
MortonCopy<true, PixelFormat::RGB32F>,
MortonCopy<true, PixelFormat::RGBA8_SRGB>,
MortonCopy<true, PixelFormat::RG8U>,
MortonCopy<true, PixelFormat::RG8S>,
MortonCopy<true, PixelFormat::RG32UI>,
MortonCopy<true, PixelFormat::R32UI>,
MortonCopy<true, PixelFormat::ASTC_2D_8X8>,
MortonCopy<true, PixelFormat::ASTC_2D_8X5>,
MortonCopy<true, PixelFormat::ASTC_2D_5X4>,
MortonCopy<true, PixelFormat::BGRA8_SRGB>,
MortonCopy<true, PixelFormat::DXT1_SRGB>,
MortonCopy<true, PixelFormat::DXT23_SRGB>,
MortonCopy<true, PixelFormat::DXT45_SRGB>,
MortonCopy<true, PixelFormat::BC7U_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_5X5>,
MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_10X8>,
MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>,
MortonCopy<true, PixelFormat::Z32F>,
MortonCopy<true, PixelFormat::Z16>,
MortonCopy<true, PixelFormat::Z24S8>,
MortonCopy<true, PixelFormat::S8Z24>,
MortonCopy<true, PixelFormat::Z32FS8>,
// clang-format on
};
static constexpr ConversionArray linear_to_morton_fns = {
// clang-format off
MortonCopy<false, PixelFormat::ABGR8U>,
MortonCopy<false, PixelFormat::ABGR8S>,
MortonCopy<false, PixelFormat::ABGR8UI>,
MortonCopy<false, PixelFormat::B5G6R5U>,
MortonCopy<false, PixelFormat::A2B10G10R10U>,
MortonCopy<false, PixelFormat::A1B5G5R5U>,
MortonCopy<false, PixelFormat::R8U>,
MortonCopy<false, PixelFormat::R8UI>,
MortonCopy<false, PixelFormat::RGBA16F>,
MortonCopy<false, PixelFormat::RGBA16U>,
MortonCopy<false, PixelFormat::RGBA16UI>,
MortonCopy<false, PixelFormat::R11FG11FB10F>,
MortonCopy<false, PixelFormat::RGBA32UI>,
MortonCopy<false, PixelFormat::DXT1>,
MortonCopy<false, PixelFormat::DXT23>,
MortonCopy<false, PixelFormat::DXT45>,
MortonCopy<false, PixelFormat::DXN1>,
MortonCopy<false, PixelFormat::DXN2UNORM>,
MortonCopy<false, PixelFormat::DXN2SNORM>,
MortonCopy<false, PixelFormat::BC7U>,
MortonCopy<false, PixelFormat::BC6H_UF16>,
MortonCopy<false, PixelFormat::BC6H_SF16>,
// TODO(Subv): Swizzling ASTC formats are not supported
nullptr,
MortonCopy<false, PixelFormat::G8R8U>,
MortonCopy<false, PixelFormat::G8R8S>,
MortonCopy<false, PixelFormat::BGRA8>,
MortonCopy<false, PixelFormat::RGBA32F>,
MortonCopy<false, PixelFormat::RG32F>,
MortonCopy<false, PixelFormat::R32F>,
MortonCopy<false, PixelFormat::R16F>,
MortonCopy<false, PixelFormat::R16U>,
MortonCopy<false, PixelFormat::R16S>,
MortonCopy<false, PixelFormat::R16UI>,
MortonCopy<false, PixelFormat::R16I>,
MortonCopy<false, PixelFormat::RG16>,
MortonCopy<false, PixelFormat::RG16F>,
MortonCopy<false, PixelFormat::RG16UI>,
MortonCopy<false, PixelFormat::RG16I>,
MortonCopy<false, PixelFormat::RG16S>,
MortonCopy<false, PixelFormat::RGB32F>,
MortonCopy<false, PixelFormat::RGBA8_SRGB>,
MortonCopy<false, PixelFormat::RG8U>,
MortonCopy<false, PixelFormat::RG8S>,
MortonCopy<false, PixelFormat::RG32UI>,
MortonCopy<false, PixelFormat::R32UI>,
nullptr,
nullptr,
nullptr,
MortonCopy<false, PixelFormat::BGRA8_SRGB>,
MortonCopy<false, PixelFormat::DXT1_SRGB>,
MortonCopy<false, PixelFormat::DXT23_SRGB>,
MortonCopy<false, PixelFormat::DXT45_SRGB>,
MortonCopy<false, PixelFormat::BC7U_SRGB>,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
MortonCopy<false, PixelFormat::Z32F>,
MortonCopy<false, PixelFormat::Z16>,
MortonCopy<false, PixelFormat::Z24S8>,
MortonCopy<false, PixelFormat::S8Z24>,
MortonCopy<false, PixelFormat::Z32FS8>,
// clang-format on
};
static MortonCopyFn GetSwizzleFunction(MortonSwizzleMode mode, Surface::PixelFormat format) {
switch (mode) {
case MortonSwizzleMode::MortonToLinear:
return morton_to_linear_fns[static_cast<std::size_t>(format)];
case MortonSwizzleMode::LinearToMorton:
return linear_to_morton_fns[static_cast<std::size_t>(format)];
}
UNREACHABLE();
}
/// 8x8 Z-Order coordinate from 2D coordinates
static u32 MortonInterleave(u32 x, u32 y) {
static const u32 xlut[] = {0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15};
static const u32 ylut[] = {0x00, 0x02, 0x08, 0x0a, 0x20, 0x22, 0x28, 0x2a};
return xlut[x % 8] + ylut[y % 8];
}
/// Calculates the offset of the position of the pixel in Morton order
static u32 GetMortonOffset(u32 x, u32 y, u32 bytes_per_pixel) {
// Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each
// of which is composed of four 2x2 subtiles each of which is composed of four texels.
// Each structure is embedded into the next-bigger one in a diagonal pattern, e.g.
// texels are laid out in a 2x2 subtile like this:
// 2 3
// 0 1
//
// The full 8x8 tile has the texels arranged like this:
//
// 42 43 46 47 58 59 62 63
// 40 41 44 45 56 57 60 61
// 34 35 38 39 50 51 54 55
// 32 33 36 37 48 49 52 53
// 10 11 14 15 26 27 30 31
// 08 09 12 13 24 25 28 29
// 02 03 06 07 18 19 22 23
// 00 01 04 05 16 17 20 21
//
// This pattern is what's called Z-order curve, or Morton order.
const unsigned int block_height = 8;
const unsigned int coarse_x = x & ~7;
u32 i = MortonInterleave(x, y);
const unsigned int offset = coarse_x * block_height;
return (i + offset) * bytes_per_pixel;
}
static u32 MortonInterleave128(u32 x, u32 y) {
// 128x128 Z-Order coordinate from 2D coordinates
static constexpr u32 xlut[] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042,
0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809,
0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000,
0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043,
0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a,
0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001,
0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048,
0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b,
0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002,
0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049,
0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840,
0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003,
0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a,
0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841,
0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008,
0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b,
0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842,
0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009,
0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800,
0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843,
0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a,
0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801,
0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848,
0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b,
0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802,
0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849,
0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040,
0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803,
0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a,
0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041,
0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808,
0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b,
0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042,
0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809,
0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b,
};
static constexpr u32 ylut[] = {
0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090,
0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124,
0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200,
0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294,
0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330,
0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404,
0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0,
0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534,
0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610,
0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4,
0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780,
0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014,
0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0,
0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184,
0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220,
0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4,
0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390,
0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424,
0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500,
0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594,
0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630,
0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704,
0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0,
0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034,
0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110,
0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4,
0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280,
0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314,
0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0,
0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484,
0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520,
0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4,
0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690,
0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724,
0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4,
};
return xlut[x % 128] + ylut[y % 128];
}
static u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) {
// Calculates the offset of the position of the pixel in Morton order
// Framebuffer images are split into 128x128 tiles.
constexpr u32 block_height = 128;
const u32 coarse_x = x & ~127;
const u32 i = MortonInterleave128(x, y);
const u32 offset = coarse_x * block_height;
return (i + offset) * bytes_per_pixel;
}
void MortonSwizzle(MortonSwizzleMode mode, Surface::PixelFormat format, u32 stride,
u32 block_height, u32 height, u32 block_depth, u32 depth, u8* buffer,
std::size_t buffer_size, VAddr addr) {
GetSwizzleFunction(mode, format)(stride, block_height, height, block_depth, depth, buffer,
buffer_size, addr);
}
void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, u32 linear_bytes_per_pixel,
u8* morton_data, u8* linear_data, bool morton_to_linear) {
u8* data_ptrs[2];
for (u32 y = 0; y < height; ++y) {
for (u32 x = 0; x < width; ++x) {
const u32 coarse_y = y & ~127;
const u32 morton_offset =
GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
const u32 linear_pixel_index = (x + y * width) * linear_bytes_per_pixel;
data_ptrs[morton_to_linear ? 1 : 0] = morton_data + morton_offset;
data_ptrs[morton_to_linear ? 0 : 1] = &linear_data[linear_pixel_index];
std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
}
}
}
} // namespace VideoCore

View File

@@ -1,21 +0,0 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#include "video_core/surface.h"
namespace VideoCore {
enum class MortonSwizzleMode { MortonToLinear, LinearToMorton };
void MortonSwizzle(MortonSwizzleMode mode, VideoCore::Surface::PixelFormat format, u32 stride,
u32 block_height, u32 height, u32 block_depth, u32 depth, u8* buffer,
std::size_t buffer_size, VAddr addr);
void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, u32 linear_bytes_per_pixel,
u8* morton_data, u8* linear_data, bool morton_to_linear);
} // namespace VideoCore

View File

@@ -76,7 +76,7 @@ std::tuple<u8*, GLintptr> OGLBufferCache::ReserveMemory(std::size_t size, std::s
return std::make_tuple(uploaded_ptr, uploaded_offset);
}
bool OGLBufferCache::Map(std::size_t max_size) {
void OGLBufferCache::Map(std::size_t max_size) {
bool invalidate;
std::tie(buffer_ptr, buffer_offset_base, invalidate) =
stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4);
@@ -85,7 +85,6 @@ bool OGLBufferCache::Map(std::size_t max_size) {
if (invalidate) {
InvalidateAll();
}
return invalidate;
}
void OGLBufferCache::Unmap() {

View File

@@ -50,7 +50,7 @@ public:
/// Reserves memory to be used by host's CPU. Returns mapped address and offset.
std::tuple<u8*, GLintptr> ReserveMemory(std::size_t size, std::size_t alignment = 4);
bool Map(std::size_t max_size);
void Map(std::size_t max_size);
void Unmap();
GLuint GetHandle() const;

View File

@@ -176,25 +176,15 @@ void RasterizerOpenGL::SetupVertexFormat() {
}
state.draw.vertex_array = VAO.handle;
state.ApplyVertexBufferState();
// Rebinding the VAO invalidates the vertex buffer bindings.
gpu.dirty_flags.vertex_array = 0xFFFFFFFF;
}
void RasterizerOpenGL::SetupVertexBuffer() {
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
const auto& regs = gpu.regs;
if (!gpu.dirty_flags.vertex_array)
return;
MICROPROFILE_SCOPE(OpenGL_VB);
const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
const auto& regs = gpu.regs;
// Upload all guest vertex arrays sequentially to our buffer
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
if (~gpu.dirty_flags.vertex_array & (1u << index))
continue;
const auto& vertex_array = regs.vertex_array[index];
if (!vertex_array.IsEnabled())
continue;
@@ -221,8 +211,6 @@ void RasterizerOpenGL::SetupVertexBuffer() {
// Implicit set by glBindVertexBuffer. Stupid glstate handling...
state.draw.vertex_buffer = buffer_cache.GetHandle();
gpu.dirty_flags.vertex_array = 0;
}
DrawParameters RasterizerOpenGL::SetupDraw() {
@@ -612,7 +600,7 @@ void RasterizerOpenGL::DrawArrays() {
return;
MICROPROFILE_SCOPE(OpenGL_Drawing);
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
const auto& regs = gpu.regs;
ScopeAcquireGLContext acquire_context{emu_window};
@@ -632,7 +620,7 @@ void RasterizerOpenGL::DrawArrays() {
SyncTransformFeedback();
SyncPointState();
CheckAlphaTests();
SyncPolygonOffset();
// TODO(bunnei): Sync framebuffer_scale uniform here
// TODO(bunnei): Sync scissorbox uniform(s) here
@@ -665,11 +653,7 @@ void RasterizerOpenGL::DrawArrays() {
// Add space for at least 18 constant buffers
buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment);
bool invalidate = buffer_cache.Map(buffer_size);
if (invalidate) {
// As all cached buffers are invalidated, we need to recheck their state.
gpu.dirty_flags.vertex_attrib_format = 0xFFFFFFFF;
}
buffer_cache.Map(buffer_size);
SetupVertexFormat();
SetupVertexBuffer();
@@ -985,25 +969,13 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
const bool geometry_shaders_enabled =
regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry));
const std::size_t viewport_count =
geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1;
for (std::size_t i = 0; i < viewport_count; i++) {
for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
auto& viewport = current_state.viewports[i];
const auto& src = regs.viewports[i];
if (regs.viewport_transform_enabled) {
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
viewport.x = viewport_rect.left;
viewport.y = viewport_rect.bottom;
viewport.width = viewport_rect.GetWidth();
viewport.height = viewport_rect.GetHeight();
} else {
viewport.x = src.x;
viewport.y = src.y;
viewport.width = src.width;
viewport.height = src.height;
}
viewport.x = viewport_rect.left;
viewport.y = viewport_rect.bottom;
viewport.width = viewport_rect.GetWidth();
viewport.height = viewport_rect.GetHeight();
viewport.depth_range_far = regs.viewports[i].depth_range_far;
viewport.depth_range_near = regs.viewports[i].depth_range_near;
}
@@ -1177,11 +1149,7 @@ void RasterizerOpenGL::SyncLogicOpState() {
void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
const bool geometry_shaders_enabled =
regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry));
const std::size_t viewport_count =
geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1;
for (std::size_t i = 0; i < viewport_count; i++) {
for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
const auto& src = regs.scissor_test[i];
auto& dst = current_state.viewports[i].scissor;
dst.enabled = (src.enable != 0);
@@ -1211,16 +1179,6 @@ void RasterizerOpenGL::SyncPointState() {
state.point.size = regs.point_size;
}
void RasterizerOpenGL::SyncPolygonOffset() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0;
state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0;
state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0;
state.polygon_offset.units = regs.polygon_offset_units;
state.polygon_offset.factor = regs.polygon_offset_factor;
state.polygon_offset.clamp = regs.polygon_offset_clamp;
}
void RasterizerOpenGL::CheckAlphaTests() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;

View File

@@ -183,9 +183,6 @@ private:
/// Syncs Color Mask
void SyncColorMask();
/// Syncs the polygon offsets
void SyncPolygonOffset();
/// Check asserts for alpha testing.
void CheckAlphaTests();

View File

@@ -15,7 +15,6 @@
#include "core/memory.h"
#include "core/settings.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/morton.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
#include "video_core/renderer_opengl/gl_state.h"
@@ -23,11 +22,10 @@
#include "video_core/surface.h"
#include "video_core/textures/astc.h"
#include "video_core/textures/decoders.h"
#include "video_core/utils.h"
namespace OpenGL {
using VideoCore::MortonSwizzle;
using VideoCore::MortonSwizzleMode;
using VideoCore::Surface::ComponentTypeFromDepthFormat;
using VideoCore::Surface::ComponentTypeFromRenderTarget;
using VideoCore::Surface::ComponentTypeFromTexture;
@@ -372,7 +370,174 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const {
return {0, actual_height, MipWidth(mip_level), 0};
}
void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params,
template <bool morton_to_gl, PixelFormat format>
void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer,
std::size_t gl_buffer_size, VAddr addr) {
constexpr u32 bytes_per_pixel = GetBytesPerPixel(format);
// With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
// pixel values.
const u32 tile_size_x{GetDefaultBlockWidth(format)};
const u32 tile_size_y{GetDefaultBlockHeight(format)};
if (morton_to_gl) {
Tegra::Texture::UnswizzleTexture(gl_buffer, addr, tile_size_x, tile_size_y, bytes_per_pixel,
stride, height, depth, block_height, block_depth);
} else {
Tegra::Texture::CopySwizzledData((stride + tile_size_x - 1) / tile_size_x,
(height + tile_size_y - 1) / tile_size_y, depth,
bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr),
gl_buffer, false, block_height, block_depth);
}
}
using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
VideoCore::Surface::MaxPixelFormat>;
static constexpr GLConversionArray morton_to_gl_fns = {
// clang-format off
MortonCopy<true, PixelFormat::ABGR8U>,
MortonCopy<true, PixelFormat::ABGR8S>,
MortonCopy<true, PixelFormat::ABGR8UI>,
MortonCopy<true, PixelFormat::B5G6R5U>,
MortonCopy<true, PixelFormat::A2B10G10R10U>,
MortonCopy<true, PixelFormat::A1B5G5R5U>,
MortonCopy<true, PixelFormat::R8U>,
MortonCopy<true, PixelFormat::R8UI>,
MortonCopy<true, PixelFormat::RGBA16F>,
MortonCopy<true, PixelFormat::RGBA16U>,
MortonCopy<true, PixelFormat::RGBA16UI>,
MortonCopy<true, PixelFormat::R11FG11FB10F>,
MortonCopy<true, PixelFormat::RGBA32UI>,
MortonCopy<true, PixelFormat::DXT1>,
MortonCopy<true, PixelFormat::DXT23>,
MortonCopy<true, PixelFormat::DXT45>,
MortonCopy<true, PixelFormat::DXN1>,
MortonCopy<true, PixelFormat::DXN2UNORM>,
MortonCopy<true, PixelFormat::DXN2SNORM>,
MortonCopy<true, PixelFormat::BC7U>,
MortonCopy<true, PixelFormat::BC6H_UF16>,
MortonCopy<true, PixelFormat::BC6H_SF16>,
MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
MortonCopy<true, PixelFormat::G8R8U>,
MortonCopy<true, PixelFormat::G8R8S>,
MortonCopy<true, PixelFormat::BGRA8>,
MortonCopy<true, PixelFormat::RGBA32F>,
MortonCopy<true, PixelFormat::RG32F>,
MortonCopy<true, PixelFormat::R32F>,
MortonCopy<true, PixelFormat::R16F>,
MortonCopy<true, PixelFormat::R16U>,
MortonCopy<true, PixelFormat::R16S>,
MortonCopy<true, PixelFormat::R16UI>,
MortonCopy<true, PixelFormat::R16I>,
MortonCopy<true, PixelFormat::RG16>,
MortonCopy<true, PixelFormat::RG16F>,
MortonCopy<true, PixelFormat::RG16UI>,
MortonCopy<true, PixelFormat::RG16I>,
MortonCopy<true, PixelFormat::RG16S>,
MortonCopy<true, PixelFormat::RGB32F>,
MortonCopy<true, PixelFormat::RGBA8_SRGB>,
MortonCopy<true, PixelFormat::RG8U>,
MortonCopy<true, PixelFormat::RG8S>,
MortonCopy<true, PixelFormat::RG32UI>,
MortonCopy<true, PixelFormat::R32UI>,
MortonCopy<true, PixelFormat::ASTC_2D_8X8>,
MortonCopy<true, PixelFormat::ASTC_2D_8X5>,
MortonCopy<true, PixelFormat::ASTC_2D_5X4>,
MortonCopy<true, PixelFormat::BGRA8_SRGB>,
MortonCopy<true, PixelFormat::DXT1_SRGB>,
MortonCopy<true, PixelFormat::DXT23_SRGB>,
MortonCopy<true, PixelFormat::DXT45_SRGB>,
MortonCopy<true, PixelFormat::BC7U_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_5X5>,
MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>,
MortonCopy<true, PixelFormat::ASTC_2D_10X8>,
MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>,
MortonCopy<true, PixelFormat::Z32F>,
MortonCopy<true, PixelFormat::Z16>,
MortonCopy<true, PixelFormat::Z24S8>,
MortonCopy<true, PixelFormat::S8Z24>,
MortonCopy<true, PixelFormat::Z32FS8>,
// clang-format on
};
static constexpr GLConversionArray gl_to_morton_fns = {
// clang-format off
MortonCopy<false, PixelFormat::ABGR8U>,
MortonCopy<false, PixelFormat::ABGR8S>,
MortonCopy<false, PixelFormat::ABGR8UI>,
MortonCopy<false, PixelFormat::B5G6R5U>,
MortonCopy<false, PixelFormat::A2B10G10R10U>,
MortonCopy<false, PixelFormat::A1B5G5R5U>,
MortonCopy<false, PixelFormat::R8U>,
MortonCopy<false, PixelFormat::R8UI>,
MortonCopy<false, PixelFormat::RGBA16F>,
MortonCopy<false, PixelFormat::RGBA16U>,
MortonCopy<false, PixelFormat::RGBA16UI>,
MortonCopy<false, PixelFormat::R11FG11FB10F>,
MortonCopy<false, PixelFormat::RGBA32UI>,
MortonCopy<false, PixelFormat::DXT1>,
MortonCopy<false, PixelFormat::DXT23>,
MortonCopy<false, PixelFormat::DXT45>,
MortonCopy<false, PixelFormat::DXN1>,
MortonCopy<false, PixelFormat::DXN2UNORM>,
MortonCopy<false, PixelFormat::DXN2SNORM>,
MortonCopy<false, PixelFormat::BC7U>,
MortonCopy<false, PixelFormat::BC6H_UF16>,
MortonCopy<false, PixelFormat::BC6H_SF16>,
// TODO(Subv): Swizzling ASTC formats are not supported
nullptr,
MortonCopy<false, PixelFormat::G8R8U>,
MortonCopy<false, PixelFormat::G8R8S>,
MortonCopy<false, PixelFormat::BGRA8>,
MortonCopy<false, PixelFormat::RGBA32F>,
MortonCopy<false, PixelFormat::RG32F>,
MortonCopy<false, PixelFormat::R32F>,
MortonCopy<false, PixelFormat::R16F>,
MortonCopy<false, PixelFormat::R16U>,
MortonCopy<false, PixelFormat::R16S>,
MortonCopy<false, PixelFormat::R16UI>,
MortonCopy<false, PixelFormat::R16I>,
MortonCopy<false, PixelFormat::RG16>,
MortonCopy<false, PixelFormat::RG16F>,
MortonCopy<false, PixelFormat::RG16UI>,
MortonCopy<false, PixelFormat::RG16I>,
MortonCopy<false, PixelFormat::RG16S>,
MortonCopy<false, PixelFormat::RGB32F>,
MortonCopy<false, PixelFormat::RGBA8_SRGB>,
MortonCopy<false, PixelFormat::RG8U>,
MortonCopy<false, PixelFormat::RG8S>,
MortonCopy<false, PixelFormat::RG32UI>,
MortonCopy<false, PixelFormat::R32UI>,
nullptr,
nullptr,
nullptr,
MortonCopy<false, PixelFormat::BGRA8_SRGB>,
MortonCopy<false, PixelFormat::DXT1_SRGB>,
MortonCopy<false, PixelFormat::DXT23_SRGB>,
MortonCopy<false, PixelFormat::DXT45_SRGB>,
MortonCopy<false, PixelFormat::BC7U_SRGB>,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
MortonCopy<false, PixelFormat::Z32F>,
MortonCopy<false, PixelFormat::Z16>,
MortonCopy<false, PixelFormat::Z24S8>,
MortonCopy<false, PixelFormat::S8Z24>,
MortonCopy<false, PixelFormat::Z32FS8>,
// clang-format on
};
void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
std::vector<u8>& gl_buffer, u32 mip_level) {
u32 depth = params.MipDepth(mip_level);
if (params.target == SurfaceTarget::Texture2D) {
@@ -385,19 +550,19 @@ void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params,
const u64 layer_size = params.LayerMemorySize();
const u64 gl_size = params.LayerSizeGL(mip_level);
for (u32 i = 0; i < params.depth; i++) {
MortonSwizzle(mode, params.pixel_format, params.MipWidth(mip_level),
params.MipBlockHeight(mip_level), params.MipHeight(mip_level),
params.MipBlockDepth(mip_level), 1, gl_buffer.data() + offset_gl, gl_size,
params.addr + offset);
functions[static_cast<std::size_t>(params.pixel_format)](
params.MipWidth(mip_level), params.MipBlockHeight(mip_level),
params.MipHeight(mip_level), params.MipBlockDepth(mip_level), 1,
gl_buffer.data() + offset_gl, gl_size, params.addr + offset);
offset += layer_size;
offset_gl += gl_size;
}
} else {
const u64 offset = params.GetMipmapLevelOffset(mip_level);
MortonSwizzle(mode, params.pixel_format, params.MipWidth(mip_level),
params.MipBlockHeight(mip_level), params.MipHeight(mip_level),
params.MipBlockDepth(mip_level), depth, gl_buffer.data(), gl_buffer.size(),
params.addr + offset);
functions[static_cast<std::size_t>(params.pixel_format)](
params.MipWidth(mip_level), params.MipBlockHeight(mip_level),
params.MipHeight(mip_level), params.MipBlockDepth(mip_level), depth, gl_buffer.data(),
gl_buffer.size(), params.addr + offset);
}
}
@@ -831,7 +996,7 @@ void CachedSurface::LoadGLBuffer() {
ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
params.block_width, static_cast<u32>(params.target));
for (u32 i = 0; i < params.max_mip_level; i++)
SwizzleFunc(MortonSwizzleMode::MortonToLinear, params, gl_buffer[i], i);
SwizzleFunc(morton_to_gl_fns, params, gl_buffer[i], i);
} else {
const auto texture_src_data{Memory::GetPointer(params.addr)};
const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
@@ -870,7 +1035,7 @@ void CachedSurface::FlushGLBuffer() {
ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
params.block_width, static_cast<u32>(params.target));
SwizzleFunc(MortonSwizzleMode::LinearToMorton, params, gl_buffer[0], 0);
SwizzleFunc(gl_to_morton_fns, params, gl_buffer[0], 0);
} else {
std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes());
}

View File

@@ -500,42 +500,27 @@ public:
const Register& buf_reg) {
const std::string dest = GetOutputAttribute(attribute);
const std::string src = GetRegisterAsFloat(val_reg);
if (dest.empty())
return;
// Can happen with unknown/unimplemented output attributes, in which case we ignore the
// instruction for now.
if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
// TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry
// shader. These instructions use a dirty register as buffer index, to avoid some
// drivers from complaining about out of boundary writes, guard them.
const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " +
std::to_string(MAX_GEOMETRY_BUFFERS) + ')'};
shader.AddLine("amem[" + buf_index + "][" +
std::to_string(static_cast<u32>(attribute)) + ']' + GetSwizzle(elem) +
" = " + src + ';');
return;
}
switch (attribute) {
case Attribute::Index::ClipDistances0123:
case Attribute::Index::ClipDistances4567: {
const u64 index = attribute == Attribute::Index::ClipDistances4567 ? 4 : 0 + elem;
UNIMPLEMENTED_IF_MSG(
((header.vtg.clip_distances >> index) & 1) == 0,
"Shader is setting gl_ClipDistance{} without enabling it in the header", index);
fixed_pipeline_output_attributes_used.insert(attribute);
shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';');
break;
}
case Attribute::Index::PointSize:
fixed_pipeline_output_attributes_used.insert(attribute);
shader.AddLine(dest + " = " + src + ';');
break;
default:
shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';');
break;
if (!dest.empty()) {
// Can happen with unknown/unimplemented output attributes, in which case we ignore the
// instruction for now.
if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
// TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry
// shader. These instructions use a dirty register as buffer index, to avoid some
// drivers from complaining about out of boundary writes, guard them.
const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " +
std::to_string(MAX_GEOMETRY_BUFFERS) + ')'};
shader.AddLine("amem[" + buf_index + "][" +
std::to_string(static_cast<u32>(attribute)) + ']' +
GetSwizzle(elem) + " = " + src + ';');
} else {
if (attribute == Attribute::Index::PointSize) {
fixed_pipeline_output_attributes_used.insert(attribute);
shader.AddLine(dest + " = " + src + ';');
} else {
shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';');
}
}
}
}
@@ -755,19 +740,12 @@ private:
void GenerateVertex() {
if (stage != Maxwell3D::Regs::ShaderStage::Vertex)
return;
bool clip_distances_declared = false;
declarations.AddLine("out gl_PerVertex {");
++declarations.scope;
declarations.AddLine("vec4 gl_Position;");
for (auto& o : fixed_pipeline_output_attributes_used) {
if (o == Attribute::Index::PointSize)
declarations.AddLine("float gl_PointSize;");
if (!clip_distances_declared && (o == Attribute::Index::ClipDistances0123 ||
o == Attribute::Index::ClipDistances4567)) {
declarations.AddLine("float gl_ClipDistance[];");
clip_distances_declared = true;
}
}
--declarations.scope;
declarations.AddLine("};");
@@ -867,8 +845,7 @@ private:
// vertex shader, and what's the value of the fourth element when inside a Tess Eval
// shader.
ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex);
// Config pack's first value is instance_id.
return "vec4(0, 0, uintBitsToFloat(config_pack[0]), uintBitsToFloat(gl_VertexID))";
return "vec4(0, 0, uintBitsToFloat(instance_id.x), uintBitsToFloat(gl_VertexID))";
case Attribute::Index::FrontFacing:
// TODO(Subv): Find out what the values are for the other elements.
ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment);
@@ -939,10 +916,6 @@ private:
return "gl_PointSize";
case Attribute::Index::Position:
return "position";
case Attribute::Index::ClipDistances0123:
case Attribute::Index::ClipDistances4567: {
return "gl_ClipDistance";
}
default:
const u32 index{static_cast<u32>(attribute) -
static_cast<u32>(Attribute::Index::Attribute_0)};
@@ -1293,15 +1266,7 @@ private:
regs.SetRegisterToInteger(dest, true, 0, result, 1, 1);
}
void WriteTexsInstruction(const Instruction& instr, const std::string& coord,
const std::string& texture) {
// 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);
shader.AddLine("vec4 texture_tmp = " + texture + ';');
void WriteTexsInstruction(const Instruction& instr, const std::string& texture) {
// TEXS has two destination registers and a swizzle. The first two elements in the swizzle
// go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1
@@ -1313,19 +1278,17 @@ private:
if (written_components < 2) {
// Write the first two swizzle components to gpr0 and gpr0+1
regs.SetRegisterToFloat(instr.gpr0, component, "texture_tmp", 1, 4, false,
regs.SetRegisterToFloat(instr.gpr0, component, texture, 1, 4, false,
written_components % 2);
} else {
ASSERT(instr.texs.HasTwoDestinations());
// Write the rest of the swizzle components to gpr28 and gpr28+1
regs.SetRegisterToFloat(instr.gpr28, component, "texture_tmp", 1, 4, false,
regs.SetRegisterToFloat(instr.gpr28, component, texture, 1, 4, false,
written_components % 2);
}
++written_components;
}
--shader.scope;
shader.AddLine('}');
}
static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) {
@@ -1722,26 +1685,6 @@ private:
break;
}
case OpCode::Type::Bfi: {
UNIMPLEMENTED_IF(instr.generates_cc);
const auto [base, packed_shift] = [&]() -> std::tuple<std::string, std::string> {
switch (opcode->get().GetId()) {
case OpCode::Id::BFI_IMM_R:
return {regs.GetRegisterAsInteger(instr.gpr39, 0, false),
std::to_string(instr.alu.GetSignedImm20_20())};
default:
UNREACHABLE();
}
}();
const std::string offset = '(' + packed_shift + " & 0xff)";
const std::string bits = "((" + packed_shift + " >> 8) & 0xff)";
const std::string insert = regs.GetRegisterAsInteger(instr.gpr8, 0, false);
regs.SetRegisterToInteger(
instr.gpr0, false, 0,
"bitfieldInsert(" + base + ", " + insert + ", " + offset + ", " + bits + ')', 1, 1);
break;
}
case OpCode::Type::Shift: {
std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true);
std::string op_b;
@@ -2567,83 +2510,61 @@ private:
const bool depth_compare =
instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
u32 num_coordinates = TextureCoordinates(texture_type);
u32 start_index = 0;
std::string array_elem;
if (is_array) {
array_elem = regs.GetRegisterAsInteger(instr.gpr8);
start_index = 1;
}
const auto process_mode = instr.tex.GetTextureProcessMode();
u32 start_index_b = 0;
std::string lod_value;
if (process_mode != Tegra::Shader::TextureProcessMode::LZ &&
process_mode != Tegra::Shader::TextureProcessMode::None) {
start_index_b = 1;
lod_value = regs.GetRegisterAsFloat(instr.gpr20);
}
std::string depth_value;
if (depth_compare) {
depth_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + start_index_b);
}
bool depth_compare_extra = false;
if (depth_compare)
num_coordinates += 1;
switch (num_coordinates) {
case 1: {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
if (is_array) {
if (depth_compare) {
coord = "vec3 coords = vec3(" + x + ", " + depth_value + ", " +
array_elem + ");";
} else {
coord = "vec2 coords = vec2(" + x + ", " + array_elem + ");";
}
const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
coord = "vec2 coords = vec2(" + x + ", " + index + ");";
} else {
if (depth_compare) {
coord = "vec2 coords = vec2(" + x + ", " + depth_value + ");";
} else {
coord = "float coords = " + x + ';';
}
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
coord = "float coords = " + x + ';';
}
break;
}
case 2: {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
const std::string y =
regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1);
if (is_array) {
if (depth_compare) {
coord = "vec4 coords = vec4(" + x + ", " + y + ", " + depth_value +
", " + array_elem + ");";
} else {
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + array_elem + ");";
}
const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
} else {
if (depth_compare) {
coord =
"vec3 coords = vec3(" + x + ", " + y + ", " + depth_value + ");";
} else {
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
}
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
}
break;
}
case 3: {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
const std::string y =
regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1);
const std::string z =
regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 2);
if (is_array) {
depth_compare_extra = depth_compare;
coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
array_elem + ");";
} else {
if (depth_compare) {
coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
depth_value + ");";
if (depth_compare) {
if (is_array) {
const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index +
");";
} else {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
}
} else {
if (is_array) {
const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 3);
coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index +
");";
} else {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
}
}
@@ -2659,85 +2580,82 @@ private:
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
texture_type = Tegra::Shader::TextureType::Texture2D;
}
// TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias
// or lod.
const std::string sampler =
GetSampler(instr.sampler, texture_type, is_array, depth_compare);
// 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.AddLine("{");
++shader.scope;
shader.AddLine(coord);
std::string texture;
switch (instr.tex.GetTextureProcessMode()) {
case Tegra::Shader::TextureProcessMode::None: {
if (!depth_compare_extra) {
texture = "texture(" + sampler + ", coords)";
} else {
texture = "texture(" + sampler + ", coords, " + depth_value + ')';
}
texture = "texture(" + sampler + ", coords)";
break;
}
case Tegra::Shader::TextureProcessMode::LZ: {
if (!depth_compare_extra) {
texture = "textureLod(" + sampler + ", coords, 0.0)";
} else {
texture = "texture(" + sampler + ", coords, " + depth_value + ')';
}
texture = "textureLod(" + sampler + ", coords, 0.0)";
break;
}
case Tegra::Shader::TextureProcessMode::LB:
case Tegra::Shader::TextureProcessMode::LBA: {
const std::string bias = [&]() {
if (depth_compare) {
if (is_array)
return regs.GetRegisterAsFloat(instr.gpr20.Value() + 2);
else
return regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
} else {
return regs.GetRegisterAsFloat(instr.gpr20);
}
}();
shader.AddLine("float bias = " + bias + ';');
// TODO: Figure if A suffix changes the equation at all.
if (!depth_compare_extra) {
texture = "texture(" + sampler + ", coords, " + lod_value + ')';
} else {
texture = "texture(" + sampler + ", coords, " + depth_value + ')';
LOG_WARNING(HW_GPU,
"OpenGL Limitation: can't set bias value along depth compare");
}
texture = "texture(" + sampler + ", coords, bias)";
break;
}
case Tegra::Shader::TextureProcessMode::LL:
case Tegra::Shader::TextureProcessMode::LLA: {
const std::string lod = [&]() {
if (num_coordinates <= 2) {
return regs.GetRegisterAsFloat(instr.gpr20);
} else {
return regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
}
}();
shader.AddLine("float lod = " + lod + ';');
// TODO: Figure if A suffix changes the equation at all.
if (!depth_compare_extra) {
texture = "textureLod(" + sampler + ", coords, " + lod_value + ')';
} else {
texture = "texture(" + sampler + ", coords, " + depth_value + ')';
LOG_WARNING(HW_GPU,
"OpenGL Limitation: can't set lod value along depth compare");
}
texture = "textureLod(" + sampler + ", coords, lod)";
break;
}
default: {
if (!depth_compare_extra) {
texture = "texture(" + sampler + ", coords)";
} else {
texture = "texture(" + sampler + ", coords, " + depth_value + ')';
}
texture = "texture(" + sampler + ", coords)";
UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
static_cast<u32>(instr.tex.GetTextureProcessMode()));
}
}
if (!depth_compare) {
shader.AddLine("vec4 texture_tmp = " + texture + ';');
std::size_t dest_elem{};
for (std::size_t elem = 0; elem < 4; ++elem) {
if (!instr.tex.IsComponentEnabled(elem)) {
// Skip disabled components
continue;
}
regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false,
dest_elem);
regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
++dest_elem;
}
} else {
regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
}
--shader.scope;
shader.AddLine('}');
shader.AddLine("}");
break;
}
case OpCode::Id::TEXS: {
@@ -2750,76 +2668,41 @@ private:
const bool depth_compare =
instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
u32 num_coordinates = TextureCoordinates(texture_type);
const auto process_mode = instr.texs.GetTextureProcessMode();
std::string lod_value;
std::string coord;
u32 lod_offset = 0;
if (process_mode == Tegra::Shader::TextureProcessMode::LL) {
if (num_coordinates > 2) {
lod_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
lod_offset = 2;
} else {
lod_value = regs.GetRegisterAsFloat(instr.gpr20);
lod_offset = 1;
}
}
if (depth_compare)
num_coordinates += 1;
// Scope to avoid variable name overlaps.
shader.AddLine('{');
++shader.scope;
switch (num_coordinates) {
case 1: {
coord = "float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';';
break;
}
case 2: {
if (is_array) {
if (depth_compare) {
const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index +
");";
} else {
const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
}
const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + index + ");");
} else {
if (lod_offset != 0) {
if (depth_compare) {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y =
regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string z =
regs.GetRegisterAsFloat(instr.gpr20.Value() + lod_offset);
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
} else {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y =
regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
}
} else {
if (depth_compare) {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y =
regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
} else {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
}
}
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
}
break;
}
case 3: {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
if (is_array) {
const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
index + ");");
} else {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");");
}
break;
}
default:
@@ -2829,14 +2712,14 @@ private:
// Fallback to interpreting as a 2D texture for now
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
texture_type = Tegra::Shader::TextureType::Texture2D;
is_array = false;
}
const std::string sampler =
GetSampler(instr.sampler, texture_type, is_array, depth_compare);
std::string texture;
switch (process_mode) {
switch (instr.texs.GetTextureProcessMode()) {
case Tegra::Shader::TextureProcessMode::None: {
texture = "texture(" + sampler + ", coords)";
break;
@@ -2850,7 +2733,8 @@ private:
break;
}
case Tegra::Shader::TextureProcessMode::LL: {
texture = "textureLod(" + sampler + ", coords, " + lod_value + ')';
const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
texture = "textureLod(" + sampler + ", coords, " + op_c + ')';
break;
}
default: {
@@ -2860,11 +2744,13 @@ private:
}
}
if (!depth_compare) {
WriteTexsInstruction(instr, coord, texture);
WriteTexsInstruction(instr, texture);
} else {
WriteTexsInstruction(instr, coord, "vec4(" + texture + ')');
WriteTexsInstruction(instr, "vec4(" + texture + ')');
}
shader.AddLine('}');
--shader.scope;
break;
}
case OpCode::Id::TLDS: {
@@ -2886,12 +2772,11 @@ private:
// Scope to avoid variable name overlaps.
shader.AddLine('{');
++shader.scope;
std::string coords;
switch (texture_type) {
case Tegra::Shader::TextureType::Texture1D: {
const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
coords = "float coords = " + x + ';';
shader.AddLine("int coords = " + x + ';');
break;
}
case Tegra::Shader::TextureType::Texture2D: {
@@ -2899,8 +2784,7 @@ private:
const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
const std::string y = regs.GetRegisterAsInteger(instr.gpr20);
// shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
coords = "ivec2 coords = ivec2(" + x + ", " + y + ");";
shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
extra_op_offset = 1;
break;
}
@@ -2928,7 +2812,7 @@ private:
static_cast<u32>(instr.tlds.GetTextureProcessMode()));
}
}
WriteTexsInstruction(instr, coords, texture);
WriteTexsInstruction(instr, texture);
--shader.scope;
shader.AddLine('}');
@@ -2987,17 +2871,14 @@ private:
const std::string texture = "textureGather(" + sampler + ", coords, " +
std::to_string(instr.tld4.component) + ')';
if (!depth_compare) {
shader.AddLine("vec4 texture_tmp = " + texture + ';');
std::size_t dest_elem{};
for (std::size_t elem = 0; elem < 4; ++elem) {
if (!instr.tex.IsComponentEnabled(elem)) {
// Skip disabled components
continue;
}
regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false,
dest_elem);
regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
++dest_elem;
}
} else {
@@ -3018,7 +2899,6 @@ private:
// Scope to avoid variable name overlaps.
shader.AddLine('{');
++shader.scope;
std::string coords;
const bool depth_compare =
instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
@@ -3028,19 +2908,20 @@ private:
const std::string sampler = GetSampler(
instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare);
if (!depth_compare) {
coords = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
shader.AddLine("vec2 coords = vec2(" + op_a + ", " + op_b + ");");
} else {
// Note: TLD4S coordinate encoding works just like TEXS's
const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
coords = "vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");";
shader.AddLine(
"float op_y = " + regs.GetRegisterAsFloat(instr.gpr8.Value() + 1) + ';');
shader.AddLine("vec3 coords = vec3(" + op_a + ", op_y, " + op_b + ");");
}
const std::string texture = "textureGather(" + sampler + ", coords, " +
std::to_string(instr.tld4s.component) + ')';
if (!depth_compare) {
WriteTexsInstruction(instr, coords, texture);
WriteTexsInstruction(instr, texture);
} else {
WriteTexsInstruction(instr, coords, "vec4(" + texture + ')');
WriteTexsInstruction(instr, "vec4(" + texture + ')');
}
--shader.scope;
@@ -3336,34 +3217,6 @@ private:
}
break;
}
case OpCode::Type::RegisterSetPredicate: {
UNIMPLEMENTED_IF(instr.r2p.mode != Tegra::Shader::R2pMode::Pr);
const std::string apply_mask = [&]() {
switch (opcode->get().GetId()) {
case OpCode::Id::R2P_IMM:
return std::to_string(instr.r2p.immediate_mask);
default:
UNREACHABLE();
}
}();
const std::string mask = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) +
" >> " + std::to_string(instr.r2p.byte) + ')';
constexpr u64 programmable_preds = 7;
for (u64 pred = 0; pred < programmable_preds; ++pred) {
const auto shift = std::to_string(1 << pred);
shader.AddLine("if ((" + apply_mask + " & " + shift + ") != 0) {");
++shader.scope;
SetPredicate(pred, '(' + mask + " & " + shift + ") != 0");
--shader.scope;
shader.AddLine('}');
}
break;
}
case OpCode::Type::FloatSet: {
const std::string op_a = GetOperandAbsNeg(regs.GetRegisterAsFloat(instr.gpr8),
instr.fset.abs_a != 0, instr.fset.neg_a != 0);
@@ -3401,10 +3254,6 @@ private:
regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1,
1);
}
if (instr.generates_cc.Value() != 0) {
regs.SetInternalFlag(InternalFlag::ZeroFlag, predicate);
LOG_WARNING(HW_GPU, "FSET Condition Code is incomplete");
}
break;
}
case OpCode::Type::IntegerSet: {
@@ -3658,11 +3507,6 @@ private:
regs.SetRegisterToInteger(instr.gpr0, false, 0, "0u", 1, 1);
break;
}
case Tegra::Shader::SystemVariable::Ydirection: {
// Config pack's third value is Y_NEGATE's state.
regs.SetRegisterToFloat(instr.gpr0, 0, "uintBitsToFloat(config_pack[2])", 1, 1);
break;
}
default: {
UNIMPLEMENTED_MSG("Unhandled system move: {}",
static_cast<u32>(instr.sys20.Value()));
@@ -3686,17 +3530,11 @@ private:
"BRA with constant buffers are not implemented");
const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
"BRA condition code used: {}", static_cast<u32>(cc));
const u32 target = offset + instr.bra.GetBranchTarget();
if (cc != Tegra::Shader::ConditionCode::T) {
const std::string condition_code = regs.GetConditionCode(cc);
shader.AddLine("if (" + condition_code + "){");
shader.scope++;
shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
shader.scope--;
shader.AddLine('}');
} else {
shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
}
shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
break;
}
case OpCode::Id::IPA: {

View File

@@ -24,7 +24,8 @@ layout (location = 0) out vec4 position;
layout(std140) uniform vs_config {
vec4 viewport_flip;
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
uvec4 instance_id;
uvec4 flip_stage;
uvec4 alpha_test;
};
)";
@@ -62,8 +63,7 @@ void main() {
out += R"(
// Check if the flip stage is VertexB
// Config pack's second value is flip_stage
if (config_pack[1] == 1) {
if (flip_stage[0] == 1) {
// Viewport can be flipped, which is unsupported by glViewport
position.xy *= viewport_flip.xy;
}
@@ -71,7 +71,7 @@ void main() {
// TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0
// For now, this is here to bring order in lieu of proper emulation
if (config_pack[1] == 1) {
if (flip_stage[0] == 1) {
position.w = 1.0;
}
}
@@ -101,7 +101,8 @@ layout (location = 0) out vec4 position;
layout (std140) uniform gs_config {
vec4 viewport_flip;
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
uvec4 instance_id;
uvec4 flip_stage;
uvec4 alpha_test;
};
@@ -138,7 +139,8 @@ layout (location = 0) in vec4 position;
layout (std140) uniform fs_config {
vec4 viewport_flip;
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
uvec4 instance_id;
uvec4 flip_stage;
uvec4 alpha_test;
};

View File

@@ -27,18 +27,16 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh
alpha_test.func = func;
alpha_test.ref = regs.alpha_test_ref;
instance_id = state.current_instance;
// We only assign the instance to the first component of the vector, the rest is just padding.
instance_id[0] = state.current_instance;
// Assign in which stage the position has to be flipped
// (the last stage before the fragment shader).
if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) {
flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry);
flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry);
} else {
flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB);
flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB);
}
// Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value.
y_direction = regs.screen_y_control.y_negate == 0 ? 1.f : -1.f;
}
} // namespace OpenGL::GLShader

View File

@@ -21,11 +21,8 @@ using Tegra::Engines::Maxwell3D;
struct MaxwellUniformData {
void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage);
alignas(16) GLvec4 viewport_flip;
struct alignas(16) {
GLuint instance_id;
GLuint flip_stage;
GLfloat y_direction;
};
alignas(16) GLuvec4 instance_id;
alignas(16) GLuvec4 flip_stage;
struct alignas(16) {
GLuint enabled;
GLuint func;
@@ -33,7 +30,7 @@ struct MaxwellUniformData {
GLuint padding;
} alpha_test;
};
static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect");
static_assert(sizeof(MaxwellUniformData) == 64, "MaxwellUniformData structure size is incorrect");
static_assert(sizeof(MaxwellUniformData) < 16384,
"MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");

View File

@@ -92,13 +92,6 @@ OpenGLState::OpenGLState() {
point.size = 1;
fragment_color_clamp.enabled = false;
polygon_offset.fill_enable = false;
polygon_offset.line_enable = false;
polygon_offset.point_enable = false;
polygon_offset.factor = 0.0f;
polygon_offset.units = 0.0f;
polygon_offset.clamp = 0.0f;
}
void OpenGLState::ApplyDefaultState() {
@@ -413,55 +406,6 @@ void OpenGLState::ApplyLogicOp() const {
}
}
void OpenGLState::ApplyPolygonOffset() const {
const bool fill_enable_changed =
polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable;
const bool line_enable_changed =
polygon_offset.line_enable != cur_state.polygon_offset.line_enable;
const bool point_enable_changed =
polygon_offset.point_enable != cur_state.polygon_offset.point_enable;
const bool factor_changed = polygon_offset.factor != cur_state.polygon_offset.factor;
const bool units_changed = polygon_offset.units != cur_state.polygon_offset.units;
const bool clamp_changed = polygon_offset.clamp != cur_state.polygon_offset.clamp;
if (fill_enable_changed) {
if (polygon_offset.fill_enable) {
glEnable(GL_POLYGON_OFFSET_FILL);
} else {
glDisable(GL_POLYGON_OFFSET_FILL);
}
}
if (line_enable_changed) {
if (polygon_offset.line_enable) {
glEnable(GL_POLYGON_OFFSET_LINE);
} else {
glDisable(GL_POLYGON_OFFSET_LINE);
}
}
if (point_enable_changed) {
if (polygon_offset.point_enable) {
glEnable(GL_POLYGON_OFFSET_POINT);
} else {
glDisable(GL_POLYGON_OFFSET_POINT);
}
}
if ((polygon_offset.fill_enable || polygon_offset.line_enable || polygon_offset.point_enable) &&
(factor_changed || units_changed || clamp_changed)) {
if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) {
glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp);
} else {
glPolygonOffset(polygon_offset.factor, polygon_offset.units);
UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0,
"Unimplemented Depth polygon offset clamp.");
}
}
}
void OpenGLState::ApplyTextures() const {
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
const auto& texture_unit = texture_units[i];
@@ -588,7 +532,6 @@ void OpenGLState::Apply() const {
ApplyLogicOp();
ApplyTextures();
ApplySamplers();
ApplyPolygonOffset();
cur_state = *this;
}

View File

@@ -176,15 +176,6 @@ public:
float size; // GL_POINT_SIZE
} point;
struct {
bool point_enable;
bool line_enable;
bool fill_enable;
GLfloat units;
GLfloat factor;
GLfloat clamp;
} polygon_offset;
std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE
OpenGLState();
@@ -235,7 +226,6 @@ private:
void ApplyLogicOp() const;
void ApplyTextures() const;
void ApplySamplers() const;
void ApplyPolygonOffset() const;
};
} // namespace OpenGL

View File

@@ -19,9 +19,9 @@
#include "core/settings.h"
#include "core/telemetry_session.h"
#include "core/tracer/recorder.h"
#include "video_core/morton.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/utils.h"
namespace OpenGL {

164
src/video_core/utils.h Normal file
View File

@@ -0,0 +1,164 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
namespace VideoCore {
// 8x8 Z-Order coordinate from 2D coordinates
static inline u32 MortonInterleave(u32 x, u32 y) {
static const u32 xlut[] = {0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15};
static const u32 ylut[] = {0x00, 0x02, 0x08, 0x0a, 0x20, 0x22, 0x28, 0x2a};
return xlut[x % 8] + ylut[y % 8];
}
/**
* Calculates the offset of the position of the pixel in Morton order
*/
static inline u32 GetMortonOffset(u32 x, u32 y, u32 bytes_per_pixel) {
// Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each
// of which is composed of four 2x2 subtiles each of which is composed of four texels.
// Each structure is embedded into the next-bigger one in a diagonal pattern, e.g.
// texels are laid out in a 2x2 subtile like this:
// 2 3
// 0 1
//
// The full 8x8 tile has the texels arranged like this:
//
// 42 43 46 47 58 59 62 63
// 40 41 44 45 56 57 60 61
// 34 35 38 39 50 51 54 55
// 32 33 36 37 48 49 52 53
// 10 11 14 15 26 27 30 31
// 08 09 12 13 24 25 28 29
// 02 03 06 07 18 19 22 23
// 00 01 04 05 16 17 20 21
//
// This pattern is what's called Z-order curve, or Morton order.
const unsigned int block_height = 8;
const unsigned int coarse_x = x & ~7;
u32 i = VideoCore::MortonInterleave(x, y);
const unsigned int offset = coarse_x * block_height;
return (i + offset) * bytes_per_pixel;
}
static inline u32 MortonInterleave128(u32 x, u32 y) {
// 128x128 Z-Order coordinate from 2D coordinates
static constexpr u32 xlut[] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042,
0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809,
0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000,
0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043,
0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a,
0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001,
0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048,
0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b,
0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002,
0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049,
0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840,
0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003,
0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a,
0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841,
0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008,
0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b,
0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842,
0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009,
0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800,
0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843,
0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a,
0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801,
0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848,
0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b,
0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802,
0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849,
0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040,
0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803,
0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a,
0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041,
0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808,
0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b,
0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042,
0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809,
0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b,
};
static constexpr u32 ylut[] = {
0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090,
0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124,
0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200,
0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294,
0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330,
0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404,
0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0,
0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534,
0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610,
0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4,
0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780,
0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014,
0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0,
0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184,
0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220,
0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4,
0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390,
0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424,
0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500,
0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594,
0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630,
0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704,
0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0,
0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034,
0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110,
0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4,
0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280,
0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314,
0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0,
0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484,
0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520,
0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4,
0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690,
0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724,
0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4,
};
return xlut[x % 128] + ylut[y % 128];
}
static inline u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) {
// Calculates the offset of the position of the pixel in Morton order
// Framebuffer images are split into 128x128 tiles.
const unsigned int block_height = 128;
const unsigned int coarse_x = x & ~127;
u32 i = MortonInterleave128(x, y);
const unsigned int offset = coarse_x * block_height;
return (i + offset) * bytes_per_pixel;
}
static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel,
u32 gl_bytes_per_pixel, u8* morton_data, u8* gl_data,
bool morton_to_gl) {
u8* data_ptrs[2];
for (unsigned y = 0; y < height; ++y) {
for (unsigned x = 0; x < width; ++x) {
const u32 coarse_y = y & ~127;
u32 morton_offset =
GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
u32 gl_pixel_index = (x + y * width) * gl_bytes_per_pixel;
data_ptrs[morton_to_gl] = morton_data + morton_offset;
data_ptrs[!morton_to_gl] = &gl_data[gl_pixel_index];
memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
}
}
}
} // namespace VideoCore