mirror of
https://github.com/Lime3DS/Lime3DS
synced 2024-11-01 04:37:52 +00:00
Merge pull request #2900 from wwylele/clip-2
PICA: implement custom clip plane
This commit is contained in:
commit
699c920991
5 changed files with 116 additions and 46 deletions
|
@ -5,10 +5,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "video_core/pica_types.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
|
|
||||||
|
@ -31,7 +31,17 @@ struct RasterizerRegs {
|
||||||
|
|
||||||
BitField<0, 24, u32> viewport_size_y;
|
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_range; // float24
|
||||||
BitField<0, 24, u32> viewport_depth_near_plane; // 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);
|
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, proctex_diff_lut_buffer.handle);
|
||||||
|
|
||||||
// Sync fixed function OpenGL state
|
// Sync fixed function OpenGL state
|
||||||
|
SyncClipEnabled();
|
||||||
|
SyncClipCoef();
|
||||||
SyncCullMode();
|
SyncCullMode();
|
||||||
SyncBlendEnabled();
|
SyncBlendEnabled();
|
||||||
SyncBlendFuncs();
|
SyncBlendFuncs();
|
||||||
|
@ -401,6 +403,18 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||||
SyncCullMode();
|
SyncCullMode();
|
||||||
break;
|
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
|
// Depth modifiers
|
||||||
case PICA_REG_INDEX(rasterizer.viewport_depth_range):
|
case PICA_REG_INDEX(rasterizer.viewport_depth_range):
|
||||||
SyncDepthScale();
|
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() {
|
void RasterizerOpenGL::SyncCullMode() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
|
|
||||||
|
|
|
@ -151,14 +151,21 @@ private:
|
||||||
LightSrc light_src[8];
|
LightSrc light_src[8];
|
||||||
alignas(16) GLvec4 const_color[6]; // A vec4 color for each of the six tev stages
|
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 tev_combiner_buffer_color;
|
||||||
|
alignas(16) GLvec4 clip_coef;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
sizeof(UniformData) == 0x460,
|
sizeof(UniformData) == 0x470,
|
||||||
"The size of the UniformData structure has changed, update the structure in the shader");
|
"The size of the UniformData structure has changed, update the structure in the shader");
|
||||||
static_assert(sizeof(UniformData) < 16384,
|
static_assert(sizeof(UniformData) < 16384,
|
||||||
"UniformData structure must be less than 16kb as per the OpenGL spec");
|
"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
|
/// Sets the OpenGL shader in accordance with the current PICA register state
|
||||||
void SetShader();
|
void SetShader();
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,42 @@ using TevStageConfig = TexturingRegs::TevStageConfig;
|
||||||
|
|
||||||
namespace GLShader {
|
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 PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) {
|
||||||
PicaShaderConfig res;
|
PicaShaderConfig res;
|
||||||
|
|
||||||
|
@ -1010,8 +1046,6 @@ std::string GenerateFragmentShader(const PicaShaderConfig& config) {
|
||||||
|
|
||||||
std::string out = R"(
|
std::string out = R"(
|
||||||
#version 330 core
|
#version 330 core
|
||||||
#define NUM_TEV_STAGES 6
|
|
||||||
#define NUM_LIGHTS 8
|
|
||||||
|
|
||||||
in vec4 primary_color;
|
in vec4 primary_color;
|
||||||
in vec2 texcoord[3];
|
in vec2 texcoord[3];
|
||||||
|
@ -1023,36 +1057,6 @@ in vec4 gl_FragCoord;
|
||||||
|
|
||||||
out vec4 color;
|
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 sampler2D tex[3];
|
||||||
uniform samplerBuffer lighting_lut;
|
uniform samplerBuffer lighting_lut;
|
||||||
uniform samplerBuffer fog_lut;
|
uniform samplerBuffer fog_lut;
|
||||||
|
@ -1061,7 +1065,11 @@ uniform samplerBuffer proctex_color_map;
|
||||||
uniform samplerBuffer proctex_alpha_map;
|
uniform samplerBuffer proctex_alpha_map;
|
||||||
uniform samplerBuffer proctex_lut;
|
uniform samplerBuffer proctex_lut;
|
||||||
uniform samplerBuffer proctex_diff_lut;
|
uniform samplerBuffer proctex_diff_lut;
|
||||||
|
)";
|
||||||
|
|
||||||
|
out += UniformBlockDef;
|
||||||
|
|
||||||
|
out += R"(
|
||||||
// Rotate the vector v by the quaternion q
|
// Rotate the vector v by the quaternion q
|
||||||
vec3 quaternion_rotate(vec4 q, vec3 v) {
|
vec3 quaternion_rotate(vec4 q, vec3 v) {
|
||||||
return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * 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 vec4 normquat;
|
||||||
out vec3 view;
|
out vec3 view;
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
out += UniformBlockDef;
|
||||||
|
|
||||||
|
out += R"(
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
primary_color = vert_color;
|
primary_color = vert_color;
|
||||||
texcoord[0] = vert_texcoord0;
|
texcoord[0] = vert_texcoord0;
|
||||||
|
@ -1207,7 +1221,7 @@ void main() {
|
||||||
view = vert_view;
|
view = vert_view;
|
||||||
gl_Position = vert_position;
|
gl_Position = vert_position;
|
||||||
gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0
|
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) {}
|
: coeffs(coeffs), bias(bias) {}
|
||||||
|
|
||||||
bool IsInside(const Vertex& vertex) const {
|
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 {
|
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 f0 = float24::FromFloat32(0.0);
|
||||||
static const float24 f1 = float24::FromFloat32(1.0);
|
static const float24 f1 = float24::FromFloat32(1.0);
|
||||||
static const std::array<ClippingEdge, 7> clipping_edges = {{
|
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(-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, -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, f0)}, // z = 0
|
||||||
{Math::MakeVec(f0, f0, -f1, -f1)}, // z = -w
|
{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(f0, f0, f0, f1), Math::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// Simple implementation of the Sutherland-Hodgman clipping algorithm.
|
// Simple implementation of the Sutherland-Hodgman clipping algorithm.
|
||||||
// TODO: Make this less inefficient (currently lots of useless buffering overhead happens here)
|
// 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);
|
std::swap(input_list, output_list);
|
||||||
output_list->clear();
|
output_list->clear();
|
||||||
|
|
||||||
|
@ -147,12 +146,24 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu
|
||||||
}
|
}
|
||||||
reference_vertex = &vertex;
|
reference_vertex = &vertex;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto edge : clipping_edges) {
|
||||||
|
Clip(edge);
|
||||||
|
|
||||||
// Need to have at least a full triangle to continue...
|
// Need to have at least a full triangle to continue...
|
||||||
if (output_list->size() < 3)
|
if (output_list->size() < 3)
|
||||||
return;
|
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)[0]);
|
||||||
InitScreenCoordinates((*output_list)[1]);
|
InitScreenCoordinates((*output_list)[1]);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue