2021-08-07 18:57:13 -04:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <vector>
|
2022-06-22 23:37:46 -04:00
|
|
|
|
2021-10-31 13:12:50 -04:00
|
|
|
#include "common/dma/gs.h"
|
2021-08-07 18:57:13 -04:00
|
|
|
#include "common/math/Vector.h"
|
|
|
|
#include "common/util/SmallVector.h"
|
2022-06-22 23:37:46 -04:00
|
|
|
|
|
|
|
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
2021-08-09 21:42:05 -04:00
|
|
|
#include "game/graphics/pipelines/opengl.h"
|
2021-08-07 18:57:13 -04:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* The direct renderer will handle rendering GIFtags directly.
|
|
|
|
* It's named after the DIRECT VIFCode which sends data directly to the GS.
|
|
|
|
*
|
|
|
|
* It should mostly be used for debugging/text stuff as this rendering style does all the math on
|
|
|
|
* the EE and just sends geometry directly to the GS without using the VUs.
|
|
|
|
*
|
|
|
|
* It can be used as a BucketRenderer, or as a subcomponent of another renderer.
|
|
|
|
*/
|
|
|
|
class DirectRenderer : public BucketRenderer {
|
|
|
|
public:
|
2022-09-05 20:29:12 -04:00
|
|
|
DirectRenderer(const std::string& name, int my_id, int batch_size);
|
2023-07-14 18:17:54 -04:00
|
|
|
void init_shaders(ShaderLibrary& sl) override;
|
2023-08-15 21:53:06 -04:00
|
|
|
void draw_debug_window() override;
|
2021-10-10 20:07:03 -04:00
|
|
|
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
2023-02-27 19:51:14 -05:00
|
|
|
virtual void pre_render() {}
|
|
|
|
virtual void post_render() {}
|
2023-08-15 21:53:06 -04:00
|
|
|
~DirectRenderer();
|
|
|
|
|
2021-08-07 18:57:13 -04:00
|
|
|
/*!
|
|
|
|
* Render directly from _VIF_ data.
|
|
|
|
* You can optionally provide two vif tags that come in front of data.
|
|
|
|
* These can be set to 0 if you don't have these.
|
|
|
|
*/
|
2021-10-10 20:07:03 -04:00
|
|
|
void render_vif(u32 vif0,
|
|
|
|
u32 vif1,
|
|
|
|
const u8* data,
|
|
|
|
u32 size,
|
|
|
|
SharedRenderState* render_state,
|
|
|
|
ScopedProfilerNode& prof);
|
2021-08-07 18:57:13 -04:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Render directly from _GIF_ data.
|
|
|
|
*/
|
2021-10-10 20:07:03 -04:00
|
|
|
void render_gif(const u8* data,
|
|
|
|
u32 size,
|
|
|
|
SharedRenderState* render_state,
|
|
|
|
ScopedProfilerNode& prof);
|
2021-08-07 18:57:13 -04:00
|
|
|
|
|
|
|
void reset_state();
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* If you don't use the render interface, call this at the very end.
|
|
|
|
*/
|
2021-10-10 20:07:03 -04:00
|
|
|
void flush_pending(SharedRenderState* render_state, ScopedProfilerNode& prof);
|
2021-08-07 18:57:13 -04:00
|
|
|
|
2022-02-24 22:33:10 -05:00
|
|
|
void hack_disable_blend() {
|
|
|
|
m_blend_state.a = GsAlpha::BlendMode::SOURCE;
|
|
|
|
m_blend_state.b = GsAlpha::BlendMode::SOURCE;
|
|
|
|
m_blend_state.c = GsAlpha::BlendMode::SOURCE;
|
|
|
|
m_blend_state.d = GsAlpha::BlendMode::SOURCE;
|
|
|
|
}
|
|
|
|
|
2022-03-14 19:47:29 -04:00
|
|
|
void set_mipmap(bool en) { m_debug_state.disable_mipmap = !en; }
|
2021-10-10 20:07:03 -04:00
|
|
|
void handle_prim(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
2023-02-27 19:51:14 -05:00
|
|
|
void handle_ad(const u8* data, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
2021-08-07 21:16:44 -04:00
|
|
|
void handle_st_packed(const u8* data);
|
|
|
|
void handle_rgbaq_packed(const u8* data);
|
2021-10-10 20:07:03 -04:00
|
|
|
void handle_xyzf2_packed(const u8* data,
|
|
|
|
SharedRenderState* render_state,
|
|
|
|
ScopedProfilerNode& prof);
|
2022-09-05 20:29:12 -04:00
|
|
|
void handle_xyz2_packed(const u8* data,
|
|
|
|
SharedRenderState* render_state,
|
|
|
|
ScopedProfilerNode& prof);
|
2023-02-27 19:51:14 -05:00
|
|
|
void handle_prim_packed(const u8* data,
|
|
|
|
SharedRenderState* render_state,
|
|
|
|
ScopedProfilerNode& prof);
|
2022-02-25 14:44:31 -05:00
|
|
|
void handle_tex0_1_packed(const u8* data);
|
2023-02-27 19:51:14 -05:00
|
|
|
void handle_uv_packed(const u8* data);
|
|
|
|
void handle_rgbaq(u64 val);
|
|
|
|
void handle_xyzf2(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
2023-08-15 21:53:06 -04:00
|
|
|
void lookup_textures_again(SharedRenderState* render_state);
|
2023-08-18 11:04:31 -04:00
|
|
|
void reinitialize_gl_state() {
|
|
|
|
m_prim_gl_state_needs_gl_update = true;
|
|
|
|
m_test_state_needs_gl_update = true;
|
|
|
|
m_blend_state_needs_gl_update = true;
|
|
|
|
}
|
2023-02-27 19:51:14 -05:00
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void handle_frame(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
2023-05-04 18:34:09 -04:00
|
|
|
void handle_scissor(u64 val);
|
2023-02-27 19:51:14 -05:00
|
|
|
void handle_zbuf1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
|
|
|
void handle_test1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
|
|
|
void handle_alpha1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
|
|
|
void handle_pabe(u64 val);
|
|
|
|
void handle_clamp1(u64 val);
|
2022-02-25 14:44:31 -05:00
|
|
|
void handle_tex0_1(u64 val);
|
|
|
|
void handle_tex1_1(u64 val);
|
2023-02-27 19:51:14 -05:00
|
|
|
void handle_texa(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
|
|
|
void handle_xyoffset(u64 val);
|
2023-05-04 18:34:09 -04:00
|
|
|
void handle_bitbltbuf(u64 val);
|
|
|
|
void handle_trxpos(u64 val);
|
|
|
|
void handle_trxreg(u64 val);
|
|
|
|
void handle_trxdir(u64 dir, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
2021-10-10 20:07:03 -04:00
|
|
|
void handle_xyzf2_common(u32 x,
|
|
|
|
u32 y,
|
|
|
|
u32 z,
|
|
|
|
u8 f,
|
|
|
|
SharedRenderState* render_state,
|
2021-11-13 20:44:17 -05:00
|
|
|
ScopedProfilerNode& prof,
|
|
|
|
bool advance);
|
2021-08-07 18:57:13 -04:00
|
|
|
|
2021-08-08 20:46:14 -04:00
|
|
|
void update_gl_prim(SharedRenderState* render_state);
|
2021-08-07 18:57:13 -04:00
|
|
|
void update_gl_blend();
|
|
|
|
void update_gl_test();
|
2022-01-06 18:47:20 -05:00
|
|
|
void update_gl_texture(SharedRenderState* render_state, int unit);
|
2023-02-27 19:51:14 -05:00
|
|
|
bool m_offscreen_mode = false;
|
2021-08-08 20:46:14 -04:00
|
|
|
|
2021-08-07 18:57:13 -04:00
|
|
|
struct TestState {
|
|
|
|
void from_register(GsTest reg);
|
|
|
|
|
|
|
|
GsTest current_register;
|
|
|
|
bool alpha_test_enable = false;
|
|
|
|
bool prim_alpha_enable = false;
|
|
|
|
GsTest::AlphaTest alpha_test = GsTest::AlphaTest::NOTEQUAL;
|
|
|
|
u8 aref = 0;
|
|
|
|
GsTest::AlphaFail afail = GsTest::AlphaFail::KEEP;
|
|
|
|
bool date = false;
|
|
|
|
bool datm = false;
|
|
|
|
bool zte = true;
|
|
|
|
GsTest::ZTest ztst = GsTest::ZTest::GEQUAL;
|
2023-02-27 19:51:14 -05:00
|
|
|
bool write_rgb = true;
|
2021-09-26 11:41:58 -04:00
|
|
|
bool depth_writes = true;
|
|
|
|
|
2021-08-07 18:57:13 -04:00
|
|
|
} m_test_state;
|
|
|
|
|
|
|
|
struct BlendState {
|
|
|
|
void from_register(GsAlpha reg);
|
|
|
|
|
|
|
|
GsAlpha current_register;
|
|
|
|
GsAlpha::BlendMode a = GsAlpha::BlendMode::SOURCE;
|
|
|
|
GsAlpha::BlendMode b = GsAlpha::BlendMode::DEST;
|
|
|
|
GsAlpha::BlendMode c = GsAlpha::BlendMode::SOURCE;
|
|
|
|
GsAlpha::BlendMode d = GsAlpha::BlendMode::DEST;
|
|
|
|
bool alpha_blend_enable = false;
|
|
|
|
u8 fix = 0;
|
|
|
|
|
|
|
|
} m_blend_state;
|
|
|
|
|
|
|
|
// state set through the prim register that requires changing GL stuff.
|
|
|
|
struct PrimGlState {
|
|
|
|
void from_register(GsPrim reg);
|
|
|
|
|
|
|
|
GsPrim current_register;
|
|
|
|
bool gouraud_enable = false;
|
|
|
|
bool texture_enable = false;
|
|
|
|
bool fogging_enable = false;
|
|
|
|
|
|
|
|
bool aa_enable = false;
|
|
|
|
bool use_uv = false; // todo: might not require a gl state change
|
|
|
|
bool ctxt = false; // do they ever use ctxt2?
|
|
|
|
bool fix = false; // what does this even do?
|
2023-02-27 19:51:14 -05:00
|
|
|
u32 ta0 = 0;
|
2021-08-07 18:57:13 -04:00
|
|
|
} m_prim_gl_state;
|
|
|
|
|
2022-02-25 16:53:39 -05:00
|
|
|
static constexpr int TEXTURE_STATE_COUNT = 1;
|
2022-01-06 18:47:20 -05:00
|
|
|
|
2021-08-08 20:46:14 -04:00
|
|
|
struct TextureState {
|
|
|
|
GsTex0 current_register;
|
|
|
|
u32 texture_base_ptr = 0;
|
2021-08-11 19:36:15 -04:00
|
|
|
bool using_mt4hh = false;
|
2021-09-26 11:41:58 -04:00
|
|
|
bool tcc = false;
|
2022-02-25 16:53:39 -05:00
|
|
|
bool decal = false;
|
2021-10-20 19:49:32 -04:00
|
|
|
bool enable_tex_filt = true;
|
2022-01-06 18:47:20 -05:00
|
|
|
|
|
|
|
struct ClampState {
|
|
|
|
void from_register(u64 value) { current_register = value; }
|
|
|
|
u64 current_register = 0b101;
|
|
|
|
bool clamp_s = true;
|
|
|
|
bool clamp_t = true;
|
|
|
|
} m_clamp_state;
|
|
|
|
|
|
|
|
bool used = false;
|
|
|
|
|
2022-02-25 14:44:31 -05:00
|
|
|
bool compatible_with(const TextureState& other) {
|
|
|
|
return current_register == other.current_register &&
|
|
|
|
m_clamp_state.current_register == other.m_clamp_state.current_register &&
|
|
|
|
enable_tex_filt == other.enable_tex_filt;
|
2022-01-07 16:13:19 -05:00
|
|
|
}
|
2022-02-25 14:44:31 -05:00
|
|
|
};
|
2022-01-07 16:13:19 -05:00
|
|
|
|
2022-02-25 14:44:31 -05:00
|
|
|
// vertices will reference these texture states
|
|
|
|
TextureState m_buffered_tex_state[TEXTURE_STATE_COUNT];
|
2023-08-15 21:53:06 -04:00
|
|
|
bool m_buffered_tex_state_currently_bound[TEXTURE_STATE_COUNT] = {0};
|
2022-02-25 14:44:31 -05:00
|
|
|
int m_next_free_tex_state = 0;
|
2022-01-06 18:47:20 -05:00
|
|
|
|
2022-02-25 14:44:31 -05:00
|
|
|
// this texture state mirrors the current GS register.
|
|
|
|
TextureState m_tex_state_from_reg;
|
2022-01-06 18:47:20 -05:00
|
|
|
|
2022-02-25 14:44:31 -05:00
|
|
|
// if this is not -1, then it is the index of a texture state in m_buffered_tex_state that
|
|
|
|
// matches m_tex_state_from_reg.
|
|
|
|
int m_current_tex_state_idx = -1;
|
|
|
|
|
|
|
|
int get_texture_unit_for_current_reg(SharedRenderState* render_state, ScopedProfilerNode& prof);
|
2021-08-08 20:46:14 -04:00
|
|
|
|
2021-08-07 18:57:13 -04:00
|
|
|
// state set through the prim/rgbaq register that doesn't require changing GL stuff
|
2021-08-07 21:16:44 -04:00
|
|
|
struct PrimBuildState {
|
2021-08-07 18:57:13 -04:00
|
|
|
GsPrim::Kind kind = GsPrim::Kind::PRIM_7;
|
2021-11-13 20:44:17 -05:00
|
|
|
math::Vector<u8, 4> rgba_reg = math::Vector<u8, 4>{0, 0, 0, 0};
|
2021-08-08 20:46:14 -04:00
|
|
|
math::Vector<float, 2> st_reg;
|
2021-08-07 18:57:13 -04:00
|
|
|
|
|
|
|
std::array<math::Vector<u8, 4>, 3> building_rgba;
|
2022-02-25 23:25:49 -05:00
|
|
|
std::array<math::Vector<u32, 4>, 3> building_vert;
|
2021-10-10 20:07:03 -04:00
|
|
|
std::array<math::Vector<float, 3>, 3> building_stq;
|
2021-08-07 18:57:13 -04:00
|
|
|
int building_idx = 0;
|
2021-08-07 21:16:44 -04:00
|
|
|
int tri_strip_startup = 0;
|
2021-08-07 18:57:13 -04:00
|
|
|
|
2021-10-10 20:07:03 -04:00
|
|
|
float Q = 1.0;
|
2021-08-07 18:57:13 -04:00
|
|
|
} m_prim_building;
|
|
|
|
|
2021-12-30 19:38:18 -05:00
|
|
|
struct Vertex {
|
2022-02-25 23:25:49 -05:00
|
|
|
math::Vector<float, 4> xyzf;
|
2021-12-30 19:38:18 -05:00
|
|
|
math::Vector<float, 3> stq;
|
|
|
|
math::Vector<u8, 4> rgba;
|
2022-02-25 16:53:39 -05:00
|
|
|
u8 tex_unit;
|
|
|
|
u8 tcc;
|
|
|
|
u8 decal;
|
2022-02-25 23:25:49 -05:00
|
|
|
u8 fog_enable;
|
2023-02-27 19:51:14 -05:00
|
|
|
u8 use_uv;
|
2023-05-04 18:34:09 -04:00
|
|
|
math::Vector<u8, 11> __pad;
|
|
|
|
// this can be simplified to use gs coords, if needed
|
|
|
|
math::Vector<float, 4> scissor;
|
2021-12-30 19:38:18 -05:00
|
|
|
};
|
2022-01-06 18:47:20 -05:00
|
|
|
static_assert(sizeof(Vertex) == 64);
|
2022-02-25 16:53:39 -05:00
|
|
|
static_assert(offsetof(Vertex, tex_unit) == 32);
|
2021-12-30 19:38:18 -05:00
|
|
|
|
2021-08-07 18:57:13 -04:00
|
|
|
struct PrimitiveBuffer {
|
|
|
|
PrimitiveBuffer(int max_triangles);
|
2021-12-30 19:38:18 -05:00
|
|
|
std::vector<Vertex> vertices;
|
2021-08-07 18:57:13 -04:00
|
|
|
int vert_count = 0;
|
|
|
|
int max_verts = 0;
|
2023-02-27 19:51:14 -05:00
|
|
|
float x_off = 0;
|
|
|
|
float y_off = 0;
|
2021-08-07 18:57:13 -04:00
|
|
|
// leave 6 free on the end so we always have room to flush one last primitive.
|
2021-08-10 22:13:34 -04:00
|
|
|
bool is_full() { return max_verts < (vert_count + 18); }
|
2021-08-08 20:46:14 -04:00
|
|
|
void push(const math::Vector<u8, 4>& rgba,
|
2022-02-25 23:25:49 -05:00
|
|
|
const math::Vector<u32, 4>& vert,
|
2022-01-06 18:47:20 -05:00
|
|
|
const math::Vector<float, 3>& stq,
|
2023-05-04 18:34:09 -04:00
|
|
|
const math::Vector<float, 4>& scissor,
|
2022-01-06 18:47:20 -05:00
|
|
|
int unit,
|
2022-02-25 16:53:39 -05:00
|
|
|
bool tcc,
|
2022-02-25 23:25:49 -05:00
|
|
|
bool decal,
|
2023-02-27 19:51:14 -05:00
|
|
|
bool fog_enable,
|
|
|
|
bool use_uv);
|
2021-08-07 18:57:13 -04:00
|
|
|
} m_prim_buffer;
|
|
|
|
|
2023-05-04 18:34:09 -04:00
|
|
|
// the scissor state tends to be shared across buckets, so it is static here
|
|
|
|
static struct ScissorState {
|
|
|
|
u16 scax0 = 0, scay0 = 0;
|
|
|
|
u16 scax1 = 0, scay1 = 0;
|
|
|
|
} m_scissor;
|
|
|
|
// however the toggle for it is per-bucket
|
|
|
|
bool m_scissor_enable = false;
|
|
|
|
|
|
|
|
struct BufferBlitState {
|
|
|
|
// used to keep track of blit progress
|
|
|
|
u8 expect = 0;
|
|
|
|
|
|
|
|
// blit buffer source+dest settings
|
|
|
|
u16 sbp = 0, dbp = 0;
|
|
|
|
u8 sbw = 0, dbw = 0;
|
|
|
|
u8 spsm = 0, dpsm = 0;
|
|
|
|
// transfer pos
|
|
|
|
u16 ssax = 0, dsax = 0;
|
|
|
|
u16 ssay = 0, dsay = 0;
|
|
|
|
// transfer region
|
|
|
|
u16 width = 0, height = 0;
|
|
|
|
// transfer dir
|
|
|
|
u8 pixel_dir = 0;
|
|
|
|
|
|
|
|
// gif IMAGE transfer size
|
|
|
|
u16 qwc = 0;
|
|
|
|
} m_blit_buf_state;
|
|
|
|
|
2021-08-07 18:57:13 -04:00
|
|
|
struct {
|
2021-12-30 19:38:18 -05:00
|
|
|
GLuint vertex_buffer;
|
2021-10-06 19:32:58 -04:00
|
|
|
GLuint vao;
|
2021-08-07 18:57:13 -04:00
|
|
|
u32 vertex_buffer_bytes = 0;
|
2021-12-30 19:38:18 -05:00
|
|
|
u32 vertex_buffer_max_verts = 0;
|
2022-02-24 22:33:10 -05:00
|
|
|
float color_mult = 1.0;
|
2022-03-15 23:12:40 -04:00
|
|
|
float alpha_mult = 1.0;
|
2021-08-07 18:57:13 -04:00
|
|
|
} m_ogl;
|
|
|
|
|
2023-07-14 18:17:54 -04:00
|
|
|
struct {
|
|
|
|
GLint alpha_min, alpha_max;
|
|
|
|
GLint normal_shader_id = -1;
|
|
|
|
} m_uniforms;
|
|
|
|
|
2021-08-29 14:54:16 -04:00
|
|
|
struct {
|
|
|
|
bool disable_texture = false;
|
|
|
|
bool wireframe = false;
|
2021-09-26 11:41:58 -04:00
|
|
|
bool red = false;
|
|
|
|
bool always_draw = false;
|
2021-11-15 20:07:10 -05:00
|
|
|
bool disable_mipmap = true;
|
2021-08-29 14:54:16 -04:00
|
|
|
} m_debug_state;
|
|
|
|
|
2021-11-13 20:44:17 -05:00
|
|
|
struct {
|
|
|
|
int triangles = 0;
|
|
|
|
int draw_calls = 0;
|
|
|
|
|
|
|
|
int flush_from_tex_0 = 0;
|
|
|
|
int flush_from_tex_1 = 0;
|
|
|
|
int flush_from_zbuf = 0;
|
|
|
|
int flush_from_test = 0;
|
2023-02-27 19:51:14 -05:00
|
|
|
int flush_from_ta0 = 0;
|
2021-11-13 20:44:17 -05:00
|
|
|
int flush_from_alpha = 0;
|
|
|
|
int flush_from_clamp = 0;
|
|
|
|
int flush_from_prim = 0;
|
2022-01-06 18:47:20 -05:00
|
|
|
int flush_from_state_exhaust = 0;
|
2021-11-13 20:44:17 -05:00
|
|
|
} m_stats;
|
2021-08-10 21:31:15 -04:00
|
|
|
|
2021-08-07 18:57:13 -04:00
|
|
|
bool m_prim_gl_state_needs_gl_update = true;
|
|
|
|
bool m_test_state_needs_gl_update = true;
|
2023-07-14 18:17:54 -04:00
|
|
|
bool m_test_state_needs_double_draw = false;
|
|
|
|
float m_double_draw_aref = 0;
|
2021-08-07 18:57:13 -04:00
|
|
|
bool m_blend_state_needs_gl_update = true;
|
2021-09-26 11:41:58 -04:00
|
|
|
|
|
|
|
struct SpriteMode {
|
|
|
|
bool do_first_draw = true;
|
|
|
|
} m_sprite_mode;
|
2021-08-07 18:57:13 -04:00
|
|
|
};
|