From: Andrew Wesie Subject: [v2 1/3] wined3d: Implement return instruction. Message-Id: <1479447962-13489-1-git-send-email-awesie@gmail.com> Date: Thu, 17 Nov 2016 23:46:00 -0600 A return instruction may occur inside of a conditional or loop, and we need to output a GLSL return instruction, and possibly an epilogue. Some shaders may not end with a return instruction, in which case we pretend there was one. Signed-off-by: Andrew Wesie --- dlls/wined3d/glsl_shader.c | 94 +++++++++++++++++++++++++++++++--------------- dlls/wined3d/shader.c | 11 ++++++ 2 files changed, 75 insertions(+), 30 deletions(-) diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 9e9c83b..9af8fc5 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -270,6 +270,9 @@ struct glsl_ffp_destroy_ctx const struct wined3d_gl_info *gl_info; }; +static void shader_glsl_epilogue_ps(const struct wined3d_shader_context *ctx); +static void shader_glsl_epilogue_vs(const struct wined3d_shader_context *ctx); + static const char *debug_gl_shader_type(GLenum type) { switch (type) @@ -4461,9 +4464,21 @@ static void shader_glsl_callnz(const struct wined3d_shader_instruction *ins) static void shader_glsl_ret(const struct wined3d_shader_instruction *ins) { - /* No-op. The closing } is written when a new function is started, and at the end of the shader. This - * function only suppresses the unhandled instruction warning - */ + const struct wined3d_shader_version *version = &ins->ctx->shader->reg_maps.shader_version; + + switch(version->type) + { + case WINED3D_SHADER_TYPE_PIXEL: + shader_glsl_epilogue_ps(ins->ctx); + break; + case WINED3D_SHADER_TYPE_VERTEX: + shader_glsl_epilogue_vs(ins->ctx); + break; + default: + break; + } + + shader_addline(ins->ctx->buffer, "return;\n"); } /********************************************* @@ -5995,25 +6010,34 @@ static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context /* Base Shader Body */ shader_generate_main(shader, buffer, reg_maps, function, &priv_ctx); + shader_addline(buffer, "}\n"); + + TRACE("Compiling shader object %u.\n", shader_id); + shader_glsl_compile(gl_info, shader_id, buffer->buffer); + + return shader_id; +} + +static void shader_glsl_epilogue_ps(const struct wined3d_shader_context *ctx) +{ + const struct wined3d_shader *shader = ctx->shader; + const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps; + const struct wined3d_gl_info *gl_info = ctx->gl_info; + const struct shader_glsl_ctx_priv *priv = ctx->backend_data; + const struct ps_compile_args *args = priv->cur_ps_args; + /* Pixel shaders < 2.0 place the resulting color in R0 implicitly */ if (reg_maps->shader_version.major < 2) - shader_addline(buffer, "%s[0] = R0;\n", get_fragment_output(gl_info)); + shader_addline(ctx->buffer, "%s[0] = R0;\n", get_fragment_output(gl_info)); if (args->srgb_correction) - shader_glsl_generate_srgb_write_correction(buffer, gl_info); + shader_glsl_generate_srgb_write_correction(ctx->buffer, gl_info); /* SM < 3 does not replace the fog stage. */ if (reg_maps->shader_version.major < 3) - shader_glsl_generate_fog_code(buffer, gl_info, args->fog); - - shader_glsl_generate_alpha_test(buffer, gl_info, args->alpha_test_func + 1); - - shader_addline(buffer, "}\n"); - - TRACE("Compiling shader object %u.\n", shader_id); - shader_glsl_compile(gl_info, shader_id, buffer->buffer); + shader_glsl_generate_fog_code(ctx->buffer, gl_info, args->fog); - return shader_id; + shader_glsl_generate_alpha_test(ctx->buffer, gl_info, args->alpha_test_func + 1); } /* Context activation is done by the caller. */ @@ -6024,10 +6048,8 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps; struct wined3d_string_buffer *buffer = &priv->shader_buffer; const struct wined3d_gl_info *gl_info = context->gl_info; - BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT]; const DWORD *function = shader->function; struct shader_glsl_ctx_priv priv_ctx; - unsigned int i; /* Create the hw GLSL shader program and assign it as the shader->prgId */ GLuint shader_id = GL_EXTCALL(glCreateShader(GL_VERTEX_SHADER)); @@ -6063,8 +6085,26 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context /* Base Shader Body */ shader_generate_main(shader, buffer, reg_maps, function, &priv_ctx); + shader_addline(buffer, "}\n"); + + TRACE("Compiling shader object %u.\n", shader_id); + shader_glsl_compile(gl_info, shader_id, buffer->buffer); + + return shader_id; +} + +static void shader_glsl_epilogue_vs(const struct wined3d_shader_context *ctx) +{ + const struct wined3d_shader *shader = ctx->shader; + const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps; + const struct wined3d_gl_info *gl_info = ctx->gl_info; + const struct shader_glsl_ctx_priv *priv = ctx->backend_data; + const struct vs_compile_args *args = priv->cur_vs_args; + BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT]; + unsigned int i; + /* Unpack outputs */ - shader_addline(buffer, "setup_vs_output(vs_out);\n"); + shader_addline(ctx->buffer, "setup_vs_output(vs_out);\n"); /* The D3DRS_FOGTABLEMODE render state defines if the shader-generated fog coord is used * or if the fragment depth is used. If the fragment depth is used(FOGTABLEMODE != NONE), @@ -6074,10 +6114,10 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context if (reg_maps->shader_version.major < 3) { if (args->fog_src == VS_FOG_Z) - shader_addline(buffer, "%s = gl_Position.z;\n", + shader_addline(ctx->buffer, "%s = gl_Position.z;\n", legacy_context ? "gl_FogFragCoord" : "ffp_varying_fogcoord"); else if (!reg_maps->fog) - shader_addline(buffer, "%s = 0.0;\n", + shader_addline(ctx->buffer, "%s = 0.0;\n", legacy_context ? "gl_FogFragCoord" : "ffp_varying_fogcoord"); } @@ -6085,26 +6125,20 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context if (args->clip_enabled) { if (legacy_context) - shader_addline(buffer, "gl_ClipVertex = gl_Position;\n"); + shader_addline(ctx->buffer, "gl_ClipVertex = gl_Position;\n"); else for (i = 0; i < gl_info->limits.user_clip_distances; ++i) - shader_addline(buffer, "gl_ClipDistance[%u] = dot(gl_Position, clip_planes[%u]);\n", i, i); + shader_addline(ctx->buffer, "gl_ClipDistance[%u] = dot(gl_Position, clip_planes[%u]);\n", i, i); } if (args->point_size && !args->per_vertex_point_size) - shader_addline(buffer, "gl_PointSize = clamp(ffp_point.size, ffp_point.size_min, ffp_point.size_max);\n"); + shader_addline(ctx->buffer, "gl_PointSize = clamp(ffp_point.size, ffp_point.size_min, ffp_point.size_max);\n"); if (args->next_shader_type == WINED3D_SHADER_TYPE_PIXEL && !gl_info->supported[ARB_CLIP_CONTROL]) - shader_glsl_fixup_position(buffer); - - shader_addline(buffer, "}\n"); - - TRACE("Compiling shader object %u.\n", shader_id); - shader_glsl_compile(gl_info, shader_id, buffer->buffer); - - return shader_id; + shader_glsl_fixup_position(ctx->buffer); } + /* Context activation is done by the caller. */ static GLuint shader_glsl_generate_geometry_shader(const struct wined3d_context *context, struct shader_glsl_priv *priv, const struct wined3d_shader *shader, const struct gs_compile_args *args) diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index 61509d9..592e53b 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2028,6 +2028,7 @@ void shader_generate_main(const struct wined3d_shader *shader, struct wined3d_st struct wined3d_shader_tex_mx tex_mx; struct wined3d_shader_context ctx; const DWORD *ptr = byte_code; + enum WINED3D_SHADER_INSTRUCTION_HANDLER last_opcode = WINED3DSIH_TABLE_SIZE; /* Initialize current parsing state. */ tex_mx.current_row = 0; @@ -2062,6 +2063,16 @@ void shader_generate_main(const struct wined3d_shader *shader, struct wined3d_st /* Call appropriate function for output target */ device->shader_backend->shader_handle_instruction(&ins); + last_opcode = ins.handler_idx; + } + + if (last_opcode != WINED3DSIH_RET) + { + /* Force a return instruction at the end of function body. */ + memset(&ins, 0, sizeof(ins)); + ins.ctx = &ctx; + ins.handler_idx = WINED3DSIH_RET; + device->shader_backend->shader_handle_instruction(&ins); } } -- 2.7.4