Compare commits
1 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4e68bbb32 |
@@ -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!")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -183,9 +183,6 @@ private:
|
||||
/// Syncs Color Mask
|
||||
void SyncColorMask();
|
||||
|
||||
/// Syncs the polygon offsets
|
||||
void SyncPolygonOffset();
|
||||
|
||||
/// Check asserts for alpha testing.
|
||||
void CheckAlphaTests();
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
164
src/video_core/utils.h
Normal 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
|
||||
Reference in New Issue
Block a user