mirror of
https://github.com/open-goal/jak-project.git
synced 2024-11-23 06:09:57 +00:00
tfrag improvements (#970)
* tfrag improvements * cleanup * one last fix * clang
This commit is contained in:
parent
dcbd90a3f3
commit
7292cb5765
@ -44,7 +44,7 @@ void diff_dma_chains(DmaFollower ref, DmaFollower dma) {
|
||||
auto ref_result = ref.read_and_advance();
|
||||
auto dma_result = dma.read_and_advance();
|
||||
|
||||
for (int i = 0; i < ref_result.size_bytes; i++) {
|
||||
for (int i = 0; i < (int)ref_result.size_bytes; i++) {
|
||||
if (ref_result.data[i] != dma_result.data[i]) {
|
||||
fmt::print("Bad data ({} vs {}) at {} into transfer: {} {}\n", ref_result.data[i],
|
||||
dma_result.data[i], i, ref_tag.print(), dma_tag.print());
|
||||
|
@ -95,6 +95,7 @@ set(RUNTIME_SOURCE
|
||||
graphics/opengl_renderer/SkyRenderer.cpp
|
||||
graphics/opengl_renderer/SpriteRenderer.cpp
|
||||
graphics/opengl_renderer/TextureUploadHandler.cpp
|
||||
graphics/opengl_renderer/tfrag/BufferedRenderer.cpp
|
||||
graphics/opengl_renderer/tfrag/program6_cpu.cpp
|
||||
graphics/opengl_renderer/tfrag/tfrag_unpack.cpp
|
||||
graphics/opengl_renderer/tfrag/TFragment.cpp
|
||||
|
@ -71,6 +71,8 @@ void DirectRenderer::draw_debug_window() {
|
||||
ImGui::Checkbox("red", &m_debug_state.red);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("always", &m_debug_state.always_draw);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("no mip", &m_debug_state.disable_mipmap);
|
||||
|
||||
if (m_mode == Mode::SPRITE_CPU) {
|
||||
ImGui::Checkbox("draw1", &m_sprite_mode.do_first_draw);
|
||||
@ -128,6 +130,7 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfil
|
||||
m_test_state_needs_gl_update = false;
|
||||
}
|
||||
|
||||
// I think it's important that this comes last.
|
||||
if (m_texture_state.needs_gl_update) {
|
||||
update_gl_texture(render_state);
|
||||
m_texture_state.needs_gl_update = false;
|
||||
@ -218,7 +221,10 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfil
|
||||
render_state->shaders[ShaderId::SPRITE_CPU_AFAIL].activate();
|
||||
glDepthMask(GL_FALSE);
|
||||
glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count);
|
||||
if (m_test_state.depth_writes) {
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
m_prim_gl_state_needs_gl_update = true;
|
||||
m_blend_state_needs_gl_update = true;
|
||||
draw_count++;
|
||||
@ -349,7 +355,8 @@ void DirectRenderer::update_gl_texture(SharedRenderState* render_state) {
|
||||
}
|
||||
|
||||
if (m_texture_state.enable_tex_filt) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
m_debug_state.disable_mipmap ? GL_LINEAR : GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
@ -391,8 +398,9 @@ void DirectRenderer::update_gl_blend() {
|
||||
|
||||
void DirectRenderer::update_gl_test() {
|
||||
const auto& state = m_test_state;
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
if (state.zte) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
switch (state.ztst) {
|
||||
case GsTest::ZTest::NEVER:
|
||||
glDepthFunc(GL_NEVER);
|
||||
@ -769,13 +777,14 @@ void DirectRenderer::handle_zbuf1(u64 val,
|
||||
assert(x.psm() == TextureFormat::PSMZ24);
|
||||
assert(x.zbp() == 448);
|
||||
|
||||
bool write = x.zmsk();
|
||||
bool write = !x.zmsk();
|
||||
// assert(write);
|
||||
|
||||
if (write != m_test_state.depth_writes) {
|
||||
m_stats.flush_from_zbuf++;
|
||||
flush_pending(render_state, prof);
|
||||
m_test_state_needs_gl_update = true;
|
||||
m_prim_gl_state_needs_gl_update = true;
|
||||
m_test_state.depth_writes = write;
|
||||
}
|
||||
}
|
||||
@ -1042,10 +1051,8 @@ void DirectRenderer::TestState::from_register(GsTest reg) {
|
||||
}
|
||||
|
||||
zte = reg.zte();
|
||||
if (zte) {
|
||||
ztst = reg.ztest();
|
||||
}
|
||||
}
|
||||
|
||||
void DirectRenderer::BlendState::from_register(GsAlpha reg) {
|
||||
current_register = reg;
|
||||
|
@ -207,6 +207,7 @@ class DirectRenderer : public BucketRenderer {
|
||||
bool wireframe = false;
|
||||
bool red = false;
|
||||
bool always_draw = false;
|
||||
bool disable_mipmap = true;
|
||||
} m_debug_state;
|
||||
|
||||
struct {
|
||||
|
@ -73,4 +73,7 @@ ShaderLibrary::ShaderLibrary() {
|
||||
at(ShaderId::SPRITE_CPU_AFAIL) = {"sprite_cpu_afail"};
|
||||
at(ShaderId::SKY) = {"sky"};
|
||||
at(ShaderId::SKY_BLEND) = {"sky_blend"};
|
||||
at(ShaderId::DEBUG_BUFFERED) = {"debug_buffered"};
|
||||
at(ShaderId::BUFFERED_TCC0) = {"buffered_tcc0"};
|
||||
at(ShaderId::BUFFERED_TCC1) = {"buffered_tcc1"};
|
||||
}
|
@ -29,8 +29,11 @@ enum class ShaderId {
|
||||
DEBUG_RED = 4,
|
||||
SPRITE_CPU = 5,
|
||||
SPRITE_CPU_AFAIL = 6,
|
||||
SKY,
|
||||
SKY_BLEND,
|
||||
SKY = 7,
|
||||
SKY_BLEND = 8,
|
||||
DEBUG_BUFFERED = 9,
|
||||
BUFFERED_TCC0 = 10,
|
||||
BUFFERED_TCC1 = 11,
|
||||
MAX_SHADERS
|
||||
};
|
||||
|
||||
|
@ -160,7 +160,9 @@ void SpriteRenderer::render_2d_group0(DmaFollower& dma,
|
||||
auto run = dma.read_and_advance();
|
||||
assert(run.vifcode0().kind == VifCode::Kind::NOP);
|
||||
assert(run.vifcode1().kind == VifCode::Kind::MSCAL);
|
||||
assert(run.vifcode1().immediate == SpriteProgMem::Sprites2dGrp0);
|
||||
|
||||
// HACK: this renderers 3D sprites with the 2D renderer. amazingly, it almost works.
|
||||
// assert(run.vifcode1().immediate == SpriteProgMem::Sprites2dGrp0);
|
||||
if (m_enabled) {
|
||||
do_2d_group0_block_cpu(sprite_count, render_state, prof);
|
||||
}
|
||||
@ -733,7 +735,7 @@ void SpriteRenderer::do_2d_group0_block_cpu(u32 count,
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
// ilw.y vi08, 1(vi02) | nop vi08 = matrix
|
||||
u32 offset_selector = m_vec_data_2d[sprite_idx].matrix();
|
||||
assert(offset_selector == 0 || offset_selector == 1);
|
||||
// assert(offset_selector == 0 || offset_selector == 1);
|
||||
// moved this out of the loop.
|
||||
// lq.xyzw vf25, 900(vi00) | nop vf25 = cam_mat
|
||||
// lq.xyzw vf26, 901(vi00) | nop
|
||||
|
18
game/graphics/opengl_renderer/shaders/buffered_tcc0.frag
Normal file
18
game/graphics/opengl_renderer/shaders/buffered_tcc0.frag
Normal file
@ -0,0 +1,18 @@
|
||||
#version 330 core
|
||||
|
||||
out vec4 color;
|
||||
|
||||
in vec4 fragment_color;
|
||||
in vec3 tex_coord;
|
||||
uniform sampler2D tex_T0;
|
||||
uniform float alpha_reject;
|
||||
|
||||
void main() {
|
||||
vec4 T0 = texture(tex_T0, tex_coord.xy / tex_coord.z);
|
||||
//vec4 T0 = textureProj(tex_T0, vec3(tex_coord.xy, 1.0));
|
||||
T0.w = 1.0;
|
||||
color = fragment_color * T0 * 2.0;
|
||||
if (color.a <= alpha_reject) {
|
||||
discard;
|
||||
}
|
||||
}
|
14
game/graphics/opengl_renderer/shaders/buffered_tcc0.vert
Normal file
14
game/graphics/opengl_renderer/shaders/buffered_tcc0.vert
Normal file
@ -0,0 +1,14 @@
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec3 position_in;
|
||||
layout (location = 1) in vec4 rgba_in;
|
||||
layout (location = 2) in vec3 tex_coord_in;
|
||||
|
||||
out vec4 fragment_color;
|
||||
out vec3 tex_coord;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4((position_in.x - 0.5) * 16. , -(position_in.y - 0.5) * 32, position_in.z, 1.0);
|
||||
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.a * 2);
|
||||
tex_coord = tex_coord_in;
|
||||
}
|
17
game/graphics/opengl_renderer/shaders/buffered_tcc1.frag
Normal file
17
game/graphics/opengl_renderer/shaders/buffered_tcc1.frag
Normal file
@ -0,0 +1,17 @@
|
||||
#version 330 core
|
||||
|
||||
out vec4 color;
|
||||
|
||||
in vec4 fragment_color;
|
||||
in vec3 tex_coord;
|
||||
uniform sampler2D tex_T0;
|
||||
uniform float alpha_reject;
|
||||
|
||||
void main() {
|
||||
//vec4 T0 = texture(tex_T0, tex_coord);
|
||||
vec4 T0 = texture(tex_T0, tex_coord.xy / tex_coord.z);
|
||||
color = fragment_color * T0 * 2.0;
|
||||
if (color.a <= alpha_reject) {
|
||||
discard;
|
||||
}
|
||||
}
|
14
game/graphics/opengl_renderer/shaders/buffered_tcc1.vert
Normal file
14
game/graphics/opengl_renderer/shaders/buffered_tcc1.vert
Normal file
@ -0,0 +1,14 @@
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec3 position_in;
|
||||
layout (location = 1) in vec4 rgba_in;
|
||||
layout (location = 2) in vec3 tex_coord_in;
|
||||
|
||||
out vec4 fragment_color;
|
||||
out vec3 tex_coord;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z, 1.0);
|
||||
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w * 2.);
|
||||
tex_coord = tex_coord_in;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#version 330 core
|
||||
|
||||
out vec4 color;
|
||||
|
||||
in vec4 fragment_color;
|
||||
|
||||
void main() {
|
||||
color = fragment_color;
|
||||
}
|
17
game/graphics/opengl_renderer/shaders/debug_buffered.vert
Normal file
17
game/graphics/opengl_renderer/shaders/debug_buffered.vert
Normal file
@ -0,0 +1,17 @@
|
||||
// Shader for debugging the buffered renderer.
|
||||
// no texture
|
||||
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec3 position_in;
|
||||
layout (location = 1) in vec4 rgba_in;
|
||||
layout (location = 2) in vec3 stq_in;
|
||||
|
||||
out vec4 fragment_color;
|
||||
|
||||
void main() {
|
||||
// Note: position.y is multiplied by 32 instead of 16 to undo the half-height for interlacing stuff.
|
||||
gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z, 1.0);
|
||||
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w + 0.5);
|
||||
//fragment_color = vec4(1.0, 0, 0, 0.7);
|
||||
}
|
732
game/graphics/opengl_renderer/tfrag/BufferedRenderer.cpp
Normal file
732
game/graphics/opengl_renderer/tfrag/BufferedRenderer.cpp
Normal file
@ -0,0 +1,732 @@
|
||||
#include "BufferedRenderer.h"
|
||||
#include "common/dma/gs.h"
|
||||
#include "third-party/imgui/imgui.h"
|
||||
#include "game/graphics/pipelines/opengl.h"
|
||||
|
||||
namespace BufferedRenderer {
|
||||
|
||||
std::string DrawMode::to_string() const {
|
||||
std::string result;
|
||||
result += fmt::format(" depth-write: {}\n", get_depth_write_enable());
|
||||
result += fmt::format(" depth-test: ");
|
||||
switch (get_depth_test()) {
|
||||
case GsTest::ZTest::NEVER:
|
||||
result += "never\n";
|
||||
break;
|
||||
case GsTest::ZTest::GEQUAL:
|
||||
result += "gequal\n";
|
||||
break;
|
||||
case GsTest::ZTest::ALWAYS:
|
||||
result += "always\n";
|
||||
break;
|
||||
case GsTest::ZTest::GREATER:
|
||||
result += "greater\n";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
result += fmt::format(" alpha: ");
|
||||
switch (get_alpha_blend()) {
|
||||
case AlphaBlend::SRC_0_SRC_DST:
|
||||
result += "src, 0, src, dst\n";
|
||||
break;
|
||||
case AlphaBlend::SRC_DST_SRC_DST:
|
||||
result += "src, dst, src, dst\n";
|
||||
break;
|
||||
case AlphaBlend::DISABLED:
|
||||
result += "disabled\n";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
result += fmt::format(" clamp: {}\n", get_clamp_enable());
|
||||
result += fmt::format(" filt: {}\n", get_filt_enable());
|
||||
result += fmt::format(" tcc: {}\n", get_tcc_enable());
|
||||
result += fmt::format(" aref: {}\n", get_aref());
|
||||
result += fmt::format(" ate: {}\n", get_at_enable());
|
||||
result += fmt::format(" atst: ");
|
||||
switch (get_alpha_test()) {
|
||||
case AlphaTest::ALWAYS:
|
||||
result += "always\n";
|
||||
break;
|
||||
case AlphaTest::GEQUAL:
|
||||
result += "gequal\n";
|
||||
break;
|
||||
case AlphaTest::NEVER:
|
||||
result += "never\n";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
result += fmt::format(" zte: {}\n", get_zt_enable());
|
||||
result += fmt::format(" abe: {}\n", get_ab_enable());
|
||||
result += fmt::format(" afail: ");
|
||||
switch (get_alpha_fail()) {
|
||||
case GsTest::AlphaFail::KEEP:
|
||||
result += "keep\n";
|
||||
break;
|
||||
case GsTest::AlphaFail::FB_ONLY:
|
||||
result += "fb-only\n";
|
||||
break;
|
||||
case GsTest::AlphaFail::RGB_ONLY:
|
||||
result += "rgb-only\n";
|
||||
break;
|
||||
case GsTest::AlphaFail::ZB_ONLY:
|
||||
result += "zb-only\n";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Renderer::Renderer(BucketId my_id) : m_my_id(my_id) {
|
||||
glGenBuffers(1, &m_ogl.vertex_buffer);
|
||||
glGenBuffers(1, &m_ogl.index_buffer);
|
||||
glGenVertexArrays(1, &m_ogl.vao);
|
||||
|
||||
// these are some big buffers
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer);
|
||||
m_ogl.vertex_buffer_size = MAX_VERTS;
|
||||
glBufferData(GL_ARRAY_BUFFER, m_ogl.vertex_buffer_size * sizeof(Vertex), nullptr,
|
||||
GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer);
|
||||
m_ogl.index_buffer_size = MAX_VERTS * 3;
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer_size * sizeof(u32), nullptr,
|
||||
GL_DYNAMIC_DRAW);
|
||||
}
|
||||
|
||||
Renderer::~Renderer() {
|
||||
glDeleteBuffers(1, &m_ogl.vertex_buffer);
|
||||
glDeleteBuffers(1, &m_ogl.index_buffer);
|
||||
glDeleteVertexArrays(1, &m_ogl.vao);
|
||||
}
|
||||
|
||||
void Renderer::render_list(const DrawList& list,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
const std::vector<Vertex>& vertices) {
|
||||
// first, load primitive buffer
|
||||
glBindVertexArray(m_ogl.vao);
|
||||
u32 vert_count = std::min((int)vertices.size(), (int)m_ogl.vertex_buffer_size);
|
||||
if (vertices.size() > m_ogl.vertex_buffer_size) {
|
||||
fmt::print("TOO MANY VERTICES: {} / {}\n", vertices.size(), m_ogl.vertex_buffer_size);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
glEnableVertexAttribArray(3);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, vert_count * sizeof(Vertex), vertices.data());
|
||||
|
||||
glVertexAttribPointer(0, // location 0 in the shader
|
||||
3, // 3 values per vert
|
||||
GL_UNSIGNED_INT, // u32's
|
||||
GL_TRUE, // normalized
|
||||
sizeof(Vertex), // stride
|
||||
(void*)offsetof(Vertex, xyz) // offset (0)
|
||||
);
|
||||
|
||||
glVertexAttribPointer(1, // location 1 in the shader
|
||||
4, // 4 values per vert
|
||||
GL_UNSIGNED_BYTE, // u8's
|
||||
GL_TRUE, // normalized
|
||||
sizeof(Vertex), // stride
|
||||
(void*)offsetof(Vertex, rgba) // offset (0)
|
||||
);
|
||||
|
||||
glVertexAttribPointer(2, // location 2 in the shader
|
||||
3, // 3 values per vert
|
||||
GL_FLOAT, // u32's
|
||||
GL_FALSE, // normalized
|
||||
sizeof(Vertex), // stride
|
||||
(void*)offsetof(Vertex, st) // offset (0)
|
||||
);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
for (auto& group : list.groups) {
|
||||
if (group.tbp != UINT16_MAX) {
|
||||
render_group(group, render_state, prof, vertices);
|
||||
}
|
||||
}
|
||||
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
glDisableVertexAttribArray(2);
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void Renderer::setup_opengl_excluding_textures(SharedRenderState* render_state, DrawMode mode) {
|
||||
if (mode.get_depth_write_enable()) {
|
||||
glDepthMask(GL_TRUE);
|
||||
} else {
|
||||
glDepthMask(GL_FALSE);
|
||||
}
|
||||
|
||||
if (mode.get_zt_enable()) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
switch (mode.get_depth_test()) {
|
||||
case GsTest::ZTest::NEVER:
|
||||
glDepthFunc(GL_NEVER);
|
||||
break;
|
||||
case GsTest::ZTest::ALWAYS:
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
break;
|
||||
case GsTest::ZTest::GEQUAL:
|
||||
glDepthFunc(GL_GEQUAL);
|
||||
break;
|
||||
case GsTest::ZTest::GREATER:
|
||||
glDepthFunc(GL_GREATER);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
} else {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
if (mode.get_ab_enable() && mode.get_alpha_blend() != DrawMode::AlphaBlend::DISABLED) {
|
||||
glEnable(GL_BLEND);
|
||||
switch (mode.get_alpha_blend()) {
|
||||
case DrawMode::AlphaBlend::SRC_DST_SRC_DST:
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
break;
|
||||
case DrawMode::AlphaBlend::SRC_0_SRC_DST:
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode.get_clamp_enable()) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
}
|
||||
|
||||
if (mode.get_filt_enable()) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
float alpha_reject = 0.;
|
||||
if (mode.get_at_enable()) {
|
||||
switch (mode.get_alpha_test()) {
|
||||
case DrawMode::AlphaTest::ALWAYS:
|
||||
break;
|
||||
case DrawMode::AlphaTest::GEQUAL:
|
||||
alpha_reject = mode.get_aref() / 127.f;
|
||||
break;
|
||||
case DrawMode::AlphaTest::NEVER:
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// todo check afail
|
||||
|
||||
if (mode.get_tcc_enable()) {
|
||||
render_state->shaders[ShaderId::BUFFERED_TCC1].activate();
|
||||
glUniform1f(
|
||||
glGetUniformLocation(render_state->shaders[ShaderId::BUFFERED_TCC1].id(), "alpha_reject"),
|
||||
alpha_reject);
|
||||
glUniform1i(glGetUniformLocation(render_state->shaders[ShaderId::BUFFERED_TCC1].id(), "T0"), 0);
|
||||
} else {
|
||||
render_state->shaders[ShaderId::BUFFERED_TCC0].activate();
|
||||
glUniform1f(
|
||||
glGetUniformLocation(render_state->shaders[ShaderId::BUFFERED_TCC0].id(), "alpha_reject"),
|
||||
alpha_reject);
|
||||
glUniform1i(glGetUniformLocation(render_state->shaders[ShaderId::BUFFERED_TCC0].id(), "T0"), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::render_group(const DrawGroup& group,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
const std::vector<Vertex>& /*vertices*/) {
|
||||
TextureRecord* tex = nullptr;
|
||||
|
||||
tex = render_state->texture_pool->lookup(group.tbp);
|
||||
|
||||
if (!tex) {
|
||||
fmt::print("Failed to find texture at {}, using random\n", group.tbp);
|
||||
tex = render_state->texture_pool->get_random_texture();
|
||||
}
|
||||
assert(tex);
|
||||
|
||||
// first: do we need to load the texture?
|
||||
if (!tex->on_gpu) {
|
||||
render_state->texture_pool->upload_to_gpu(tex);
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->gpu_texture);
|
||||
|
||||
for (auto& draw : group.draws) {
|
||||
if (draw.mode.is_valid()) {
|
||||
m_stats.draw_calls++;
|
||||
prof.add_draw_call();
|
||||
prof.add_tri(draw.triangles.size());
|
||||
render_state->shaders[ShaderId::DEBUG_BUFFERED].activate();
|
||||
setup_opengl_excluding_textures(render_state, draw.mode);
|
||||
// check for overflows.
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer);
|
||||
if (draw.triangles.size() * 3 > m_ogl.index_buffer_size) {
|
||||
fmt::format("TOO MANY TRIS: {}/{}\n", draw.triangles.size() * 3, m_ogl.index_buffer_size);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, draw.triangles.size() * sizeof(u32) * 3,
|
||||
draw.triangles.data());
|
||||
glDrawElements(GL_TRIANGLES, draw.triangles.size() * 3, GL_UNSIGNED_INT, (void*)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::draw_debug_window() {
|
||||
// todo
|
||||
ImGui::Text("draws: %d", m_stats.draw_calls);
|
||||
}
|
||||
|
||||
void Renderer::clear_stats() {
|
||||
m_stats = {};
|
||||
}
|
||||
|
||||
Builder::Builder(BucketId my_id) : m_my_id(my_id), m_renderer(my_id) {}
|
||||
|
||||
void Builder::add_gif_data_sized(const void* data, u32 expected_size) {
|
||||
if (expected_size != add_gif_data(data)) {
|
||||
assert(false); // todo, might be too strict due to alignment crap
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::flush(SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
||||
m_renderer.render_list(m_list, render_state, prof, m_vertices);
|
||||
m_list.clear();
|
||||
m_vertices.clear();
|
||||
m_cache = {};
|
||||
}
|
||||
|
||||
void Builder::draw_debug_window() {
|
||||
ImGui::Text("Builder: %d tri, %d vert", m_stats.m_tri, m_stats.m_dvert);
|
||||
|
||||
ImGui::Text("Renderer:");
|
||||
ImGui::Separator();
|
||||
m_renderer.draw_debug_window();
|
||||
}
|
||||
|
||||
void Builder::reset_state() {
|
||||
m_current_mode.as_int() = 0;
|
||||
m_stats = {};
|
||||
m_renderer.clear_stats();
|
||||
m_vertex_queue = {};
|
||||
m_current_mode.enable_depth_write();
|
||||
m_current_mode.enable_ab();
|
||||
m_current_mode.enable_at();
|
||||
m_current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST);
|
||||
}
|
||||
|
||||
u32 Builder::add_gif_data(const void* data_in) {
|
||||
bool eop = false;
|
||||
auto* data = (const u8*)data_in;
|
||||
|
||||
u32 offset = 0;
|
||||
while (!eop) {
|
||||
GifTag tag(data + offset);
|
||||
offset += 16;
|
||||
|
||||
// unpack registers.
|
||||
// faster to do it once outside of the nloop loop.
|
||||
GifTag::RegisterDescriptor reg_desc[16];
|
||||
u32 nreg = tag.nreg();
|
||||
for (u32 i = 0; i < nreg; i++) {
|
||||
reg_desc[i] = tag.reg(i);
|
||||
}
|
||||
|
||||
auto format = tag.flg();
|
||||
if (format == GifTag::Format::PACKED) {
|
||||
if (tag.pre()) {
|
||||
handle_prim(tag.prim());
|
||||
}
|
||||
for (u32 loop = 0; loop < tag.nloop(); loop++) {
|
||||
for (u32 reg = 0; reg < nreg; reg++) {
|
||||
switch (reg_desc[reg]) {
|
||||
case GifTag::RegisterDescriptor::AD:
|
||||
handle_ad(data + offset);
|
||||
break;
|
||||
case GifTag::RegisterDescriptor::ST:
|
||||
handle_st_packed(data + offset);
|
||||
break;
|
||||
case GifTag::RegisterDescriptor::RGBAQ:
|
||||
handle_rgbaq_packed(data + offset);
|
||||
break;
|
||||
case GifTag::RegisterDescriptor::XYZF2:
|
||||
handle_xyzf2_packed(data + offset);
|
||||
break;
|
||||
// case GifTag::RegisterDescriptor::PRIM:
|
||||
// handle_prim_packed(data + offset, render_state, prof);
|
||||
// break;
|
||||
// case GifTag::RegisterDescriptor::TEX0_1:
|
||||
// handle_tex0_1_packed(data + offset, render_state, prof);
|
||||
// break;
|
||||
default:
|
||||
fmt::print("Register {} is not supported in packed mode of BufferedRenderer\n",
|
||||
reg_descriptor_name(reg_desc[reg]));
|
||||
assert(false);
|
||||
}
|
||||
offset += 16; // PACKED = quadwords
|
||||
}
|
||||
}
|
||||
} else if (format == GifTag::Format::REGLIST) {
|
||||
for (u32 loop = 0; loop < tag.nloop(); loop++) {
|
||||
for (u32 reg = 0; reg < nreg; reg++) {
|
||||
u64 register_data;
|
||||
memcpy(®ister_data, data + offset, 8);
|
||||
// fmt::print("loop: {} reg: {} {}\n", loop, reg,
|
||||
// reg_descriptor_name(reg_desc[reg]));
|
||||
switch (reg_desc[reg]) {
|
||||
// case GifTag::RegisterDescriptor::PRIM:
|
||||
// handle_prim(register_data, render_state, prof);
|
||||
// break;
|
||||
// case GifTag::RegisterDescriptor::RGBAQ:
|
||||
// handle_rgbaq(register_data);
|
||||
// break;
|
||||
// case GifTag::RegisterDescriptor::XYZF2:
|
||||
// handle_xyzf2(register_data, render_state, prof);
|
||||
// break;
|
||||
default:
|
||||
fmt::print("Register {} is not supported in reglist mode of BufferedRenderer\n",
|
||||
reg_descriptor_name(reg_desc[reg]));
|
||||
assert(false);
|
||||
}
|
||||
offset += 8; // PACKED = quadwords
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert(false); // format not packed or reglist.
|
||||
}
|
||||
|
||||
eop = tag.eop();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
void Builder::handle_ad(const u8* data) {
|
||||
u64 value;
|
||||
GsRegisterAddress addr;
|
||||
memcpy(&value, data, sizeof(u64));
|
||||
memcpy(&addr, data + 8, sizeof(GsRegisterAddress));
|
||||
|
||||
switch (addr) {
|
||||
// case GsRegisterAddress::ZBUF_1:
|
||||
// handle_zbuf1(value, render_state, prof);
|
||||
// break;
|
||||
case GsRegisterAddress::TEST_1:
|
||||
handle_test1(value);
|
||||
break;
|
||||
case GsRegisterAddress::ALPHA_1:
|
||||
handle_alpha1(value);
|
||||
break;
|
||||
// case GsRegisterAddress::PABE:
|
||||
// handle_pabe(value);
|
||||
break;
|
||||
case GsRegisterAddress::CLAMP_1:
|
||||
handle_clamp1(value);
|
||||
break;
|
||||
// case GsRegisterAddress::PRIM:
|
||||
// handle_prim(value, render_state, prof);
|
||||
// break;
|
||||
//
|
||||
case GsRegisterAddress::TEX1_1:
|
||||
handle_tex1_1(value);
|
||||
break;
|
||||
// case GsRegisterAddress::TEXA:
|
||||
// handle_texa(value);
|
||||
// break;
|
||||
// case GsRegisterAddress::TEXCLUT:
|
||||
// // TODO
|
||||
// // the only thing the direct renderer does with texture is font, which does no tricks
|
||||
// with
|
||||
// // CLUT. The texture upload process will do all of the lookups with the default CLUT.
|
||||
// // So we'll just assume that the TEXCLUT is set properly and ignore this.
|
||||
// break;
|
||||
// case GsRegisterAddress::FOGCOL:
|
||||
// // TODO
|
||||
// break;
|
||||
case GsRegisterAddress::TEX0_1:
|
||||
handle_tex0_1(value);
|
||||
break;
|
||||
case GsRegisterAddress::MIPTBP1_1:
|
||||
case GsRegisterAddress::MIPTBP2_1:
|
||||
// this has the address of different mip levels, we can just ignore it.
|
||||
break;
|
||||
// case GsRegisterAddress::TEXFLUSH:
|
||||
// break;
|
||||
default:
|
||||
fmt::print("Address {} is not supported in ad of BufferedRenderer\n",
|
||||
register_address_name(addr));
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::handle_test1(u64 val) {
|
||||
// ate, atst, aref, afail, date, datm, zte, ztest
|
||||
GsTest test(val);
|
||||
|
||||
// ATE
|
||||
m_current_mode.set_at(test.alpha_test_enable());
|
||||
|
||||
// ATST
|
||||
switch (test.alpha_test()) {
|
||||
case GsTest::AlphaTest::ALWAYS:
|
||||
m_current_mode.set_alpha_test(DrawMode::AlphaTest::ALWAYS);
|
||||
break;
|
||||
case GsTest::AlphaTest::GEQUAL:
|
||||
m_current_mode.set_alpha_test(DrawMode::AlphaTest::GEQUAL);
|
||||
break;
|
||||
case GsTest::AlphaTest::NEVER:
|
||||
m_current_mode.set_alpha_test(DrawMode::AlphaTest::NEVER);
|
||||
break;
|
||||
default:
|
||||
fmt::print("Alpha test: {} not supported\n", (int)test.alpha_test());
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// AREF
|
||||
m_current_mode.set_aref(test.aref());
|
||||
|
||||
// AFAIL
|
||||
m_current_mode.set_alpha_fail(test.afail());
|
||||
|
||||
// DATE
|
||||
assert(test.date() == false);
|
||||
|
||||
// DATM
|
||||
// who cares, if date is off
|
||||
|
||||
// ZTE
|
||||
m_current_mode.set_zt(test.zte());
|
||||
|
||||
// ZTST
|
||||
m_current_mode.set_depth_test(test.ztest());
|
||||
}
|
||||
|
||||
void Builder::handle_tex0_1(u64 val) {
|
||||
GsTex0 reg(val);
|
||||
|
||||
// TBP0
|
||||
m_current_tbp = reg.tbp0();
|
||||
|
||||
// TBW
|
||||
// assume it's right
|
||||
|
||||
// PSM
|
||||
assert(reg.psm() != GsTex0::PSM::PSMT4HH); // not supported in buffered yet.
|
||||
|
||||
// TW, TH
|
||||
// assume it's right
|
||||
|
||||
// TCC
|
||||
m_current_mode.set_tcc(reg.tcc());
|
||||
|
||||
// TFX
|
||||
assert(reg.tfx() == GsTex0::TextureFunction::MODULATE);
|
||||
|
||||
// CBP, CPSM, CSM
|
||||
// assume it's right
|
||||
}
|
||||
|
||||
void Builder::handle_tex1_1(u64 val) {
|
||||
GsTex1 reg(val);
|
||||
// ignoring these and doing our own thing!
|
||||
// just need to pick between filtering and not filtering.
|
||||
m_current_mode.set_filt_enable(reg.mmag());
|
||||
}
|
||||
|
||||
void Builder::handle_clamp1(u64 val) {
|
||||
// check that we got one of the expected ones
|
||||
if (!(val == 0b101 || val == 0 || val == 1 || val == 0b100)) {
|
||||
fmt::print("clamp: 0x{:x}\n", val);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// this isn't quite right, but I'm hoping it's enough!
|
||||
m_current_mode.set_clamp_enable(val == 0b101);
|
||||
}
|
||||
|
||||
void Builder::handle_alpha1(u64 val) {
|
||||
GsAlpha reg(val);
|
||||
if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && reg.b_mode() == GsAlpha::BlendMode::DEST &&
|
||||
reg.c_mode() == GsAlpha::BlendMode::SOURCE && reg.d_mode() == GsAlpha::BlendMode::DEST) {
|
||||
// (Cs - Cd) * As + Cd
|
||||
// Cs * As + (1 - As) * Cd
|
||||
m_current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST);
|
||||
|
||||
} else if (reg.a_mode() == GsAlpha::BlendMode::SOURCE &&
|
||||
reg.b_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED &&
|
||||
reg.c_mode() == GsAlpha::BlendMode::SOURCE &&
|
||||
reg.d_mode() == GsAlpha::BlendMode::DEST) {
|
||||
// (Cs - 0) * As + Cd
|
||||
// Cs * As + (1) * CD
|
||||
m_current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_SRC_DST);
|
||||
} else {
|
||||
// unsupported blend: a 0 b 2 c 2 d 1
|
||||
fmt::print("unsupported blend: a {} b {} c {} d {}\n", (int)reg.a_mode(), (int)reg.b_mode(),
|
||||
(int)reg.c_mode(), (int)reg.d_mode());
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::handle_prim(u64 val) {
|
||||
GsPrim prim(val);
|
||||
|
||||
// PRIM
|
||||
m_prim_kind = prim.kind();
|
||||
|
||||
// IIP
|
||||
assert(prim.gouraud());
|
||||
|
||||
// TME
|
||||
assert(prim.tme());
|
||||
|
||||
// FGE
|
||||
// TODO fog
|
||||
|
||||
// ABE
|
||||
m_current_mode.set_ab(prim.abe());
|
||||
|
||||
// AA1
|
||||
assert(!prim.aa1());
|
||||
|
||||
// FST
|
||||
assert(!prim.fst());
|
||||
|
||||
// CTXT
|
||||
assert(!prim.ctxt());
|
||||
|
||||
// FIX
|
||||
assert(!prim.fix());
|
||||
|
||||
if (m_vertex_queue.startup) {
|
||||
m_vertex_queue.startup = 0;
|
||||
m_vertex_queue.idx = 0;
|
||||
} else {
|
||||
// assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::handle_st_packed(const u8* data) {
|
||||
memcpy(m_st_pending_q, data, 3 * sizeof(float));
|
||||
}
|
||||
|
||||
void Builder::handle_rgbaq_packed(const u8* data) {
|
||||
m_q = m_st_pending_q[2];
|
||||
// memcpy(m_rgba.data(), data, 4);
|
||||
m_rgba[0] = data[0];
|
||||
m_rgba[1] = data[4];
|
||||
m_rgba[2] = data[8];
|
||||
m_rgba[3] = data[12];
|
||||
}
|
||||
|
||||
void Builder::handle_xyzf2_packed(const u8* data) {
|
||||
u32 x, y;
|
||||
memcpy(&x, data, 4);
|
||||
memcpy(&y, data + 4, 4);
|
||||
|
||||
u64 upper;
|
||||
memcpy(&upper, data + 8, 8);
|
||||
u32 z = (upper >> 4) & 0xffffff;
|
||||
|
||||
u8 f = (upper >> 36);
|
||||
bool adc = upper & (1ull << 47);
|
||||
handle_xyzf2_common(x, y, z, f, !adc);
|
||||
}
|
||||
|
||||
void Builder::handle_xyzf2_common(u32 x, u32 y, u32 z, u8 /*f*/, bool advance) {
|
||||
// first, create a vertex:
|
||||
u32 new_vertex = create_vertex_now(x, y, z);
|
||||
|
||||
// next, add that vertex. This will inform us if we actually draw a prim or not
|
||||
bool new_prim = false;
|
||||
switch (m_prim_kind) {
|
||||
case GsPrim::Kind::TRI_STRIP:
|
||||
new_prim = handle_tri_strip_add(new_vertex, advance);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (new_prim) {
|
||||
// todo, winding order?
|
||||
add_prim_now({m_vertex_queue.verts[0], m_vertex_queue.verts[1], m_vertex_queue.verts[2]});
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::add_prim_now(Triangle tri) {
|
||||
if (m_cache.last_tbp == m_current_tbp && m_cache.last_mode == m_current_mode.as_int()) {
|
||||
m_cache.draw->triangles.push_back(tri);
|
||||
} else {
|
||||
auto group = m_list.get_group_for_tbp(m_current_tbp);
|
||||
assert(group);
|
||||
// todo flush and stats
|
||||
|
||||
auto draw = group->get_draw_for_mode(m_current_mode);
|
||||
assert(draw);
|
||||
// todo flush and stats
|
||||
draw->triangles.push_back(tri);
|
||||
m_cache.last_mode = m_current_mode.as_int();
|
||||
m_cache.last_tbp = m_current_tbp;
|
||||
m_cache.draw = draw;
|
||||
}
|
||||
|
||||
m_stats.m_tri++;
|
||||
}
|
||||
|
||||
u32 Builder::create_vertex_now(u32 x, u32 y, u32 z) {
|
||||
m_stats.m_dvert++;
|
||||
u32 idx = m_vertices.size();
|
||||
m_vertices.emplace_back();
|
||||
auto& vert = m_vertices.back();
|
||||
vert.xyz = math::Vector<u32, 3>(x << 16, y << 16, z << 8);
|
||||
vert.rgba = m_rgba;
|
||||
vert.st = math::Vector<float, 2>(m_st_pending_q[0], m_st_pending_q[1]);
|
||||
vert.q = m_q;
|
||||
return idx;
|
||||
}
|
||||
|
||||
bool Builder::handle_tri_strip_add(u32 new_vertex, bool advance) {
|
||||
m_vertex_queue.verts[m_vertex_queue.idx] = new_vertex;
|
||||
m_vertex_queue.idx++;
|
||||
|
||||
// wrap the index
|
||||
if (m_vertex_queue.idx == 3) {
|
||||
m_vertex_queue.idx = 0;
|
||||
}
|
||||
|
||||
// bump the startup
|
||||
if (m_vertex_queue.startup < 3) {
|
||||
m_vertex_queue.startup++;
|
||||
}
|
||||
|
||||
if (m_vertex_queue.startup >= 3) {
|
||||
if (advance) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace BufferedRenderer
|
347
game/graphics/opengl_renderer/tfrag/BufferedRenderer.h
Normal file
347
game/graphics/opengl_renderer/tfrag/BufferedRenderer.h
Normal file
@ -0,0 +1,347 @@
|
||||
#pragma once
|
||||
#include "common/math/Vector.h"
|
||||
#include "common/common_types.h"
|
||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||
#include "common/dma/gs.h"
|
||||
#include "game/graphics/pipelines/opengl.h"
|
||||
|
||||
namespace BufferedRenderer {
|
||||
|
||||
// The buffered renderer performs efficient sorting of primitives to reduce draw calls.
|
||||
|
||||
// the settings:
|
||||
|
||||
// this is the maximum number of draw "kinds" we can have per textures.
|
||||
// a draw is a different "kind" if any opengl state changes happen (like z test, etc)
|
||||
// if this is exceeded, this will return an error code.
|
||||
// you must flush the group, then try adding it again.
|
||||
// making this too large will slow down insertion and increase memory usage
|
||||
constexpr int MAX_DRAW_KINDS_PER_TEX = 4;
|
||||
|
||||
// this is the maximum number of textures. If this is exceeded, there will be an error like above.
|
||||
constexpr int MAX_TEXTURES = 256;
|
||||
|
||||
// this is the PS2 maximum TBP value.
|
||||
constexpr int MAX_TBP = 16384;
|
||||
|
||||
// 32-byte vertex.
|
||||
// the xyz, rgba, and stq are aligned. we have a free 4-bytes at the end.
|
||||
// there is a single big pool of vertices.
|
||||
struct Vertex {
|
||||
math::Vector<u32, 3> xyz; // ps2 coords (0)
|
||||
math::Vector<u8, 4> rgba; // 0, 4 (1)
|
||||
math::Vector<float, 2> st; // (2)
|
||||
float q; // (3)
|
||||
u32 pad;
|
||||
};
|
||||
static_assert(sizeof(Vertex) == 32);
|
||||
|
||||
// a triangle grabs three vertices from the pools.
|
||||
struct Triangle {
|
||||
u32 verts[3];
|
||||
};
|
||||
|
||||
// this represents all of the drawing state, stored as an integer.
|
||||
// it can also represent "invalid".
|
||||
class DrawMode {
|
||||
public:
|
||||
enum class AlphaBlend {
|
||||
DISABLED = 0,
|
||||
SRC_DST_SRC_DST = 1,
|
||||
SRC_0_SRC_DST = 2,
|
||||
};
|
||||
|
||||
enum class AlphaTest {
|
||||
NEVER = 0,
|
||||
ALWAYS = 1,
|
||||
GEQUAL = 2,
|
||||
};
|
||||
|
||||
bool get_depth_write_enable() const { return m_val & 0b1; }
|
||||
void enable_depth_write() { m_val = m_val | 0b1; }
|
||||
void disable_depth_write() { m_val = m_val & ~(0b1); }
|
||||
|
||||
GsTest::ZTest get_depth_test() const { return (GsTest::ZTest)((m_val >> 1) & 0b11); }
|
||||
void set_depth_test(GsTest::ZTest dt) { m_val = (m_val & ~(0b110)) | ((u32)(dt) << 1); }
|
||||
|
||||
AlphaBlend get_alpha_blend() const { return (AlphaBlend)((m_val >> 3) & 0b11); }
|
||||
void set_alpha_blend(AlphaBlend ab) { m_val = (m_val & ~(0b11000)) | ((u32)(ab) << 3); }
|
||||
|
||||
u8 get_aref() const { return m_val >> 8; }
|
||||
void set_aref(u8 val) { m_val = (m_val & ~(0xff00)) | (val << 8); }
|
||||
|
||||
AlphaTest get_alpha_test() const { return (AlphaTest)((m_val >> 16) & 0b11); }
|
||||
void set_alpha_test(AlphaTest ab) { m_val = (m_val & ~(0b11 << 16)) | ((u32)(ab) << 16); }
|
||||
|
||||
GsTest::AlphaFail get_alpha_fail() const { return (GsTest::AlphaFail)((m_val >> 21) & 0b11); }
|
||||
void set_alpha_fail(GsTest::AlphaFail ab) { m_val = (m_val & ~(0b11 << 21)) | ((u32)(ab) << 21); }
|
||||
|
||||
bool is_invalid() const { return m_val == UINT32_MAX; }
|
||||
bool is_valid() const { return !is_invalid(); }
|
||||
void set_invalid() { m_val = UINT32_MAX; }
|
||||
|
||||
bool get_clamp_enable() const { return m_val & (1 << 5); }
|
||||
void set_clamp_enable(bool en) {
|
||||
if (en) {
|
||||
enable_clamp();
|
||||
} else {
|
||||
disable_clamp();
|
||||
}
|
||||
}
|
||||
void enable_clamp() { m_val = m_val | (1 << 5); }
|
||||
void disable_clamp() { m_val = m_val & (~(1 << 5)); }
|
||||
|
||||
bool get_filt_enable() const { return m_val & (1 << 6); }
|
||||
void enable_filt() { m_val = m_val | (1 << 6); }
|
||||
void disable_filt() { m_val = m_val & (~(1 << 6)); }
|
||||
void set_filt_enable(bool en) {
|
||||
if (en) {
|
||||
enable_filt();
|
||||
} else {
|
||||
disable_filt();
|
||||
}
|
||||
}
|
||||
|
||||
bool get_tcc_enable() const { return m_val & (1 << 6); }
|
||||
void enable_tcc() { m_val = m_val | (1 << 7); }
|
||||
void disable_tcc() { m_val = m_val & (~(1 << 7)); }
|
||||
void set_tcc(bool en) {
|
||||
if (en) {
|
||||
enable_tcc();
|
||||
} else {
|
||||
disable_tcc();
|
||||
}
|
||||
}
|
||||
|
||||
bool get_at_enable() const { return m_val & (1 << 18); }
|
||||
void enable_at() { m_val = m_val | (1 << 18); }
|
||||
void disable_at() { m_val = m_val & (~(1 << 18)); }
|
||||
void set_at(bool en) {
|
||||
if (en) {
|
||||
enable_at();
|
||||
} else {
|
||||
disable_at();
|
||||
}
|
||||
}
|
||||
|
||||
bool get_zt_enable() const { return m_val & (1 << 19); }
|
||||
void enable_zt() { m_val = m_val | (1 << 19); }
|
||||
void disable_zt() { m_val = m_val & (~(1 << 19)); }
|
||||
void set_zt(bool en) {
|
||||
if (en) {
|
||||
enable_zt();
|
||||
} else {
|
||||
disable_zt();
|
||||
}
|
||||
}
|
||||
|
||||
bool get_ab_enable() const { return m_val & (1 << 20); }
|
||||
void enable_ab() { m_val = m_val | (1 << 20); }
|
||||
void disable_ab() { m_val = m_val & (~(1 << 20)); }
|
||||
void set_ab(bool en) {
|
||||
if (en) {
|
||||
enable_ab();
|
||||
} else {
|
||||
disable_ab();
|
||||
}
|
||||
}
|
||||
|
||||
u32& as_int() { return m_val; }
|
||||
|
||||
bool operator==(const DrawMode& other) const { return m_val == other.m_val; }
|
||||
bool operator!=(const DrawMode& other) const { return m_val != other.m_val; }
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
private:
|
||||
// 0 - depth write enable
|
||||
// 1, 2 - test: never, always, gequal, greater
|
||||
// 3, 4 - alpha: disable, [src,dst,src,dst], [src,0,src,dst], XX
|
||||
// 5 - clamp enable
|
||||
// 6 - filt enable
|
||||
// 7 - tcc enable
|
||||
// 8,9,10,11,12,14,14,15 - aref
|
||||
// 16, 17 - atest
|
||||
// 18 - ate
|
||||
// 19 - zte
|
||||
// 20 - abe
|
||||
// 21, 22 - afail
|
||||
u32 m_val = UINT32_MAX;
|
||||
};
|
||||
|
||||
struct Draw {
|
||||
DrawMode mode;
|
||||
std::vector<Triangle> triangles; // just indices
|
||||
void clear() {
|
||||
mode.set_invalid();
|
||||
triangles.clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct DrawGroup {
|
||||
Draw draws[MAX_DRAW_KINDS_PER_TEX];
|
||||
u16 tbp = UINT16_MAX;
|
||||
|
||||
// can fail, in which case you should flush the DrawGroup.
|
||||
Draw* get_draw_for_mode(DrawMode mode) {
|
||||
for (auto& draw : draws) {
|
||||
if (draw.mode.is_invalid()) {
|
||||
draw.mode = mode;
|
||||
return &draw;
|
||||
} else if (draw.mode == mode) {
|
||||
return &draw;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (auto& draw : draws) {
|
||||
draw.clear();
|
||||
tbp = UINT16_MAX;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DrawList {
|
||||
DrawGroup groups[MAX_TEXTURES];
|
||||
u16 tbp_to_tex_id[MAX_TBP];
|
||||
u16 current_tex_id = 0;
|
||||
|
||||
DrawList() {
|
||||
for (auto& x : tbp_to_tex_id) {
|
||||
x = UINT16_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (auto& group : groups) {
|
||||
group.clear();
|
||||
}
|
||||
for (auto& x : tbp_to_tex_id) {
|
||||
x = UINT16_MAX;
|
||||
}
|
||||
current_tex_id = 0;
|
||||
}
|
||||
|
||||
DrawGroup* get_group_for_tbp(u16 tbp) {
|
||||
if (tbp_to_tex_id[tbp] != UINT16_MAX) {
|
||||
// already have it
|
||||
return &groups[tbp_to_tex_id[tbp]];
|
||||
} else {
|
||||
if (current_tex_id == MAX_TEXTURES) {
|
||||
// don't have it, and out of room
|
||||
return nullptr;
|
||||
} else {
|
||||
// don't have it, but we can add it.
|
||||
auto group = &groups[current_tex_id];
|
||||
group->tbp = tbp;
|
||||
tbp_to_tex_id[tbp] = current_tex_id;
|
||||
current_tex_id++;
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Renderer {
|
||||
public:
|
||||
Renderer(BucketId my_id);
|
||||
~Renderer();
|
||||
void render_list(const DrawList& list,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
const std::vector<Vertex>& vertices);
|
||||
void render_group(const DrawGroup& group,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
const std::vector<Vertex>& vertices);
|
||||
|
||||
void setup_opengl_excluding_textures(SharedRenderState* render_state, DrawMode mode);
|
||||
|
||||
void draw_debug_window();
|
||||
void clear_stats();
|
||||
BucketId my_id() const { return m_my_id; }
|
||||
|
||||
private:
|
||||
static constexpr int MAX_VERTS = 400000;
|
||||
BucketId m_my_id;
|
||||
|
||||
struct {
|
||||
int triangles = 0;
|
||||
int draw_calls = 0;
|
||||
int groups = 0;
|
||||
} m_stats;
|
||||
|
||||
struct {
|
||||
GLuint vertex_buffer = -1;
|
||||
u32 vertex_buffer_size = 0;
|
||||
GLuint index_buffer = -1;
|
||||
u32 index_buffer_size = 0;
|
||||
GLuint vao = -1;
|
||||
} m_ogl;
|
||||
};
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
Builder(BucketId my_id);
|
||||
u32 add_gif_data(const void* data);
|
||||
void add_gif_data_sized(const void* data, u32 expected_size);
|
||||
void flush(SharedRenderState* render_state, ScopedProfilerNode& prof);
|
||||
void draw_debug_window();
|
||||
void reset_state();
|
||||
|
||||
private:
|
||||
void handle_ad(const u8* data);
|
||||
void handle_test1(u64 val);
|
||||
void handle_tex0_1(u64 val);
|
||||
void handle_tex1_1(u64 val);
|
||||
void handle_clamp1(u64 val);
|
||||
void handle_prim(u64 val);
|
||||
void handle_alpha1(u64 val);
|
||||
|
||||
void handle_st_packed(const u8* data);
|
||||
void handle_rgbaq_packed(const u8* data);
|
||||
void handle_xyzf2_packed(const u8* data);
|
||||
void handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f, bool advance);
|
||||
bool handle_tri_strip_add(u32 new_vertex, bool advance);
|
||||
void add_prim_now(Triangle tri);
|
||||
|
||||
u32 create_vertex_now(u32 x, u32 y, u32 z);
|
||||
BucketId my_id() const { return m_my_id; }
|
||||
|
||||
BucketId m_my_id;
|
||||
|
||||
DrawList m_list;
|
||||
Renderer m_renderer;
|
||||
DrawMode m_current_mode;
|
||||
u16 m_current_tbp = 0;
|
||||
|
||||
GsPrim::Kind m_prim_kind = GsPrim::Kind::PRIM_7;
|
||||
|
||||
std::vector<Vertex> m_vertices;
|
||||
|
||||
float m_st_pending_q[3] = {0}; // q goes to real q on rgbaq packed
|
||||
float m_q = 0;
|
||||
math::Vector<u8, 4> m_rgba;
|
||||
|
||||
// todo maybe add a mode cache?
|
||||
|
||||
struct {
|
||||
u32 idx = 0;
|
||||
u32 startup = 0;
|
||||
u32 verts[3] = {0, 0, 0};
|
||||
} m_vertex_queue;
|
||||
|
||||
struct {
|
||||
u32 m_dvert = 0;
|
||||
u32 m_tri = 0;
|
||||
} m_stats;
|
||||
|
||||
struct {
|
||||
u32 last_tbp = UINT32_MAX;
|
||||
u32 last_mode = UINT32_MAX;
|
||||
Draw* draw = nullptr;
|
||||
} m_cache;
|
||||
};
|
||||
} // namespace BufferedRenderer
|
@ -18,7 +18,8 @@ bool looks_like_tfrag_init(const DmaFollower& follow) {
|
||||
TFragment::TFragment(const std::string& name, BucketId my_id, bool child_mode)
|
||||
: BucketRenderer(name, my_id),
|
||||
m_child_mode(child_mode),
|
||||
m_direct_renderer(fmt::format("{}.direct", name), my_id, 1024, DirectRenderer::Mode::NORMAL) {
|
||||
m_direct_renderer(fmt::format("{}.direct", name), my_id, 1024, DirectRenderer::Mode::NORMAL),
|
||||
m_buffered_renderer(my_id) {
|
||||
for (auto& buf : m_buffered_data) {
|
||||
for (auto& x : buf.pad) {
|
||||
x = 0xff;
|
||||
@ -35,7 +36,12 @@ void TFragment::render(DmaFollower& dma,
|
||||
ScopedProfilerNode& prof) {
|
||||
m_debug_string.clear();
|
||||
m_frag_debug.clear();
|
||||
if (m_use_buffered_renderer) {
|
||||
m_buffered_renderer.reset_state();
|
||||
} else {
|
||||
m_direct_renderer.reset_state();
|
||||
}
|
||||
|
||||
m_stats = {};
|
||||
|
||||
if (!m_enabled) {
|
||||
@ -101,7 +107,12 @@ void TFragment::render(DmaFollower& dma,
|
||||
}
|
||||
|
||||
m_debug_string += fmt::format("fail: {}\n", dma.current_tag().print());
|
||||
|
||||
if (m_use_buffered_renderer) {
|
||||
m_buffered_renderer.flush(render_state, prof);
|
||||
} else {
|
||||
m_direct_renderer.flush_pending(render_state, prof);
|
||||
}
|
||||
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
auto tag = dma.current_tag().print();
|
||||
@ -124,6 +135,7 @@ void TFragment::draw_debug_window() {
|
||||
ImGui::Checkbox("Prog10 hack", &m_prog10_with_prog6);
|
||||
ImGui::Checkbox("Prog18 hack", &m_prog18_with_prog6);
|
||||
ImGui::Checkbox("Others with prog6", &m_all_with_prog6);
|
||||
ImGui::Checkbox("Use Buffered Renderer", &m_use_buffered_renderer);
|
||||
ImGui::Text("packets: %d", m_stats.tfrag_dma_packets);
|
||||
ImGui::Text("frag bytes: %d", m_stats.tfrag_bytes);
|
||||
ImGui::Text("errors: %d", m_stats.error_packets);
|
||||
@ -131,11 +143,16 @@ void TFragment::draw_debug_window() {
|
||||
ImGui::Text(" prog %d: %d calls\n", prog, m_stats.per_program[prog].calls);
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("direct")) {
|
||||
if (!m_use_buffered_renderer && ImGui::TreeNode("direct")) {
|
||||
m_direct_renderer.draw_debug_window();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (m_use_buffered_renderer && ImGui::TreeNode("buffered")) {
|
||||
m_buffered_renderer.draw_debug_window();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted(m_debug_string.data());
|
||||
}
|
||||
|
||||
@ -149,7 +166,11 @@ void TFragment::handle_initialization(DmaFollower& dma,
|
||||
assert(setup_test.vifcode1().immediate == 2);
|
||||
assert(setup_test.size_bytes == 32);
|
||||
memcpy(m_test_setup, setup_test.data, 32);
|
||||
if (m_use_buffered_renderer) {
|
||||
m_buffered_renderer.add_gif_data_sized(m_test_setup, 32);
|
||||
} else {
|
||||
m_direct_renderer.render_gif(m_test_setup, 32, render_state, prof);
|
||||
}
|
||||
|
||||
// matrix 0
|
||||
auto mat0_upload = dma.read_and_advance();
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/DirectRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/tfrag/BufferedRenderer.h"
|
||||
#include "common/dma/gs.h"
|
||||
#include "common/math/Vector.h"
|
||||
|
||||
@ -191,6 +192,7 @@ class TFragment : public BucketRenderer {
|
||||
bool m_prog10_with_prog6 = true;
|
||||
bool m_prog18_with_prog6 = true;
|
||||
bool m_all_with_prog6 = false;
|
||||
bool m_use_buffered_renderer = true;
|
||||
std::string m_frag_debug;
|
||||
|
||||
// GS setup data
|
||||
@ -278,4 +280,5 @@ class TFragment : public BucketRenderer {
|
||||
} m_stats;
|
||||
|
||||
DirectRenderer m_direct_renderer;
|
||||
BufferedRenderer::Builder m_buffered_renderer;
|
||||
};
|
||||
|
@ -1162,10 +1162,15 @@ void TFragment::XGKICK(u32 addr, SharedRenderState* render_state, ScopedProfiler
|
||||
assert(addr < KICK_ZONE_END);
|
||||
|
||||
if (!m_skip_xgkick) {
|
||||
if (m_use_buffered_renderer) {
|
||||
m_buffered_renderer.add_gif_data(
|
||||
&m_kick_data.pad[(addr - TFragDataMem::TFragKickZoneData) * 16]);
|
||||
} else {
|
||||
m_direct_renderer.render_gif(&m_kick_data.pad[(addr - TFragDataMem::TFragKickZoneData) * 16],
|
||||
UINT32_MAX, render_state, prof);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template void TFragment::exec_program_6<true>(SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof);
|
||||
|
@ -139,6 +139,7 @@ static std::shared_ptr<GfxDisplay> gl_make_main_display(int width,
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
|
||||
|
||||
std::string image_path = fmt::format("{}/docs/favicon-nobg.png", file_util::get_project_path());
|
||||
|
||||
|
@ -60,10 +60,6 @@ void TextureRecord::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&gpu_texture);
|
||||
ser.from_ptr(&dest);
|
||||
ser.from_pod_vector(&data);
|
||||
ser.from_ptr(&min_a_zero);
|
||||
ser.from_ptr(&max_a_zero);
|
||||
ser.from_ptr(&min_a_nonzero);
|
||||
ser.from_ptr(&max_a_nonzero);
|
||||
|
||||
if (ser.is_loading()) {
|
||||
gpu_texture = -1;
|
||||
@ -242,10 +238,6 @@ std::vector<std::shared_ptr<TextureRecord>> TexturePool::convert_textures(const
|
||||
min_a_zero = std::min(min_a_zero, a);
|
||||
}
|
||||
}
|
||||
texture_record->max_a_zero = max_a_zero;
|
||||
texture_record->min_a_zero = min_a_zero;
|
||||
texture_record->max_a_nonzero = max_a_nonzero;
|
||||
texture_record->min_a_nonzero = min_a_nonzero;
|
||||
|
||||
// Debug output.
|
||||
if (dump_textures_to_file) {
|
||||
@ -409,6 +401,12 @@ void TexturePool::upload_to_gpu(TextureRecord* tex) {
|
||||
// we have to set these, imgui won't do it automatically
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->gpu_texture);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
float aniso = 0.0f;
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &aniso);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, aniso);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
@ -7,22 +7,55 @@
|
||||
#include "game/graphics/texture/TextureConverter.h"
|
||||
#include "common/util/Serializer.h"
|
||||
|
||||
// Converting textures happens when textures are uploaded by the game.
|
||||
// Uploading textures to the gpu and creating samplers is done lazily, as needed.
|
||||
|
||||
// Each sampler
|
||||
struct TextureSampler {
|
||||
u64 sampler_object = -1; // the opengl sampler
|
||||
u64 handle = -1; // the handle used for bindless textures.
|
||||
bool created = false; // lazily created as needed, by default we don't make them
|
||||
};
|
||||
|
||||
// Each texture in our pool has a record:
|
||||
struct TextureRecord {
|
||||
std::string page_name;
|
||||
std::string name;
|
||||
u8 mip_level;
|
||||
u8 psm = -1;
|
||||
u8 cpsm = -1;
|
||||
u16 w, h;
|
||||
u8 data_segment;
|
||||
bool on_gpu = false;
|
||||
bool do_gc = true; // if set, will be unloaded from GPU when another is upload on top
|
||||
std::string page_name; // the page we belong to (from game info)
|
||||
std::string name; // our name (from game info)
|
||||
u8 mip_level; // which mip we are
|
||||
u8 psm = -1; // format in the game
|
||||
u8 cpsm = -1; // clut format in the game
|
||||
u16 w, h; // our dimensions
|
||||
u8 data_segment; // which segment we came from in the texture page
|
||||
bool on_gpu = false; // if we are uploaded to the GPU
|
||||
|
||||
// garbage collection settings.
|
||||
// by default, do_gc is set, and the pool will take care of freeing textures.
|
||||
// when a texture is uploaded on top of a texture (in PS2 VRAM), the texture will be unloaded from
|
||||
// the GPU. Unless somebody has another instance of the shared_ptr to this texture, this structure
|
||||
// (including converted texture data) will be discarded.
|
||||
|
||||
// In some cases, this is not desirable because the game may toggle between two different textures
|
||||
// in VRAM, and we don't want to reconvert every time. The TextureUploadHandler will implement its
|
||||
// own caching to help with this. To manage textures yourself, you should:
|
||||
// - keep around a shared_ptr to the TextureRecord (so it doesn't get deleted when it's out of PS2
|
||||
// VRAM).
|
||||
// - set do_gc to false (to keep texture in GPU memory when replaced).
|
||||
// In this case, you must use the discard function to remove the texture from the GPU, if you
|
||||
// really want to get rid of it.
|
||||
bool do_gc = true;
|
||||
|
||||
// The texture data. In some cases, we keep textures only on the GPU (for example, the result of a
|
||||
// render to texture). In these, data is not populated, but you must set only_on_gpu = true. When
|
||||
// saving graphics state, the texture will be dumped from the GPU and saved to the file so it is
|
||||
// possible to restore.
|
||||
bool only_on_gpu = false;
|
||||
std::vector<u8> data;
|
||||
u64 gpu_texture = 0;
|
||||
u32 dest = -1;
|
||||
|
||||
u8 min_a_zero, max_a_zero, min_a_nonzero, max_a_nonzero;
|
||||
// if we're on the gpu, our OpenGL texture
|
||||
u64 gpu_texture = 0;
|
||||
|
||||
// our VRAM address.
|
||||
u32 dest = -1;
|
||||
|
||||
void unload_from_gpu();
|
||||
|
||||
|
@ -119,7 +119,7 @@ int IsPressed(MappingInfo& mapping, Button button, int pad = 0) {
|
||||
|
||||
// returns the value of the analog axis (in the future, likely pressure sensitive if we support it?)
|
||||
// if invalid or otherwise -- returns 127 (analog stick neutral position)
|
||||
int AnalogValue(MappingInfo& mapping, Analog analog, int pad = 0) {
|
||||
int AnalogValue(MappingInfo& /*mapping*/, Analog analog, int pad = 0) {
|
||||
if (CheckPadIdx(pad) == -1) {
|
||||
return 127;
|
||||
}
|
||||
|
68
third-party/glad/include/glad/glad.h
generated
vendored
68
third-party/glad/include/glad/glad.h
generated
vendored
@ -1,22 +1,23 @@
|
||||
/*
|
||||
|
||||
OpenGL loader generated by glad 0.1.34 on Wed Oct 6 20:57:47 2021.
|
||||
OpenGL loader generated by glad 0.1.34 on Sun Nov 14 17:13:20 2021.
|
||||
|
||||
Language/Generator: C/C++
|
||||
Specification: gl
|
||||
APIs: gl=4.3
|
||||
Profile: compatibility
|
||||
Extensions:
|
||||
|
||||
GL_ARB_bindless_texture,
|
||||
GL_ARB_texture_filter_anisotropic
|
||||
Loader: True
|
||||
Local files: False
|
||||
Omit khrplatform: False
|
||||
Reproducible: False
|
||||
|
||||
Commandline:
|
||||
--profile="compatibility" --api="gl=4.3" --generator="c" --spec="gl" --extensions=""
|
||||
--profile="compatibility" --api="gl=4.3" --generator="c" --spec="gl" --extensions="GL_ARB_bindless_texture,GL_ARB_texture_filter_anisotropic"
|
||||
Online:
|
||||
https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D4.3
|
||||
https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D4.3&extensions=GL_ARB_bindless_texture&extensions=GL_ARB_texture_filter_anisotropic
|
||||
*/
|
||||
|
||||
|
||||
@ -4669,6 +4670,65 @@ typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void *ptr, GLsizei buf
|
||||
GLAPI PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel;
|
||||
#define glGetObjectPtrLabel glad_glGetObjectPtrLabel
|
||||
#endif
|
||||
#define GL_UNSIGNED_INT64_ARB 0x140F
|
||||
#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE
|
||||
#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF
|
||||
#ifndef GL_ARB_bindless_texture
|
||||
#define GL_ARB_bindless_texture 1
|
||||
GLAPI int GLAD_GL_ARB_bindless_texture;
|
||||
typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC)(GLuint texture);
|
||||
GLAPI PFNGLGETTEXTUREHANDLEARBPROC glad_glGetTextureHandleARB;
|
||||
#define glGetTextureHandleARB glad_glGetTextureHandleARB
|
||||
typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC)(GLuint texture, GLuint sampler);
|
||||
GLAPI PFNGLGETTEXTURESAMPLERHANDLEARBPROC glad_glGetTextureSamplerHandleARB;
|
||||
#define glGetTextureSamplerHandleARB glad_glGetTextureSamplerHandleARB
|
||||
typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC)(GLuint64 handle);
|
||||
GLAPI PFNGLMAKETEXTUREHANDLERESIDENTARBPROC glad_glMakeTextureHandleResidentARB;
|
||||
#define glMakeTextureHandleResidentARB glad_glMakeTextureHandleResidentARB
|
||||
typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC)(GLuint64 handle);
|
||||
GLAPI PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC glad_glMakeTextureHandleNonResidentARB;
|
||||
#define glMakeTextureHandleNonResidentARB glad_glMakeTextureHandleNonResidentARB
|
||||
typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC)(GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
|
||||
GLAPI PFNGLGETIMAGEHANDLEARBPROC glad_glGetImageHandleARB;
|
||||
#define glGetImageHandleARB glad_glGetImageHandleARB
|
||||
typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC)(GLuint64 handle, GLenum access);
|
||||
GLAPI PFNGLMAKEIMAGEHANDLERESIDENTARBPROC glad_glMakeImageHandleResidentARB;
|
||||
#define glMakeImageHandleResidentARB glad_glMakeImageHandleResidentARB
|
||||
typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC)(GLuint64 handle);
|
||||
GLAPI PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC glad_glMakeImageHandleNonResidentARB;
|
||||
#define glMakeImageHandleNonResidentARB glad_glMakeImageHandleNonResidentARB
|
||||
typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC)(GLint location, GLuint64 value);
|
||||
GLAPI PFNGLUNIFORMHANDLEUI64ARBPROC glad_glUniformHandleui64ARB;
|
||||
#define glUniformHandleui64ARB glad_glUniformHandleui64ARB
|
||||
typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC)(GLint location, GLsizei count, const GLuint64 *value);
|
||||
GLAPI PFNGLUNIFORMHANDLEUI64VARBPROC glad_glUniformHandleui64vARB;
|
||||
#define glUniformHandleui64vARB glad_glUniformHandleui64vARB
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC)(GLuint program, GLint location, GLuint64 value);
|
||||
GLAPI PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC glad_glProgramUniformHandleui64ARB;
|
||||
#define glProgramUniformHandleui64ARB glad_glProgramUniformHandleui64ARB
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC)(GLuint program, GLint location, GLsizei count, const GLuint64 *values);
|
||||
GLAPI PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC glad_glProgramUniformHandleui64vARB;
|
||||
#define glProgramUniformHandleui64vARB glad_glProgramUniformHandleui64vARB
|
||||
typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC)(GLuint64 handle);
|
||||
GLAPI PFNGLISTEXTUREHANDLERESIDENTARBPROC glad_glIsTextureHandleResidentARB;
|
||||
#define glIsTextureHandleResidentARB glad_glIsTextureHandleResidentARB
|
||||
typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC)(GLuint64 handle);
|
||||
GLAPI PFNGLISIMAGEHANDLERESIDENTARBPROC glad_glIsImageHandleResidentARB;
|
||||
#define glIsImageHandleResidentARB glad_glIsImageHandleResidentARB
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC)(GLuint index, GLuint64EXT x);
|
||||
GLAPI PFNGLVERTEXATTRIBL1UI64ARBPROC glad_glVertexAttribL1ui64ARB;
|
||||
#define glVertexAttribL1ui64ARB glad_glVertexAttribL1ui64ARB
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC)(GLuint index, const GLuint64EXT *v);
|
||||
GLAPI PFNGLVERTEXATTRIBL1UI64VARBPROC glad_glVertexAttribL1ui64vARB;
|
||||
#define glVertexAttribL1ui64vARB glad_glVertexAttribL1ui64vARB
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC)(GLuint index, GLenum pname, GLuint64EXT *params);
|
||||
GLAPI PFNGLGETVERTEXATTRIBLUI64VARBPROC glad_glGetVertexAttribLui64vARB;
|
||||
#define glGetVertexAttribLui64vARB glad_glGetVertexAttribLui64vARB
|
||||
#endif
|
||||
#ifndef GL_ARB_texture_filter_anisotropic
|
||||
#define GL_ARB_texture_filter_anisotropic 1
|
||||
GLAPI int GLAD_GL_ARB_texture_filter_anisotropic;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
50
third-party/glad/src/glad.c
generated
vendored
50
third-party/glad/src/glad.c
generated
vendored
@ -1,22 +1,23 @@
|
||||
/*
|
||||
|
||||
OpenGL loader generated by glad 0.1.34 on Wed Oct 6 20:57:47 2021.
|
||||
OpenGL loader generated by glad 0.1.34 on Sun Nov 14 17:13:20 2021.
|
||||
|
||||
Language/Generator: C/C++
|
||||
Specification: gl
|
||||
APIs: gl=4.3
|
||||
Profile: compatibility
|
||||
Extensions:
|
||||
|
||||
GL_ARB_bindless_texture,
|
||||
GL_ARB_texture_filter_anisotropic
|
||||
Loader: True
|
||||
Local files: False
|
||||
Omit khrplatform: False
|
||||
Reproducible: False
|
||||
|
||||
Commandline:
|
||||
--profile="compatibility" --api="gl=4.3" --generator="c" --spec="gl" --extensions=""
|
||||
--profile="compatibility" --api="gl=4.3" --generator="c" --spec="gl" --extensions="GL_ARB_bindless_texture,GL_ARB_texture_filter_anisotropic"
|
||||
Online:
|
||||
https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D4.3
|
||||
https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D4.3&extensions=GL_ARB_bindless_texture&extensions=GL_ARB_texture_filter_anisotropic
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -1184,6 +1185,24 @@ PFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL;
|
||||
PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL;
|
||||
PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL;
|
||||
PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL;
|
||||
int GLAD_GL_ARB_bindless_texture = 0;
|
||||
int GLAD_GL_ARB_texture_filter_anisotropic = 0;
|
||||
PFNGLGETTEXTUREHANDLEARBPROC glad_glGetTextureHandleARB = NULL;
|
||||
PFNGLGETTEXTURESAMPLERHANDLEARBPROC glad_glGetTextureSamplerHandleARB = NULL;
|
||||
PFNGLMAKETEXTUREHANDLERESIDENTARBPROC glad_glMakeTextureHandleResidentARB = NULL;
|
||||
PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC glad_glMakeTextureHandleNonResidentARB = NULL;
|
||||
PFNGLGETIMAGEHANDLEARBPROC glad_glGetImageHandleARB = NULL;
|
||||
PFNGLMAKEIMAGEHANDLERESIDENTARBPROC glad_glMakeImageHandleResidentARB = NULL;
|
||||
PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC glad_glMakeImageHandleNonResidentARB = NULL;
|
||||
PFNGLUNIFORMHANDLEUI64ARBPROC glad_glUniformHandleui64ARB = NULL;
|
||||
PFNGLUNIFORMHANDLEUI64VARBPROC glad_glUniformHandleui64vARB = NULL;
|
||||
PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC glad_glProgramUniformHandleui64ARB = NULL;
|
||||
PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC glad_glProgramUniformHandleui64vARB = NULL;
|
||||
PFNGLISTEXTUREHANDLERESIDENTARBPROC glad_glIsTextureHandleResidentARB = NULL;
|
||||
PFNGLISIMAGEHANDLERESIDENTARBPROC glad_glIsImageHandleResidentARB = NULL;
|
||||
PFNGLVERTEXATTRIBL1UI64ARBPROC glad_glVertexAttribL1ui64ARB = NULL;
|
||||
PFNGLVERTEXATTRIBL1UI64VARBPROC glad_glVertexAttribL1ui64vARB = NULL;
|
||||
PFNGLGETVERTEXATTRIBLUI64VARBPROC glad_glGetVertexAttribLui64vARB = NULL;
|
||||
static void load_GL_VERSION_1_0(GLADloadproc load) {
|
||||
if(!GLAD_GL_VERSION_1_0) return;
|
||||
glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
|
||||
@ -2150,9 +2169,29 @@ static void load_GL_VERSION_4_3(GLADloadproc load) {
|
||||
glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load("glGetObjectPtrLabel");
|
||||
glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv");
|
||||
}
|
||||
static void load_GL_ARB_bindless_texture(GLADloadproc load) {
|
||||
if(!GLAD_GL_ARB_bindless_texture) return;
|
||||
glad_glGetTextureHandleARB = (PFNGLGETTEXTUREHANDLEARBPROC)load("glGetTextureHandleARB");
|
||||
glad_glGetTextureSamplerHandleARB = (PFNGLGETTEXTURESAMPLERHANDLEARBPROC)load("glGetTextureSamplerHandleARB");
|
||||
glad_glMakeTextureHandleResidentARB = (PFNGLMAKETEXTUREHANDLERESIDENTARBPROC)load("glMakeTextureHandleResidentARB");
|
||||
glad_glMakeTextureHandleNonResidentARB = (PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC)load("glMakeTextureHandleNonResidentARB");
|
||||
glad_glGetImageHandleARB = (PFNGLGETIMAGEHANDLEARBPROC)load("glGetImageHandleARB");
|
||||
glad_glMakeImageHandleResidentARB = (PFNGLMAKEIMAGEHANDLERESIDENTARBPROC)load("glMakeImageHandleResidentARB");
|
||||
glad_glMakeImageHandleNonResidentARB = (PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC)load("glMakeImageHandleNonResidentARB");
|
||||
glad_glUniformHandleui64ARB = (PFNGLUNIFORMHANDLEUI64ARBPROC)load("glUniformHandleui64ARB");
|
||||
glad_glUniformHandleui64vARB = (PFNGLUNIFORMHANDLEUI64VARBPROC)load("glUniformHandleui64vARB");
|
||||
glad_glProgramUniformHandleui64ARB = (PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC)load("glProgramUniformHandleui64ARB");
|
||||
glad_glProgramUniformHandleui64vARB = (PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC)load("glProgramUniformHandleui64vARB");
|
||||
glad_glIsTextureHandleResidentARB = (PFNGLISTEXTUREHANDLERESIDENTARBPROC)load("glIsTextureHandleResidentARB");
|
||||
glad_glIsImageHandleResidentARB = (PFNGLISIMAGEHANDLERESIDENTARBPROC)load("glIsImageHandleResidentARB");
|
||||
glad_glVertexAttribL1ui64ARB = (PFNGLVERTEXATTRIBL1UI64ARBPROC)load("glVertexAttribL1ui64ARB");
|
||||
glad_glVertexAttribL1ui64vARB = (PFNGLVERTEXATTRIBL1UI64VARBPROC)load("glVertexAttribL1ui64vARB");
|
||||
glad_glGetVertexAttribLui64vARB = (PFNGLGETVERTEXATTRIBLUI64VARBPROC)load("glGetVertexAttribLui64vARB");
|
||||
}
|
||||
static int find_extensionsGL(void) {
|
||||
if (!get_exts()) return 0;
|
||||
(void)&has_ext;
|
||||
GLAD_GL_ARB_bindless_texture = has_ext("GL_ARB_bindless_texture");
|
||||
GLAD_GL_ARB_texture_filter_anisotropic = has_ext("GL_ARB_texture_filter_anisotropic");
|
||||
free_exts();
|
||||
return 1;
|
||||
}
|
||||
@ -2239,6 +2278,7 @@ int gladLoadGLLoader(GLADloadproc load) {
|
||||
load_GL_VERSION_4_3(load);
|
||||
|
||||
if (!find_extensionsGL()) return 0;
|
||||
load_GL_ARB_bindless_texture(load);
|
||||
return GLVersion.major != 0 || GLVersion.minor != 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user