Add support for shader pass feedback.

This commit is contained in:
CautiousAlbino 2015-08-26 14:21:24 +02:00
parent 2fdaa89a81
commit aee5e74001
10 changed files with 402 additions and 211 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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++)
{

View File

@ -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;
};
/**

View File

@ -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',