From e8d266cb9d607c93cfbef786240b8dc08232e02e Mon Sep 17 00:00:00 2001 From: Twinaphex Date: Sun, 30 Aug 2015 18:37:41 +0200 Subject: [PATCH] Revert "Revert "Add support for shader pass feedback."" --- gfx/drivers/gl.c | 395 ++++++++++++++++++++---------- gfx/drivers/gl_common.h | 5 + gfx/drivers_shader/shader_gl_cg.c | 130 +++++----- gfx/drivers_shader/shader_glsl.c | 51 +++- gfx/drivers_shader/shader_hlsl.c | 9 + gfx/drivers_shader/shader_null.c | 8 + gfx/video_shader_driver.h | 2 + gfx/video_shader_parse.c | 5 + gfx/video_shader_parse.h | 4 + tools/cg2glsl.py | 4 + 10 files changed, 402 insertions(+), 211 deletions(-) diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index fe0fadd5c9..41938da36a 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -429,109 +429,128 @@ static void gl_compute_fbo_geometry(gl_t *gl, unsigned width, unsigned height, } } -static void gl_create_fbo_textures(gl_t *gl) +static void gl_create_fbo_texture(gl_t *gl, unsigned i, GLuint texture) { - int i; settings_t *settings = config_get_ptr(); + + enum gfx_wrap_type wrap; + GLenum min_filter, mag_filter, wrap_enum; + bool mipmapped = false; + bool smooth = false; + bool fp_fbo, srgb_fbo; + GLuint base_filt = settings->video.smooth ? GL_LINEAR : GL_NEAREST; GLuint base_mip_filt = settings->video.smooth ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; + glBindTexture(GL_TEXTURE_2D, texture); + + mipmapped = gl->shader->mipmap_input(i + 2); + + min_filter = mipmapped ? base_mip_filt : base_filt; + if (gl->shader->filter_type(i + 2, &smooth)) + { + min_filter = mipmapped ? (smooth ? + GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST) + : (smooth ? GL_LINEAR : GL_NEAREST); + } + + mag_filter = min_filter_to_mag(min_filter); + + wrap = gl->shader->wrap_type(i + 2); + wrap_enum = gl_wrap_type_to_enum(wrap); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_enum); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_enum); + + fp_fbo = gl->fbo_scale[i].fp_fbo; + srgb_fbo = gl->fbo_scale[i].srgb_fbo; + + if (fp_fbo) + { + if (!gl->has_fp_fbo) + RARCH_ERR("[GL]: Floating-point FBO was requested, but is not supported. Falling back to UNORM. Result may band/clip/etc.!\n"); + } + else if (srgb_fbo) + { + if (!gl->has_srgb_fbo) + RARCH_ERR("[GL]: sRGB FBO was requested, but it is not supported. Falling back to UNORM. Result may have banding!\n"); + } + + if (settings->video.force_srgb_disable) + srgb_fbo = false; + +#ifndef HAVE_OPENGLES2 + if (fp_fbo && gl->has_fp_fbo) + { + RARCH_LOG("[GL]: FBO pass #%d is floating-point.\n", i); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, + gl->fbo_rect[i].width, gl->fbo_rect[i].height, + 0, GL_RGBA, GL_FLOAT, NULL); + } + else +#endif + { +#ifndef HAVE_OPENGLES + settings_t *settings = config_get_ptr(); + GLuint base_filt = settings->video.smooth ? GL_LINEAR : GL_NEAREST; + GLuint base_mip_filt = settings->video.smooth ? + GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; + + if (srgb_fbo && gl->has_srgb_fbo) + { + RARCH_LOG("[GL]: FBO pass #%d is sRGB.\n", i); +#ifdef HAVE_OPENGLES2 + /* EXT defines are same as core GLES3 defines, + * but GLES3 variant requires different arguments. */ + glTexImage2D(GL_TEXTURE_2D, + 0, GL_SRGB_ALPHA_EXT, + gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, + gl->has_srgb_fbo_gles3 ? GL_RGBA : GL_SRGB_ALPHA_EXT, + GL_UNSIGNED_BYTE, NULL); +#else + glTexImage2D(GL_TEXTURE_2D, + 0, GL_SRGB8_ALPHA8, + gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); +#endif + } + else +#endif + { +#ifdef HAVE_OPENGLES2 + glTexImage2D(GL_TEXTURE_2D, + 0, GL_RGBA, + gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); +#else + /* Avoid potential performance + * reductions on particular platforms. */ + glTexImage2D(GL_TEXTURE_2D, + 0, RARCH_GL_INTERNAL_FORMAT32, + gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, + RARCH_GL_TEXTURE_TYPE32, RARCH_GL_FORMAT32, NULL); +#endif + } + } +} + +static void gl_create_fbo_textures(gl_t *gl) +{ + int i; glGenTextures(gl->fbo_pass, gl->fbo_texture); for (i = 0; i < gl->fbo_pass; i++) { - enum gfx_wrap_type wrap; - GLenum min_filter, mag_filter, wrap_enum; - bool mipmapped = false; - bool smooth = false; - bool fp_fbo, srgb_fbo; + gl_create_fbo_texture(gl, i, gl->fbo_texture[i]); + } - glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[i]); - - mipmapped = gl->shader->mipmap_input(i + 2); - - min_filter = mipmapped ? base_mip_filt : base_filt; - if (gl->shader->filter_type(i + 2, &smooth)) - min_filter = mipmapped ? (smooth ? - GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST) - : (smooth ? GL_LINEAR : GL_NEAREST); - - mag_filter = min_filter_to_mag(min_filter); - - wrap = gl->shader->wrap_type(i + 2); - wrap_enum = gl_wrap_type_to_enum(wrap); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_enum); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_enum); - - fp_fbo = gl->fbo_scale[i].fp_fbo; - srgb_fbo = gl->fbo_scale[i].srgb_fbo; - - if (fp_fbo) - { - if (!gl->has_fp_fbo) - RARCH_ERR("[GL]: Floating-point FBO was requested, but is not supported. Falling back to UNORM. Result may band/clip/etc.!\n"); - } - else if (srgb_fbo) - { - if (!gl->has_srgb_fbo) - RARCH_ERR("[GL]: sRGB FBO was requested, but it is not supported. Falling back to UNORM. Result may have banding!\n"); - } - - if (settings->video.force_srgb_disable) - srgb_fbo = false; - - #ifndef HAVE_OPENGLES2 - if (fp_fbo && gl->has_fp_fbo) - { - RARCH_LOG("[GL]: FBO pass #%d is floating-point.\n", i); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, - gl->fbo_rect[i].width, gl->fbo_rect[i].height, - 0, GL_RGBA, GL_FLOAT, NULL); - } - else - #endif - { - #ifndef HAVE_OPENGLES - if (srgb_fbo && gl->has_srgb_fbo) - { - RARCH_LOG("[GL]: FBO pass #%d is sRGB.\n", i); - #ifdef HAVE_OPENGLES2 - /* EXT defines are same as core GLES3 defines, - * but GLES3 variant requires different arguments. */ - glTexImage2D(GL_TEXTURE_2D, - 0, GL_SRGB_ALPHA_EXT, - gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, - gl->has_srgb_fbo_gles3 ? GL_RGBA : GL_SRGB_ALPHA_EXT, - GL_UNSIGNED_BYTE, NULL); - #else - glTexImage2D(GL_TEXTURE_2D, - 0, GL_SRGB8_ALPHA8, - gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - #endif - } - else - #endif - { - #ifdef HAVE_OPENGLES2 - glTexImage2D(GL_TEXTURE_2D, - 0, GL_RGBA, - gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - #else - /* Avoid potential performance - * reductions on particular platforms. */ - glTexImage2D(GL_TEXTURE_2D, - 0, RARCH_GL_INTERNAL_FORMAT32, - gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, - RARCH_GL_TEXTURE_TYPE32, RARCH_GL_FORMAT32, NULL); - #endif - } - } + if (gl->fbo_feedback_enable) + { + glGenTextures(1, &gl->fbo_feedback_texture); + gl_create_fbo_texture(gl, gl->fbo_feedback_pass, gl->fbo_feedback_texture); } glBindTexture(GL_TEXTURE_2D, 0); @@ -545,10 +564,10 @@ static bool gl_create_fbo_targets(gl_t *gl) glBindTexture(GL_TEXTURE_2D, 0); glGenFramebuffers(gl->fbo_pass, gl->fbo); + GLenum status; + for (i = 0; i < gl->fbo_pass; i++) { - GLenum status; - glBindFramebuffer(RARCH_GL_FRAMEBUFFER, gl->fbo[i]); glFramebufferTexture2D(RARCH_GL_FRAMEBUFFER, RARCH_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl->fbo_texture[i], 0); @@ -558,10 +577,28 @@ static bool gl_create_fbo_targets(gl_t *gl) goto error; } + if (gl->fbo_feedback_texture) + { + glGenFramebuffers(1, &gl->fbo_feedback); + glBindFramebuffer(RARCH_GL_FRAMEBUFFER, gl->fbo_feedback); + glFramebufferTexture2D(RARCH_GL_FRAMEBUFFER, + RARCH_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl->fbo_feedback_texture, 0); + + status = glCheckFramebufferStatus(RARCH_GL_FRAMEBUFFER); + if (status != RARCH_GL_FRAMEBUFFER_COMPLETE) + goto error; + + /* Make sure the feedback textures are cleared so we don't feedback noise. */ + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + } + return true; error: glDeleteFramebuffers(gl->fbo_pass, gl->fbo); + if (gl->fbo_feedback) + glDeleteFramebuffers(1, &gl->fbo_feedback); RARCH_ERR("Failed to set up frame buffer objects. Multi-pass shading will not work.\n"); return false; } @@ -577,6 +614,16 @@ static void gl_deinit_fbo(gl_t *gl) memset(gl->fbo, 0, sizeof(gl->fbo)); gl->fbo_inited = false; gl->fbo_pass = 0; + + if (gl->fbo_feedback) + glDeleteFramebuffers(1, &gl->fbo_feedback); + if (gl->fbo_feedback_texture) + glDeleteTextures(1, &gl->fbo_feedback_texture); + + gl->fbo_feedback_enable = false; + gl->fbo_feedback_pass = -1; + gl->fbo_feedback_texture = 0; + gl->fbo_feedback = 0; } /* Set up render to texture. */ @@ -642,6 +689,20 @@ static void gl_init_fbo(gl_t *gl, unsigned fbo_width, unsigned fbo_height) gl->fbo_rect[i].width, gl->fbo_rect[i].height); } + gl->fbo_feedback_enable = gl->shader->get_feedback_pass(&gl->fbo_feedback_pass); + + if (gl->fbo_feedback_enable && gl->fbo_feedback_pass < (unsigned)gl->fbo_pass) + { + RARCH_LOG("[GL]: Creating feedback FBO %d @ %ux%u\n", i, + gl->fbo_rect[gl->fbo_feedback_pass].width, gl->fbo_rect[gl->fbo_feedback_pass].height); + } + else if (gl->fbo_feedback_enable) + { + RARCH_WARN("[GL]: Tried to create feedback FBO of pass #%u, but there are only %d FBO passes. Will use input texture as feedback texture.\n", + gl->fbo_feedback_pass, gl->fbo_pass); + gl->fbo_feedback_enable = false; + } + gl_create_fbo_textures(gl); if (!gl_create_fbo_targets(gl)) { @@ -918,42 +979,35 @@ static INLINE void gl_start_frame_fbo(gl_t *gl) #endif } -/* On resize, we might have to recreate our FBOs - * due to "Viewport" scale, and set a new viewport. */ - -static void gl_check_fbo_dimensions(gl_t *gl) +static void gl_check_fbo_dimension(gl_t *gl, unsigned i, GLuint fbo, GLuint texture, bool update_feedback) { - int i; + GLenum status; + unsigned img_width, img_height, max, pow2_size; + bool check_dimensions = false; + struct gfx_fbo_rect *fbo_rect = &gl->fbo_rect[i]; + + if (!fbo_rect) + return; + + check_dimensions = + (fbo_rect->max_img_width > fbo_rect->width) || + (fbo_rect->max_img_height > fbo_rect->height); + + if (!check_dimensions) + return; + + /* Check proactively since we might suddently + * get sizes of tex_w width or tex_h height. */ + img_width = fbo_rect->max_img_width; + img_height = fbo_rect->max_img_height; + max = img_width > img_height ? img_width : img_height; + pow2_size = next_pow2(max); + + fbo_rect->width = fbo_rect->height = pow2_size; - /* Check if we have to recreate our FBO textures. */ - for (i = 0; i < gl->fbo_pass; i++) { - GLenum status; - unsigned img_width, img_height, max, pow2_size; - bool check_dimensions = false; - struct gfx_fbo_rect *fbo_rect = &gl->fbo_rect[i]; - - if (!fbo_rect) - continue; - - check_dimensions = - (fbo_rect->max_img_width > fbo_rect->width) || - (fbo_rect->max_img_height > fbo_rect->height); - - if (!check_dimensions) - continue; - - /* Check proactively since we might suddently - * get sizes of tex_w width or tex_h height. */ - img_width = fbo_rect->max_img_width; - img_height = fbo_rect->max_img_height; - max = img_width > img_height ? img_width : img_height; - pow2_size = next_pow2(max); - - fbo_rect->width = fbo_rect->height = pow2_size; - - glBindFramebuffer(RARCH_GL_FRAMEBUFFER, gl->fbo[i]); - glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[i]); + glBindFramebuffer(RARCH_GL_FRAMEBUFFER, fbo); + glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, RARCH_GL_INTERNAL_FORMAT32, @@ -964,19 +1018,62 @@ static void gl_check_fbo_dimensions(gl_t *gl) glFramebufferTexture2D(RARCH_GL_FRAMEBUFFER, RARCH_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - gl->fbo_texture[i], 0); + texture, 0); status = glCheckFramebufferStatus(RARCH_GL_FRAMEBUFFER); if (status != RARCH_GL_FRAMEBUFFER_COMPLETE) RARCH_WARN("Failed to reinitialize FBO texture.\n"); + } - RARCH_LOG("[GL]: Recreating FBO texture #%d: %ux%u\n", - i, fbo_rect->width, fbo_rect->height); + /* Update feedback texture in-place so we avoid having to juggle two different fbo_rect structs since they get updated here. */ + if (update_feedback) + { + glBindFramebuffer(RARCH_GL_FRAMEBUFFER, gl->fbo_feedback); + glBindTexture(GL_TEXTURE_2D, gl->fbo_feedback_texture); + + glTexImage2D(GL_TEXTURE_2D, + 0, RARCH_GL_INTERNAL_FORMAT32, + fbo_rect->width, + fbo_rect->height, + 0, RARCH_GL_TEXTURE_TYPE32, + RARCH_GL_FORMAT32, NULL); + + glFramebufferTexture2D(RARCH_GL_FRAMEBUFFER, + RARCH_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + gl->fbo_feedback_texture, 0); + + status = glCheckFramebufferStatus(RARCH_GL_FRAMEBUFFER); + if (status != RARCH_GL_FRAMEBUFFER_COMPLETE) + RARCH_WARN("Failed to reinitialize FBO texture.\n"); + else + { + /* Make sure the feedback textures are cleared so we don't feedback noise. */ + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + } + } + + RARCH_LOG("[GL]: Recreating FBO texture #%d: %ux%u\n", + i, fbo_rect->width, fbo_rect->height); +} + +/* On resize, we might have to recreate our FBOs + * due to "Viewport" scale, and set a new viewport. */ + +static void gl_check_fbo_dimensions(gl_t *gl) +{ + int i; + + /* Check if we have to recreate our FBO textures. */ + for (i = 0; i < gl->fbo_pass; i++) + { + bool update_feedback = gl->fbo_feedback_enable && (unsigned)i == gl->fbo_feedback_pass; + gl_check_fbo_dimension(gl, i, gl->fbo[i], gl->fbo_texture[i], update_feedback); } } static void gl_frame_fbo(gl_t *gl, uint64_t frame_count, - const struct gfx_tex_info *tex_info) + const struct gfx_tex_info *tex_info, const struct gfx_tex_info *feedback_info) { unsigned width, height; const struct gfx_fbo_rect *prev_rect; @@ -1029,7 +1126,7 @@ static void gl_frame_fbo(gl_t *gl, uint64_t frame_count, gl->shader->set_params(gl, prev_rect->img_width, prev_rect->img_height, prev_rect->width, prev_rect->height, gl->vp.width, gl->vp.height, (unsigned int)frame_count, - tex_info, gl->prev_info, fbo_tex_info, fbo_tex_info_cnt); + tex_info, gl->prev_info, feedback_info, fbo_tex_info, fbo_tex_info_cnt); gl->coords.vertices = 4; gl->shader->set_coords(&gl->coords); @@ -1076,7 +1173,7 @@ static void gl_frame_fbo(gl_t *gl, uint64_t frame_count, prev_rect->img_width, prev_rect->img_height, prev_rect->width, prev_rect->height, gl->vp.width, gl->vp.height, (unsigned int)frame_count, - tex_info, gl->prev_info, fbo_tex_info, fbo_tex_info_cnt); + tex_info, gl->prev_info, feedback_info, fbo_tex_info, fbo_tex_info_cnt); gl->coords.vertex = gl->vertex_ptr; @@ -1417,6 +1514,17 @@ static INLINE void gl_set_prev_texture(gl_t *gl, sizeof(*tex_info) * (gl->textures - 1)); memcpy(&gl->prev_info[0], tex_info, sizeof(*tex_info)); + + /* Implement feedback by swapping out FBO/textures for FBO pass #N and feedbacks. */ + if (gl->fbo_feedback_enable) + { + GLuint tmp_fbo = gl->fbo_feedback; + GLuint tmp_tex = gl->fbo_feedback_texture; + gl->fbo_feedback = gl->fbo[gl->fbo_feedback_pass]; + gl->fbo_feedback_texture = gl->fbo_texture[gl->fbo_feedback_pass]; + gl->fbo[gl->fbo_feedback_pass] = tmp_fbo; + gl->fbo_texture[gl->fbo_feedback_pass] = tmp_tex; + } } static INLINE void gl_set_shader_viewport(gl_t *gl, unsigned shader) @@ -1633,6 +1741,22 @@ static bool gl_frame(void *data, const void *frame, gl->tex_info.tex_size[0] = gl->tex_w; gl->tex_info.tex_size[1] = gl->tex_h; + struct gfx_tex_info feedback_info = gl->tex_info; + if (gl->fbo_feedback_enable) + { + const struct gfx_fbo_rect *rect = &gl->fbo_rect[gl->fbo_feedback_pass]; + GLfloat xamt = (GLfloat)rect->img_width / rect->width; + GLfloat yamt = (GLfloat)rect->img_height / rect->height; + + feedback_info.tex = gl->fbo_feedback_texture; + feedback_info.input_size[0] = rect->img_width; + feedback_info.input_size[1] = rect->img_height; + feedback_info.tex_size[0] = rect->width; + feedback_info.tex_size[1] = rect->height; + + set_texture_coords(feedback_info.coord, xamt, yamt); + } + glClear(GL_COLOR_BUFFER_BIT); gl->shader->set_params(gl, @@ -1640,7 +1764,8 @@ static bool gl_frame(void *data, const void *frame, gl->tex_w, gl->tex_h, gl->vp.width, gl->vp.height, (unsigned int)frame_count, - &gl->tex_info, gl->prev_info, NULL, 0); + &gl->tex_info, gl->prev_info, &feedback_info, + NULL, 0); gl->coords.vertices = 4; gl->shader->set_coords(&gl->coords); @@ -1649,7 +1774,7 @@ static bool gl_frame(void *data, const void *frame, #ifdef HAVE_FBO if (gl->fbo_inited) - gl_frame_fbo(gl, frame_count, &gl->tex_info); + gl_frame_fbo(gl, frame_count, &gl->tex_info, &feedback_info); #endif gl_set_prev_texture(gl, &gl->tex_info); diff --git a/gfx/drivers/gl_common.h b/gfx/drivers/gl_common.h index 161aff5f8c..c4c21a89c6 100644 --- a/gfx/drivers/gl_common.h +++ b/gfx/drivers/gl_common.h @@ -209,6 +209,11 @@ typedef struct gl int fbo_pass; bool fbo_inited; + bool fbo_feedback_enable; + unsigned fbo_feedback_pass; + GLuint fbo_feedback; + GLuint fbo_feedback_texture; + GLuint hw_render_fbo[GFX_MAX_TEXTURES]; GLuint hw_render_depth[GFX_MAX_TEXTURES]; bool hw_render_fbo_init; diff --git a/gfx/drivers_shader/shader_gl_cg.c b/gfx/drivers_shader/shader_gl_cg.c index 556bdedc13..71d398ff6c 100644 --- a/gfx/drivers_shader/shader_gl_cg.c +++ b/gfx/drivers_shader/shader_gl_cg.c @@ -139,6 +139,7 @@ struct cg_program struct cg_fbo_params fbo[GFX_MAX_SHADERS]; struct cg_fbo_params orig; + struct cg_fbo_params feedback; struct cg_fbo_params prev[PREV_TEXTURES]; }; @@ -152,7 +153,7 @@ typedef struct cg_shader_data struct video_shader *shader; state_tracker_t *state_tracker; GLuint lut_textures[GFX_MAX_TEXTURES]; - CGparameter cg_attribs[PREV_TEXTURES + 1 + 4 + GFX_MAX_SHADERS]; + CGparameter cg_attribs[PREV_TEXTURES + 2 + 4 + GFX_MAX_SHADERS]; char cg_alias_define[GFX_MAX_SHADERS][128]; CGcontext cgCtx; } cg_shader_data_t; @@ -222,12 +223,40 @@ fallback: #define set_param_1f(param, x) \ if (param) cgGLSetParameter1f(param, x) +static void gl_cg_set_texture_info(cg_shader_data_t *cg, const struct cg_fbo_params *params, const struct gfx_tex_info *info) +{ + CGparameter param = params->tex; + if (param) + { + cgGLSetTextureParameter(param, info->tex); + cgGLEnableTextureParameter(param); + } + + set_param_2f(params->vid_size_v, + info->input_size[0], info->input_size[1]); + set_param_2f(params->vid_size_f, + info->input_size[0], info->input_size[1]); + set_param_2f(params->tex_size_v, + info->tex_size[0], info->tex_size[1]); + set_param_2f(params->tex_size_f, + info->tex_size[0], info->tex_size[1]); + + if (params->coord) + { + cgGLSetParameterPointer(params->coord, 2, + GL_FLOAT, 0, info->coord); + cgGLEnableClientState(params->coord); + cg->cg_attribs[cg->cg_attrib_idx++] = params->coord; + } +} + static void gl_cg_set_params(void *data, unsigned width, unsigned height, unsigned tex_width, unsigned tex_height, unsigned out_width, unsigned out_height, unsigned frame_count, const void *_info, const void *_prev_info, + const void *_feedback_info, const void *_fbo_info, unsigned fbo_info_cnt) { @@ -235,6 +264,7 @@ static void gl_cg_set_params(void *data, unsigned width, unsigned height, CGparameter param; const struct gfx_tex_info *info = (const struct gfx_tex_info*)_info; const struct gfx_tex_info *prev_info = (const struct gfx_tex_info*)_prev_info; + const struct gfx_tex_info *feedback_info = (const struct gfx_tex_info*)_feedback_info; const struct gfx_tex_info *fbo_info = (const struct gfx_tex_info*)_fbo_info; driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); @@ -269,57 +299,14 @@ static void gl_cg_set_params(void *data, unsigned width, unsigned height, } /* Set orig texture. */ - param = cg->prg[cg->active_idx].orig.tex; - if (param) - { - cgGLSetTextureParameter(param, info->tex); - cgGLEnableTextureParameter(param); - } + gl_cg_set_texture_info(cg, &cg->prg[cg->active_idx].orig, info); - set_param_2f(cg->prg[cg->active_idx].orig.vid_size_v, - info->input_size[0], info->input_size[1]); - set_param_2f(cg->prg[cg->active_idx].orig.vid_size_f, - info->input_size[0], info->input_size[1]); - set_param_2f(cg->prg[cg->active_idx].orig.tex_size_v, - info->tex_size[0], info->tex_size[1]); - set_param_2f(cg->prg[cg->active_idx].orig.tex_size_f, - info->tex_size[0], info->tex_size[1]); - - if (cg->prg[cg->active_idx].orig.coord) - { - cgGLSetParameterPointer(cg->prg[cg->active_idx].orig.coord, 2, - GL_FLOAT, 0, info->coord); - cgGLEnableClientState(cg->prg[cg->active_idx].orig.coord); - cg->cg_attribs[cg->cg_attrib_idx++] = cg->prg[cg->active_idx].orig.coord; - } + /* Set feedback texture. */ + gl_cg_set_texture_info(cg, &cg->prg[cg->active_idx].feedback, feedback_info); /* Set prev textures. */ for (i = 0; i < PREV_TEXTURES; i++) - { - param = cg->prg[cg->active_idx].prev[i].tex; - if (param) - { - cgGLSetTextureParameter(param, prev_info[i].tex); - cgGLEnableTextureParameter(param); - } - - set_param_2f(cg->prg[cg->active_idx].prev[i].vid_size_v, - prev_info[i].input_size[0], prev_info[i].input_size[1]); - set_param_2f(cg->prg[cg->active_idx].prev[i].vid_size_f, - prev_info[i].input_size[0], prev_info[i].input_size[1]); - set_param_2f(cg->prg[cg->active_idx].prev[i].tex_size_v, - prev_info[i].tex_size[0], prev_info[i].tex_size[1]); - set_param_2f(cg->prg[cg->active_idx].prev[i].tex_size_f, - prev_info[i].tex_size[0], prev_info[i].tex_size[1]); - - if (cg->prg[cg->active_idx].prev[i].coord) - { - cgGLSetParameterPointer(cg->prg[cg->active_idx].prev[i].coord, - 2, GL_FLOAT, 0, prev_info[i].coord); - cgGLEnableClientState(cg->prg[cg->active_idx].prev[i].coord); - cg->cg_attribs[cg->cg_attrib_idx++] = cg->prg[cg->active_idx].prev[i].coord; - } - } + gl_cg_set_texture_info(cg, &cg->prg[cg->active_idx].prev[i], &prev_info[i]); /* Set lookup textures. */ for (i = 0; i < cg->shader->luts; i++) @@ -348,32 +335,7 @@ static void gl_cg_set_params(void *data, unsigned width, unsigned height, if (cg->active_idx) { for (i = 0; i < fbo_info_cnt; i++) - { - if (cg->prg[cg->active_idx].fbo[i].tex) - { - cgGLSetTextureParameter( - cg->prg[cg->active_idx].fbo[i].tex, fbo_info[i].tex); - cgGLEnableTextureParameter(cg->prg[cg->active_idx].fbo[i].tex); - } - - set_param_2f(cg->prg[cg->active_idx].fbo[i].vid_size_v, - fbo_info[i].input_size[0], fbo_info[i].input_size[1]); - set_param_2f(cg->prg[cg->active_idx].fbo[i].vid_size_f, - fbo_info[i].input_size[0], fbo_info[i].input_size[1]); - - set_param_2f(cg->prg[cg->active_idx].fbo[i].tex_size_v, - fbo_info[i].tex_size[0], fbo_info[i].tex_size[1]); - set_param_2f(cg->prg[cg->active_idx].fbo[i].tex_size_f, - fbo_info[i].tex_size[0], fbo_info[i].tex_size[1]); - - if (cg->prg[cg->active_idx].fbo[i].coord) - { - cgGLSetParameterPointer(cg->prg[cg->active_idx].fbo[i].coord, - 2, GL_FLOAT, 0, fbo_info[i].coord); - cgGLEnableClientState(cg->prg[cg->active_idx].fbo[i].coord); - cg->cg_attribs[cg->cg_attrib_idx++] = cg->prg[cg->active_idx].fbo[i].coord; - } - } + gl_cg_set_texture_info(cg, &cg->prg[cg->active_idx].fbo[i], &fbo_info[i]); } /* #pragma parameters. */ @@ -850,6 +812,13 @@ static void set_program_attributes(cg_shader_data_t *cg, unsigned i) cg->prg[i].orig.tex_size_f = cgGetNamedParameter(cg->prg[i].fprg, "ORIG.texture_size"); cg->prg[i].orig.coord = cgGetNamedParameter(cg->prg[i].vprg, "ORIG.tex_coord"); + cg->prg[i].feedback.tex = cgGetNamedParameter(cg->prg[i].fprg, "FEEDBACK.texture"); + cg->prg[i].feedback.vid_size_v = cgGetNamedParameter(cg->prg[i].vprg, "FEEDBACK.video_size"); + cg->prg[i].feedback.vid_size_f = cgGetNamedParameter(cg->prg[i].fprg, "FEEDBACK.video_size"); + cg->prg[i].feedback.tex_size_v = cgGetNamedParameter(cg->prg[i].vprg, "FEEDBACK.texture_size"); + cg->prg[i].feedback.tex_size_f = cgGetNamedParameter(cg->prg[i].fprg, "FEEDBACK.texture_size"); + cg->prg[i].feedback.coord = cgGetNamedParameter(cg->prg[i].vprg, "FEEDBACK.tex_coord"); + if (i > 1) { char pass_str[64] = {0}; @@ -1081,6 +1050,18 @@ static unsigned gl_cg_get_prev_textures(void) return max_prev; } +static bool gl_cg_get_feedback_pass(unsigned *pass) +{ + driver_t *driver = driver_get_ptr(); + cg_shader_data_t *cg = (cg_shader_data_t*)driver->video_shader_data; + + if (!cg || cg->shader->feedback_pass < 0) + return false; + + *pass = cg->shader->feedback_pass; + return true; +} + static bool gl_cg_mipmap_input(unsigned idx) { driver_t *driver = driver_get_ptr(); @@ -1111,6 +1092,7 @@ const shader_backend_t gl_cg_backend = { gl_cg_set_coords, gl_cg_set_mvp, gl_cg_get_prev_textures, + gl_cg_get_feedback_pass, gl_cg_mipmap_input, gl_cg_get_current_shader, diff --git a/gfx/drivers_shader/shader_glsl.c b/gfx/drivers_shader/shader_glsl.c index f7242376b6..4df43ebceb 100644 --- a/gfx/drivers_shader/shader_glsl.c +++ b/gfx/drivers_shader/shader_glsl.c @@ -89,6 +89,7 @@ struct shader_uniforms int lut_texture[GFX_MAX_TEXTURES]; struct shader_uniforms_frame orig; + struct shader_uniforms_frame feedback; struct shader_uniforms_frame pass[GFX_MAX_SHADERS]; struct shader_uniforms_frame prev[PREV_TEXTURES]; }; @@ -212,7 +213,7 @@ typedef struct glsl_shader_data unsigned gl_attrib_index; GLuint gl_program[GFX_MAX_SHADERS]; GLuint gl_teximage[GFX_MAX_TEXTURES]; - GLint gl_attribs[PREV_TEXTURES + 1 + 4 + GFX_MAX_SHADERS]; + GLint gl_attribs[PREV_TEXTURES + 2 + 4 + GFX_MAX_SHADERS]; state_tracker_t *gl_state_tracker; } glsl_shader_data_t; @@ -606,6 +607,9 @@ static void find_uniforms(glsl_shader_data_t *glsl, clear_uniforms_frame(&uni->orig); find_uniforms_frame(glsl, prog, &uni->orig, "Orig"); + clear_uniforms_frame(&uni->feedback); + find_uniforms_frame(glsl, prog, &uni->feedback, "Feedback"); + if (pass > 1) { snprintf(frame_base, sizeof(frame_base), "PassPrev%u", pass); @@ -944,6 +948,7 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, unsigned frame_count, const void *_info, const void *_prev_info, + const void *_feedback_info, const void *_fbo_info, unsigned fbo_info_cnt) { GLfloat buffer[512]; @@ -954,6 +959,7 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, size_t size = 0, attribs_size = 0; const struct gfx_tex_info *info = (const struct gfx_tex_info*)_info; const struct gfx_tex_info *prev_info = (const struct gfx_tex_info*)_prev_info; + const struct gfx_tex_info *feedback_info = (const struct gfx_tex_info*)_feedback_info; const struct gfx_tex_info *fbo_info = (const struct gfx_tex_info*)_fbo_info; struct glsl_attrib *attr = (struct glsl_attrib*)attribs; driver_t *driver = driver_get_ptr(); @@ -1011,9 +1017,9 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, texunit++; } - /* Set original texture. */ if (glsl->glsl_active_index) { + /* Set original texture. */ if (uni->orig.texture >= 0) { /* Bind original texture. */ @@ -1042,6 +1048,35 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, size += 8; } + /* Set feedback texture. */ + if (uni->feedback.texture >= 0) + { + /* Bind original texture. */ + glActiveTexture(GL_TEXTURE0 + texunit); + glUniform1i(uni->feedback.texture, texunit); + glBindTexture(GL_TEXTURE_2D, feedback_info->tex); + texunit++; + } + + if (uni->feedback.texture_size >= 0) + glUniform2fv(uni->feedback.texture_size, 1, feedback_info->tex_size); + + if (uni->feedback.input_size >= 0) + glUniform2fv(uni->feedback.input_size, 1, feedback_info->input_size); + + /* Pass texture coordinates. */ + if (uni->feedback.tex_coord >= 0) + { + attr->loc = uni->feedback.tex_coord; + attr->size = 2; + attr->offset = size * sizeof(GLfloat); + attribs_size++; + attr++; + + memcpy(buffer + size, feedback_info->coord, 8 * sizeof(GLfloat)); + size += 8; + } + /* Bind FBO textures. */ for (i = 0; i < fbo_info_cnt; i++) { @@ -1350,6 +1385,17 @@ static bool gl_glsl_mipmap_input(unsigned idx) return false; } +static bool gl_glsl_get_feedback_pass(unsigned *index) +{ + driver_t *driver = driver_get_ptr(); + glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver->video_shader_data; + if (!glsl || glsl->shader->feedback_pass < 0) + return false; + + *index = glsl->shader->feedback_pass; + return true; +} + static struct video_shader *gl_glsl_get_current_shader(void) { driver_t *driver = driver_get_ptr(); @@ -1384,6 +1430,7 @@ const shader_backend_t gl_glsl_backend = { gl_glsl_set_coords, gl_glsl_set_mvp, gl_glsl_get_prev_textures, + gl_glsl_get_feedback_pass, gl_glsl_mipmap_input, gl_glsl_get_current_shader, diff --git a/gfx/drivers_shader/shader_hlsl.c b/gfx/drivers_shader/shader_hlsl.c index 369d190241..ddc2bc46a6 100644 --- a/gfx/drivers_shader/shader_hlsl.c +++ b/gfx/drivers_shader/shader_hlsl.c @@ -107,12 +107,14 @@ static void hlsl_set_params(void *data, unsigned width, unsigned height, unsigned frame_counter, const void *_info, const void *_prev_info, + const void *_feedback_info, const void *_fbo_info, unsigned fbo_info_cnt) { d3d_video_t *d3d = (d3d_video_t*)data; LPDIRECT3DDEVICE d3d_device_ptr = (LPDIRECT3DDEVICE)d3d->dev; const struct gfx_tex_info *info = (const struct gfx_tex_info*)_info; const struct gfx_tex_info *prev_info = (const struct gfx_tex_info*)_prev_info; + (void)_feedback_info; const struct gfx_tex_info *fbo_info = (const struct gfx_tex_info*)_fbo_info; driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); @@ -477,6 +479,12 @@ static bool hlsl_mipmap_input(unsigned idx) return false; } +static bool hlsl_get_feedback_pass(unsigned *idx) +{ + (void)idx; + return false; +} + static struct video_shader *hlsl_get_current_shader(void) { return NULL; @@ -494,6 +502,7 @@ const shader_backend_t hlsl_backend = { NULL, /* hlsl_set_coords */ hlsl_set_mvp, NULL, /* hlsl_get_prev_textures */ + hlsl_get_feedback_pass, hlsl_mipmap_input, hlsl_get_current_shader, diff --git a/gfx/drivers_shader/shader_null.c b/gfx/drivers_shader/shader_null.c index 6f0125e3cb..1297b4573e 100644 --- a/gfx/drivers_shader/shader_null.c +++ b/gfx/drivers_shader/shader_null.c @@ -43,6 +43,7 @@ static void shader_null_set_params(void *data, unsigned width, unsigned height, unsigned frame_count, const void *info, const void *prev_info, + const void *feedback_info, const void *fbo_info, unsigned fbo_info_cnt) { } @@ -118,6 +119,12 @@ static bool shader_null_mipmap_input(unsigned idx) return false; } +static bool shader_null_get_feedback_pass(unsigned *idx) +{ + (void)idx; + return false; +} + static struct video_shader *shader_null_get_current_shader(void) { return NULL; @@ -135,6 +142,7 @@ const shader_backend_t shader_null_backend = { shader_null_set_coords, shader_null_set_mvp, shader_null_get_prev_textures, + shader_null_get_feedback_pass, shader_null_mipmap_input, shader_null_get_current_shader, diff --git a/gfx/video_shader_driver.h b/gfx/video_shader_driver.h index b502f09479..48ffcc13c1 100644 --- a/gfx/video_shader_driver.h +++ b/gfx/video_shader_driver.h @@ -35,6 +35,7 @@ typedef struct shader_backend unsigned frame_counter, const void *info, const void *prev_info, + const void *feedback_info, const void *fbo_info, unsigned fbo_info_cnt); void (*use)(void *data, unsigned index); @@ -45,6 +46,7 @@ typedef struct shader_backend bool (*set_coords)(const void *data); bool (*set_mvp)(void *data, const math_matrix_4x4 *mat); unsigned (*get_prev_textures)(void); + bool (*get_feedback_pass)(unsigned *pass); bool (*mipmap_input)(unsigned index); struct video_shader *(*get_current_shader)(void); diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index 670d77795e..61a3dc8fbd 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -616,6 +616,9 @@ bool video_shader_read_conf_cgp(config_file_t *conf, struct video_shader *shader return false; } + if (!config_get_int(conf, "feedback_pass", &shader->feedback_pass)) + shader->feedback_pass = -1; + shader->passes = min(shaders, GFX_MAX_SHADERS); for (i = 0; i < shader->passes; i++) { @@ -771,6 +774,8 @@ void video_shader_write_conf_cgp(config_file_t *conf, unsigned i; config_set_int(conf, "shaders", shader->passes); + if (shader->feedback_pass >= 0) + config_set_int(conf, "feedback_pass", shader->feedback_pass); for (i = 0; i < shader->passes; i++) { diff --git a/gfx/video_shader_parse.h b/gfx/video_shader_parse.h index a3502badec..8b8c0ebd3e 100644 --- a/gfx/video_shader_parse.h +++ b/gfx/video_shader_parse.h @@ -150,6 +150,10 @@ struct video_shader char script_path[PATH_MAX_LENGTH]; char *script; /* Dynamically allocated. Must be free'd. Only used by XML. */ char script_class[512]; + + /* If < 0, no feedback pass is used. Otherwise, + * the FBO after pass #N is passed a texture to next frame. */ + int feedback_pass; }; /** diff --git a/tools/cg2glsl.py b/tools/cg2glsl.py index a412673879..63bea006fb 100755 --- a/tools/cg2glsl.py +++ b/tools/cg2glsl.py @@ -246,6 +246,7 @@ def translate_varying(cg): 'IN.vertex_coord': 'VertexCoord', 'IN.lut_tex_coord': 'LUTTexCoord', 'ORIG.tex_coord': 'OrigTexCoord', + 'FEEDBACK.tex_coord': 'FeedbackTexCoord', 'PREV.tex_coord': 'PrevTexCoord', 'PREV1.tex_coord': 'Prev1TexCoord', 'PREV2.tex_coord': 'Prev2TexCoord', @@ -276,6 +277,7 @@ def translate_varying(cg): def translate_texture_size(cg): translations = { 'ORIG.texture_size': 'OrigTextureSize', + 'FEEDBACK.texture_size': 'FeedbackTextureSize', 'PREV.texture_size': 'PrevTextureSize', 'PREV1.texture_size': 'Prev1TextureSize', 'PREV2.texture_size': 'Prev2TextureSize', @@ -299,6 +301,7 @@ def translate_texture_size(cg): 'PASSPREV7.texture_size': 'PassPrev7TextureSize', 'PASSPREV8.texture_size': 'PassPrev8TextureSize', 'ORIG.video_size': 'OrigInputSize', + 'FEEDBACK.video_size': 'FeedbackInputSize', 'PREV.video_size': 'PrevInputSize', 'PREV1.video_size': 'Prev1InputSize', 'PREV2.video_size': 'Prev2InputSize', @@ -451,6 +454,7 @@ def replace_global_fragment(source): def translate_texture(cg): translations = { 'ORIG.texture': 'OrigTexture', + 'FEEDBACK.texture': 'FeedbackTexture', 'PREV.texture': 'PrevTexture', 'PREV1.texture': 'Prev1Texture', 'PREV2.texture': 'Prev2Texture',