mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #2900 from wwylele/clip-2
PICA: implement custom clip plane
This commit is contained in:
		
						commit
						699c920991
					
				@ -5,10 +5,10 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "common/bit_field.h"
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/pica_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Pica {
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,17 @@ struct RasterizerRegs {
 | 
			
		||||
 | 
			
		||||
    BitField<0, 24, u32> viewport_size_y;
 | 
			
		||||
 | 
			
		||||
    INSERT_PADDING_WORDS(0x9);
 | 
			
		||||
    INSERT_PADDING_WORDS(0x3);
 | 
			
		||||
 | 
			
		||||
    BitField<0, 1, u32> clip_enable;
 | 
			
		||||
    BitField<0, 24, u32> clip_coef[4]; // float24
 | 
			
		||||
 | 
			
		||||
    Math::Vec4<float24> GetClipCoef() const {
 | 
			
		||||
        return {float24::FromRaw(clip_coef[0]), float24::FromRaw(clip_coef[1]),
 | 
			
		||||
                float24::FromRaw(clip_coef[2]), float24::FromRaw(clip_coef[3])};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    INSERT_PADDING_WORDS(0x1);
 | 
			
		||||
 | 
			
		||||
    BitField<0, 24, u32> viewport_depth_range;      // float24
 | 
			
		||||
    BitField<0, 24, u32> viewport_depth_near_plane; // float24
 | 
			
		||||
 | 
			
		||||
@ -169,6 +169,8 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) {
 | 
			
		||||
    glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, proctex_diff_lut_buffer.handle);
 | 
			
		||||
 | 
			
		||||
    // Sync fixed function OpenGL state
 | 
			
		||||
    SyncClipEnabled();
 | 
			
		||||
    SyncClipCoef();
 | 
			
		||||
    SyncCullMode();
 | 
			
		||||
    SyncBlendEnabled();
 | 
			
		||||
    SyncBlendFuncs();
 | 
			
		||||
@ -401,6 +403,18 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
 | 
			
		||||
        SyncCullMode();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    // Clipping plane
 | 
			
		||||
    case PICA_REG_INDEX(rasterizer.clip_enable):
 | 
			
		||||
        SyncClipEnabled();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(rasterizer.clip_coef[0], 0x48):
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(rasterizer.clip_coef[1], 0x49):
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(rasterizer.clip_coef[2], 0x4a):
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(rasterizer.clip_coef[3], 0x4b):
 | 
			
		||||
        SyncClipCoef();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    // Depth modifiers
 | 
			
		||||
    case PICA_REG_INDEX(rasterizer.viewport_depth_range):
 | 
			
		||||
        SyncDepthScale();
 | 
			
		||||
@ -1280,6 +1294,20 @@ void RasterizerOpenGL::SetShader() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncClipEnabled() {
 | 
			
		||||
    state.clip_distance[1] = Pica::g_state.regs.rasterizer.clip_enable != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncClipCoef() {
 | 
			
		||||
    const auto raw_clip_coef = Pica::g_state.regs.rasterizer.GetClipCoef();
 | 
			
		||||
    const GLvec4 new_clip_coef = {raw_clip_coef.x.ToFloat32(), raw_clip_coef.y.ToFloat32(),
 | 
			
		||||
                                  raw_clip_coef.z.ToFloat32(), raw_clip_coef.w.ToFloat32()};
 | 
			
		||||
    if (new_clip_coef != uniform_block_data.data.clip_coef) {
 | 
			
		||||
        uniform_block_data.data.clip_coef = new_clip_coef;
 | 
			
		||||
        uniform_block_data.dirty = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncCullMode() {
 | 
			
		||||
    const auto& regs = Pica::g_state.regs;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -151,14 +151,21 @@ private:
 | 
			
		||||
        LightSrc light_src[8];
 | 
			
		||||
        alignas(16) GLvec4 const_color[6]; // A vec4 color for each of the six tev stages
 | 
			
		||||
        alignas(16) GLvec4 tev_combiner_buffer_color;
 | 
			
		||||
        alignas(16) GLvec4 clip_coef;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static_assert(
 | 
			
		||||
        sizeof(UniformData) == 0x460,
 | 
			
		||||
        sizeof(UniformData) == 0x470,
 | 
			
		||||
        "The size of the UniformData structure has changed, update the structure in the shader");
 | 
			
		||||
    static_assert(sizeof(UniformData) < 16384,
 | 
			
		||||
                  "UniformData structure must be less than 16kb as per the OpenGL spec");
 | 
			
		||||
 | 
			
		||||
    /// Syncs the clip enabled status to match the PICA register
 | 
			
		||||
    void SyncClipEnabled();
 | 
			
		||||
 | 
			
		||||
    /// Syncs the clip coefficients to match the PICA register
 | 
			
		||||
    void SyncClipCoef();
 | 
			
		||||
 | 
			
		||||
    /// Sets the OpenGL shader in accordance with the current PICA register state
 | 
			
		||||
    void SetShader();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,42 @@ using TevStageConfig = TexturingRegs::TevStageConfig;
 | 
			
		||||
 | 
			
		||||
namespace GLShader {
 | 
			
		||||
 | 
			
		||||
static const std::string UniformBlockDef = R"(
 | 
			
		||||
#define NUM_TEV_STAGES 6
 | 
			
		||||
#define NUM_LIGHTS 8
 | 
			
		||||
 | 
			
		||||
struct LightSrc {
 | 
			
		||||
    vec3 specular_0;
 | 
			
		||||
    vec3 specular_1;
 | 
			
		||||
    vec3 diffuse;
 | 
			
		||||
    vec3 ambient;
 | 
			
		||||
    vec3 position;
 | 
			
		||||
    vec3 spot_direction;
 | 
			
		||||
    float dist_atten_bias;
 | 
			
		||||
    float dist_atten_scale;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
layout (std140) uniform shader_data {
 | 
			
		||||
    vec2 framebuffer_scale;
 | 
			
		||||
    int alphatest_ref;
 | 
			
		||||
    float depth_scale;
 | 
			
		||||
    float depth_offset;
 | 
			
		||||
    int scissor_x1;
 | 
			
		||||
    int scissor_y1;
 | 
			
		||||
    int scissor_x2;
 | 
			
		||||
    int scissor_y2;
 | 
			
		||||
    vec3 fog_color;
 | 
			
		||||
    vec2 proctex_noise_f;
 | 
			
		||||
    vec2 proctex_noise_a;
 | 
			
		||||
    vec2 proctex_noise_p;
 | 
			
		||||
    vec3 lighting_global_ambient;
 | 
			
		||||
    LightSrc light_src[NUM_LIGHTS];
 | 
			
		||||
    vec4 const_color[NUM_TEV_STAGES];
 | 
			
		||||
    vec4 tev_combiner_buffer_color;
 | 
			
		||||
    vec4 clip_coef;
 | 
			
		||||
};
 | 
			
		||||
)";
 | 
			
		||||
 | 
			
		||||
PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) {
 | 
			
		||||
    PicaShaderConfig res;
 | 
			
		||||
 | 
			
		||||
@ -1010,8 +1046,6 @@ std::string GenerateFragmentShader(const PicaShaderConfig& config) {
 | 
			
		||||
 | 
			
		||||
    std::string out = R"(
 | 
			
		||||
#version 330 core
 | 
			
		||||
#define NUM_TEV_STAGES 6
 | 
			
		||||
#define NUM_LIGHTS 8
 | 
			
		||||
 | 
			
		||||
in vec4 primary_color;
 | 
			
		||||
in vec2 texcoord[3];
 | 
			
		||||
@ -1023,36 +1057,6 @@ in vec4 gl_FragCoord;
 | 
			
		||||
 | 
			
		||||
out vec4 color;
 | 
			
		||||
 | 
			
		||||
struct LightSrc {
 | 
			
		||||
    vec3 specular_0;
 | 
			
		||||
    vec3 specular_1;
 | 
			
		||||
    vec3 diffuse;
 | 
			
		||||
    vec3 ambient;
 | 
			
		||||
    vec3 position;
 | 
			
		||||
    vec3 spot_direction;
 | 
			
		||||
    float dist_atten_bias;
 | 
			
		||||
    float dist_atten_scale;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
layout (std140) uniform shader_data {
 | 
			
		||||
    vec2 framebuffer_scale;
 | 
			
		||||
    int alphatest_ref;
 | 
			
		||||
    float depth_scale;
 | 
			
		||||
    float depth_offset;
 | 
			
		||||
    int scissor_x1;
 | 
			
		||||
    int scissor_y1;
 | 
			
		||||
    int scissor_x2;
 | 
			
		||||
    int scissor_y2;
 | 
			
		||||
    vec3 fog_color;
 | 
			
		||||
    vec2 proctex_noise_f;
 | 
			
		||||
    vec2 proctex_noise_a;
 | 
			
		||||
    vec2 proctex_noise_p;
 | 
			
		||||
    vec3 lighting_global_ambient;
 | 
			
		||||
    LightSrc light_src[NUM_LIGHTS];
 | 
			
		||||
    vec4 const_color[NUM_TEV_STAGES];
 | 
			
		||||
    vec4 tev_combiner_buffer_color;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
uniform sampler2D tex[3];
 | 
			
		||||
uniform samplerBuffer lighting_lut;
 | 
			
		||||
uniform samplerBuffer fog_lut;
 | 
			
		||||
@ -1061,7 +1065,11 @@ uniform samplerBuffer proctex_color_map;
 | 
			
		||||
uniform samplerBuffer proctex_alpha_map;
 | 
			
		||||
uniform samplerBuffer proctex_lut;
 | 
			
		||||
uniform samplerBuffer proctex_diff_lut;
 | 
			
		||||
)";
 | 
			
		||||
 | 
			
		||||
    out += UniformBlockDef;
 | 
			
		||||
 | 
			
		||||
    out += R"(
 | 
			
		||||
// Rotate the vector v by the quaternion q
 | 
			
		||||
vec3 quaternion_rotate(vec4 q, vec3 v) {
 | 
			
		||||
    return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);
 | 
			
		||||
@ -1197,6 +1205,12 @@ out float texcoord0_w;
 | 
			
		||||
out vec4 normquat;
 | 
			
		||||
out vec3 view;
 | 
			
		||||
 | 
			
		||||
)";
 | 
			
		||||
 | 
			
		||||
    out += UniformBlockDef;
 | 
			
		||||
 | 
			
		||||
    out += R"(
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    primary_color = vert_color;
 | 
			
		||||
    texcoord[0] = vert_texcoord0;
 | 
			
		||||
@ -1207,7 +1221,7 @@ void main() {
 | 
			
		||||
    view = vert_view;
 | 
			
		||||
    gl_Position = vert_position;
 | 
			
		||||
    gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0
 | 
			
		||||
    // TODO (wwylele): calculate gl_ClipDistance[1] from user-defined clipping plane
 | 
			
		||||
    gl_ClipDistance[1] = dot(clip_coef, vert_position);
 | 
			
		||||
}
 | 
			
		||||
)";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,7 @@ public:
 | 
			
		||||
        : coeffs(coeffs), bias(bias) {}
 | 
			
		||||
 | 
			
		||||
    bool IsInside(const Vertex& vertex) const {
 | 
			
		||||
        return Math::Dot(vertex.pos + bias, coeffs) <= float24::FromFloat32(0);
 | 
			
		||||
        return Math::Dot(vertex.pos + bias, coeffs) >= float24::FromFloat32(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool IsOutSide(const Vertex& vertex) const {
 | 
			
		||||
@ -116,19 +116,18 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu
 | 
			
		||||
    static const float24 f0 = float24::FromFloat32(0.0);
 | 
			
		||||
    static const float24 f1 = float24::FromFloat32(1.0);
 | 
			
		||||
    static const std::array<ClippingEdge, 7> clipping_edges = {{
 | 
			
		||||
        {Math::MakeVec(f1, f0, f0, -f1)},                                           // x = +w
 | 
			
		||||
        {Math::MakeVec(-f1, f0, f0, -f1)},                                          // x = -w
 | 
			
		||||
        {Math::MakeVec(f0, f1, f0, -f1)},                                           // y = +w
 | 
			
		||||
        {Math::MakeVec(f0, -f1, f0, -f1)},                                          // y = -w
 | 
			
		||||
        {Math::MakeVec(f0, f0, f1, f0)},                                            // z =  0
 | 
			
		||||
        {Math::MakeVec(f0, f0, -f1, -f1)},                                          // z = -w
 | 
			
		||||
        {Math::MakeVec(f0, f0, f0, -f1), Math::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON
 | 
			
		||||
        {Math::MakeVec(-f1, f0, f0, f1)},                                          // x = +w
 | 
			
		||||
        {Math::MakeVec(f1, f0, f0, f1)},                                           // x = -w
 | 
			
		||||
        {Math::MakeVec(f0, -f1, f0, f1)},                                          // y = +w
 | 
			
		||||
        {Math::MakeVec(f0, f1, f0, f1)},                                           // y = -w
 | 
			
		||||
        {Math::MakeVec(f0, f0, -f1, f0)},                                          // z =  0
 | 
			
		||||
        {Math::MakeVec(f0, f0, f1, f1)},                                           // z = -w
 | 
			
		||||
        {Math::MakeVec(f0, f0, f0, f1), Math::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON
 | 
			
		||||
    }};
 | 
			
		||||
 | 
			
		||||
    // Simple implementation of the Sutherland-Hodgman clipping algorithm.
 | 
			
		||||
    // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here)
 | 
			
		||||
    for (auto edge : clipping_edges) {
 | 
			
		||||
 | 
			
		||||
    auto Clip = [&](const ClippingEdge& edge) {
 | 
			
		||||
        std::swap(input_list, output_list);
 | 
			
		||||
        output_list->clear();
 | 
			
		||||
 | 
			
		||||
@ -147,12 +146,24 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu
 | 
			
		||||
            }
 | 
			
		||||
            reference_vertex = &vertex;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for (auto edge : clipping_edges) {
 | 
			
		||||
        Clip(edge);
 | 
			
		||||
 | 
			
		||||
        // Need to have at least a full triangle to continue...
 | 
			
		||||
        if (output_list->size() < 3)
 | 
			
		||||
            return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (g_state.regs.rasterizer.clip_enable) {
 | 
			
		||||
        ClippingEdge custom_edge{g_state.regs.rasterizer.GetClipCoef()};
 | 
			
		||||
        Clip(custom_edge);
 | 
			
		||||
 | 
			
		||||
        if (output_list->size() < 3)
 | 
			
		||||
            return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    InitScreenCoordinates((*output_list)[0]);
 | 
			
		||||
    InitScreenCoordinates((*output_list)[1]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user