jak-project/game/graphics/opengl_renderer/DirectRenderer.h

333 lines
10 KiB
C
Raw Normal View History

2021-08-07 18:57:13 -04:00
#pragma once
#include <vector>
#include "common/dma/gs.h"
2021-08-07 18:57:13 -04:00
#include "common/math/Vector.h"
#include "common/util/SmallVector.h"
#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:
DirectRenderer(const std::string& name, int my_id, int batch_size);
void init_shaders(ShaderLibrary& sl) override;
void draw_debug_window() override;
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
virtual void pre_render() {}
virtual void post_render() {}
~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.
*/
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.
*/
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.
*/
void flush_pending(SharedRenderState* render_state, ScopedProfilerNode& prof);
2021-08-07 18:57:13 -04: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;
}
void set_mipmap(bool en) { m_debug_state.disable_mipmap = !en; }
void handle_prim(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
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);
void handle_xyzf2_packed(const u8* data,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void handle_xyz2_packed(const u8* data,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void handle_prim_packed(const u8* data,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void handle_tex0_1_packed(const u8* data);
void handle_uv_packed(const u8* data);
void handle_rgbaq(u64 val);
void handle_xyzf2(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void lookup_textures_again(SharedRenderState* render_state);
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;
}
protected:
virtual void handle_frame(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_scissor(u64 val);
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);
void handle_tex0_1(u64 val);
void handle_tex1_1(u64 val);
void handle_texa(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_xyoffset(u64 val);
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);
void handle_xyzf2_common(u32 x,
u32 y,
u32 z,
u8 f,
SharedRenderState* render_state,
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();
void update_gl_texture(SharedRenderState* render_state, int unit);
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;
bool write_rgb = true;
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?
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;
2021-08-08 20:46:14 -04:00
struct TextureState {
GsTex0 current_register;
u32 texture_base_ptr = 0;
bool using_mt4hh = false;
bool tcc = false;
2022-02-25 16:53:39 -05:00
bool decal = false;
bool enable_tex_filt = true;
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;
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;
}
};
// vertices will reference these texture states
TextureState m_buffered_tex_state[TEXTURE_STATE_COUNT];
bool m_buffered_tex_state_currently_bound[TEXTURE_STATE_COUNT] = {0};
int m_next_free_tex_state = 0;
// this texture state mirrors the current GS register.
TextureState m_tex_state_from_reg;
// 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;
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;
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
float Q = 1.0;
2021-08-07 18:57:13 -04:00
} m_prim_building;
struct Vertex {
2022-02-25 23:25:49 -05:00
math::Vector<float, 4> xyzf;
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;
u8 use_uv;
math::Vector<u8, 11> __pad;
// this can be simplified to use gs coords, if needed
math::Vector<float, 4> scissor;
};
static_assert(sizeof(Vertex) == 64);
2022-02-25 16:53:39 -05:00
static_assert(offsetof(Vertex, tex_unit) == 32);
2021-08-07 18:57:13 -04:00
struct PrimitiveBuffer {
PrimitiveBuffer(int max_triangles);
std::vector<Vertex> vertices;
2021-08-07 18:57:13 -04:00
int vert_count = 0;
int max_verts = 0;
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,
const math::Vector<float, 3>& stq,
const math::Vector<float, 4>& scissor,
int unit,
2022-02-25 16:53:39 -05:00
bool tcc,
2022-02-25 23:25:49 -05:00
bool decal,
bool fog_enable,
bool use_uv);
2021-08-07 18:57:13 -04:00
} m_prim_buffer;
// 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 {
GLuint vertex_buffer;
GLuint vao;
2021-08-07 18:57:13 -04:00
u32 vertex_buffer_bytes = 0;
u32 vertex_buffer_max_verts = 0;
float color_mult = 1.0;
float alpha_mult = 1.0;
2021-08-07 18:57:13 -04:00
} m_ogl;
struct {
GLint alpha_min, alpha_max;
GLint normal_shader_id = -1;
} m_uniforms;
struct {
bool disable_texture = false;
bool wireframe = false;
bool red = false;
bool always_draw = false;
bool disable_mipmap = true;
} m_debug_state;
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;
int flush_from_ta0 = 0;
int flush_from_alpha = 0;
int flush_from_clamp = 0;
int flush_from_prim = 0;
int flush_from_state_exhaust = 0;
} 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;
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;
struct SpriteMode {
bool do_first_draw = true;
} m_sprite_mode;
2021-08-07 18:57:13 -04:00
};