Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented 3 point filtering in OpenGL and some misc changes. #12

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions gfx_direct3d11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

#include "gfx_screen_config.h"

#define THREE_POINT_FILTERING 0
#define DEBUG_D3D 0

using namespace Microsoft::WRL; // For ComPtr
Expand Down Expand Up @@ -321,7 +320,13 @@ static struct ShaderProgram *gfx_d3d11_create_and_load_new_shader(uint32_t shade
char buf[4096];
size_t len, num_floats;

gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, THREE_POINT_FILTERING);
#ifdef THREE_POINT_FILTERING
bool three_point_filtering = true;
#else
bool three_point_filtering = false;
#endif

gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, three_point_filtering);

ComPtr<ID3DBlob> vs, ps;
ComPtr<ID3DBlob> error_blob;
Expand Down Expand Up @@ -487,7 +492,7 @@ static void gfx_d3d11_set_sampler_parameters(int tile, bool linear_filter, uint3
D3D11_SAMPLER_DESC sampler_desc;
ZeroMemory(&sampler_desc, sizeof(D3D11_SAMPLER_DESC));

#if THREE_POINT_FILTERING
#ifdef THREE_POINT_FILTERING
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
#else
sampler_desc.Filter = linear_filter ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT;
Expand Down Expand Up @@ -598,7 +603,7 @@ static void gfx_d3d11_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t
d3d.last_resource_views[i] = d3d.textures[d3d.current_texture_ids[i]].resource_view.Get();
d3d.context->PSSetShaderResources(i, 1, d3d.textures[d3d.current_texture_ids[i]].resource_view.GetAddressOf());

#if THREE_POINT_FILTERING
#ifdef THREE_POINT_FILTERING
d3d.per_draw_cb_data.textures[i].width = d3d.textures[d3d.current_texture_ids[i]].width;
d3d.per_draw_cb_data.textures[i].height = d3d.textures[d3d.current_texture_ids[i]].height;
d3d.per_draw_cb_data.textures[i].linear_filtering = d3d.textures[d3d.current_texture_ids[i]].linear_filtering;
Expand Down
144 changes: 126 additions & 18 deletions gfx_opengl.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,30 @@ struct ShaderProgram {
uint8_t attrib_sizes[7];
uint8_t num_attribs;
bool used_noise;
GLint frame_count_location;
GLint window_height_location;
GLint noise_frame_location;
GLint noise_scale_location;
GLint texture_width_location;
GLint texture_height_location;
GLint texture_linear_filtering_location;
};

static struct ShaderProgram shader_program_pool[64];
static struct ShaderProgram *current_shader_program;
static uint8_t shader_program_pool_size;
static GLuint opengl_vbo;

static uint32_t frame_count;
static uint32_t current_height;
static uint32_t noise_frame;
static float noise_scale[2];
#ifdef THREE_POINT_FILTERING
struct TextureInfo {
uint16_t width;
uint16_t height;
bool linear_filtering;

} textures[1024];
static GLuint current_texture_ids[2];
static uint8_t current_tile;
#endif

static bool gfx_opengl_z_is_from_0_to_1(void) {
return false;
Expand All @@ -64,13 +78,28 @@ static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram *prg) {
}
}

static void gfx_opengl_set_uniforms(struct ShaderProgram *prg) {
if (prg->used_noise) {
glUniform1i(prg->frame_count_location, frame_count);
glUniform1i(prg->window_height_location, current_height);
static void gfx_opengl_set_per_program_uniforms() {
if (current_shader_program->used_noise) {
glUniform1i(current_shader_program->noise_frame_location, noise_frame);
glUniform2f(current_shader_program->noise_scale_location, noise_scale[0], noise_scale[1]);
}
}

static void gfx_opengl_set_per_draw_uniforms() {
#ifdef THREE_POINT_FILTERING
if (current_shader_program->used_textures[0] || current_shader_program->used_textures[1]) {
GLint filtering[2] = { textures[current_texture_ids[0]].linear_filtering, textures[current_texture_ids[1]].linear_filtering };
glUniform1iv(current_shader_program->texture_linear_filtering_location, 2, filtering);

GLint width[2] = { textures[current_texture_ids[0]].width, textures[current_texture_ids[1]].width };
glUniform1iv(current_shader_program->texture_width_location, 2, width);

GLint height[2] = { textures[current_texture_ids[0]].height, textures[current_texture_ids[1]].height };
glUniform1iv(current_shader_program->texture_height_location, 2, height);
}
#endif
}

static void gfx_opengl_unload_shader(struct ShaderProgram *old_prg) {
if (old_prg != NULL) {
for (int i = 0; i < old_prg->num_attribs; i++) {
Expand All @@ -80,9 +109,10 @@ static void gfx_opengl_unload_shader(struct ShaderProgram *old_prg) {
}

static void gfx_opengl_load_shader(struct ShaderProgram *new_prg) {
current_shader_program = new_prg;
glUseProgram(new_prg->opengl_program_id);
gfx_opengl_vertex_array_set_attribs(new_prg);
gfx_opengl_set_uniforms(new_prg);
gfx_opengl_set_per_program_uniforms();
}

static void append_str(char *buf, size_t *len, const char *str) {
Expand Down Expand Up @@ -169,7 +199,7 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad
gfx_cc_get_features(shader_id, &cc_features);

char vs_buf[1024];
char fs_buf[1024];
char fs_buf[2048];
size_t vs_len = 0;
size_t fs_len = 0;
size_t num_floats = 4;
Expand All @@ -192,6 +222,9 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad
vs_len += sprintf(vs_buf + vs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
num_floats += cc_features.opt_alpha ? 4 : 3;
}
if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(vs_buf, &vs_len, "varying vec4 screenPos;");
}
append_line(vs_buf, &vs_len, "void main() {");
if (cc_features.used_textures[0] || cc_features.used_textures[1]) {
append_line(vs_buf, &vs_len, "vTexCoord = aTexCoord;");
Expand All @@ -202,6 +235,9 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad
for (int i = 0; i < cc_features.num_inputs; i++) {
vs_len += sprintf(vs_buf + vs_len, "vInput%d = aInput%d;\n", i + 1, i + 1);
}
if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(vs_buf, &vs_len, "screenPos = aVtxPos;");
}
append_line(vs_buf, &vs_len, "gl_Position = aVtxPos;");
append_line(vs_buf, &vs_len, "}");

Expand All @@ -217,6 +253,9 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad
for (int i = 0; i < cc_features.num_inputs; i++) {
fs_len += sprintf(fs_buf + fs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
}
if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(fs_buf, &fs_len, "varying vec4 screenPos;");
}
if (cc_features.used_textures[0]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTex0;");
}
Expand All @@ -225,22 +264,59 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad
}

if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(fs_buf, &fs_len, "uniform int frame_count;");
append_line(fs_buf, &fs_len, "uniform int window_height;");
append_line(fs_buf, &fs_len, "uniform int noise_frame;");
append_line(fs_buf, &fs_len, "uniform vec2 noise_scale;");

append_line(fs_buf, &fs_len, "float random(in vec3 value) {");
append_line(fs_buf, &fs_len, " float random = dot(sin(value), vec3(12.9898, 78.233, 37.719));");
append_line(fs_buf, &fs_len, " float random = dot(value, vec3(12.9898, 78.233, 37.719));");
append_line(fs_buf, &fs_len, " return fract(sin(random) * 143758.5453);");
append_line(fs_buf, &fs_len, "}");
}

#ifdef THREE_POINT_FILTERING
// 3 point texture filtering
// Original author: ArthurCarvalho
// Based on GLSL implementation by twinaphex, mupen64plus-libretro project.

if (cc_features.used_textures[0] || cc_features.used_textures[1]) {
append_line(fs_buf, &fs_len, "uniform int texture_width[2];");
append_line(fs_buf, &fs_len, "uniform int texture_height[2];");
append_line(fs_buf, &fs_len, "uniform bool texture_linear_filtering[2];");
append_line(fs_buf, &fs_len, "#define TEX_OFFSET(tex, texCoord, off, texSize) texture2D(tex, texCoord - off / texSize)");
append_line(fs_buf, &fs_len, "vec4 tex2D3PointFilter(in sampler2D tex, in vec2 texCoord, in vec2 texSize) {");
append_line(fs_buf, &fs_len, " vec2 offset = fract(texCoord * texSize - vec2(0.5, 0.5));");
append_line(fs_buf, &fs_len, " offset -= step(1.0, offset.x + offset.y);");
append_line(fs_buf, &fs_len, " vec4 c0 = TEX_OFFSET(tex, texCoord, offset, texSize);");
append_line(fs_buf, &fs_len, " vec4 c1 = TEX_OFFSET(tex, texCoord, vec2(offset.x - sign(offset.x), offset.y), texSize);");
append_line(fs_buf, &fs_len, " vec4 c2 = TEX_OFFSET(tex, texCoord, vec2(offset.x, offset.y - sign(offset.y)), texSize);");
append_line(fs_buf, &fs_len, " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0);");
append_line(fs_buf, &fs_len, "}");
}
#endif

append_line(fs_buf, &fs_len, "void main() {");

if (cc_features.used_textures[0]) {
#ifdef THREE_POINT_FILTERING
append_line(fs_buf, &fs_len, " vec4 texVal0;");
append_line(fs_buf, &fs_len, " if (texture_linear_filtering[0])");
append_line(fs_buf, &fs_len, " texVal0 = tex2D3PointFilter(uTex0, vTexCoord, vec2(texture_width[0], texture_height[0]));");
append_line(fs_buf, &fs_len, " else");
append_line(fs_buf, &fs_len, " texVal0 = texture2D(uTex0, vTexCoord);");
#else
append_line(fs_buf, &fs_len, "vec4 texVal0 = texture2D(uTex0, vTexCoord);");
#endif
}
if (cc_features.used_textures[1]) {
#ifdef THREE_POINT_FILTERING
append_line(fs_buf, &fs_len, " vec4 texVal1;");
append_line(fs_buf, &fs_len, " if (texture_linear_filtering[1])");
append_line(fs_buf, &fs_len, " texVal1 = tex2D3PointFilter(uTex1, vTexCoord, vec2(texture_width[1], texture_height[1]));");
append_line(fs_buf, &fs_len, " else");
append_line(fs_buf, &fs_len, " texVal1 = texture2D(uTex1, vTexCoord);");
#else
append_line(fs_buf, &fs_len, "vec4 texVal1 = texture2D(uTex1, vTexCoord);");
#endif
}

append_str(fs_buf, &fs_len, cc_features.opt_alpha ? "vec4 texel = " : "vec3 texel = ");
Expand Down Expand Up @@ -268,7 +344,8 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad
}

if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(fs_buf, &fs_len, "texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * (240.0 / float(window_height))), float(frame_count))) + texel.a, 0.0, 1.0));");
append_line(fs_buf, &fs_len, "vec2 coords = (screenPos.xy / screenPos.w) * noise_scale;");
append_line(fs_buf, &fs_len, "texel.a *= floor(clamp(random(vec3(floor(coords), float(noise_frame))) + texel.a, 0.0, 1.0));");
}

if (cc_features.opt_alpha) {
Expand Down Expand Up @@ -371,13 +448,21 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad
}

if (cc_features.opt_alpha && cc_features.opt_noise) {
prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count");
prg->window_height_location = glGetUniformLocation(shader_program, "window_height");
prg->noise_frame_location = glGetUniformLocation(shader_program, "noise_frame");
prg->noise_scale_location = glGetUniformLocation(shader_program, "noise_scale");
prg->used_noise = true;
} else {
prg->used_noise = false;
}

#ifdef THREE_POINT_FILTERING
if (cc_features.used_textures[0] || cc_features.used_textures[1]) {
prg->texture_width_location = glGetUniformLocation(shader_program, "texture_width");
prg->texture_height_location = glGetUniformLocation(shader_program, "texture_height");
prg->texture_linear_filtering_location = glGetUniformLocation(shader_program, "texture_linear_filtering");
}
#endif

return prg;
}

Expand Down Expand Up @@ -405,10 +490,18 @@ static GLuint gfx_opengl_new_texture(void) {
static void gfx_opengl_select_texture(int tile, GLuint texture_id) {
glActiveTexture(GL_TEXTURE0 + tile);
glBindTexture(GL_TEXTURE_2D, texture_id);
#ifdef THREE_POINT_FILTERING
current_texture_ids[tile] = texture_id;
current_tile = tile;
#endif
}

static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, int width, int height) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf);
#ifdef THREE_POINT_FILTERING
textures[current_texture_ids[current_tile]].width = width;
textures[current_texture_ids[current_tile]].height = height;
#endif
}

static uint32_t gfx_cm_to_opengl(uint32_t val) {
Expand All @@ -420,8 +513,15 @@ static uint32_t gfx_cm_to_opengl(uint32_t val) {

static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) {
glActiveTexture(GL_TEXTURE0 + tile);

#ifdef THREE_POINT_FILTERING
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
textures[current_texture_ids[tile]].linear_filtering = linear_filter;
#else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
#endif
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gfx_cm_to_opengl(cms));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt));
}
Expand Down Expand Up @@ -450,7 +550,10 @@ static void gfx_opengl_set_zmode_decal(bool zmode_decal) {

static void gfx_opengl_set_viewport(int x, int y, int width, int height) {
glViewport(x, y, width, height);
current_height = height;

float aspect_ratio = (float) width / (float) height;
noise_scale[0] = 120 * aspect_ratio; // 120 = N64 height resolution (240) / 2
noise_scale[1] = 120;
}

static void gfx_opengl_set_scissor(int x, int y, int width, int height) {
Expand All @@ -467,6 +570,7 @@ static void gfx_opengl_set_use_alpha(bool use_alpha) {

static void gfx_opengl_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) {
//printf("flushing %d tris\n", buf_vbo_num_tris);
gfx_opengl_set_per_draw_uniforms();
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * buf_vbo_len, buf_vbo, GL_STREAM_DRAW);
glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris);
}
Expand All @@ -488,7 +592,11 @@ static void gfx_opengl_on_resize(void) {
}

static void gfx_opengl_start_frame(void) {
frame_count++;
noise_frame++;
if (noise_frame > 150) {
// No high values, as noise starts to look ugly
noise_frame = 0;
}

glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_TRUE); // Must be set to clear Z-buffer
Expand Down