diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 4b35c947b3b..1a49aa69068 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -3809,7 +3809,7 @@ static GLuint shader_arb_generate_pshader(const struct wined3d_shader *shader, } /* Base Shader Body */ - if (FAILED(shader_generate_main(shader, buffer, reg_maps, &priv_ctx))) + if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, NULL, NULL))) return 0; if(args->super.srgb_correction) { @@ -4223,7 +4223,7 @@ static GLuint shader_arb_generate_vshader(const struct wined3d_shader *shader, /* The shader starts with the main function */ priv_ctx.in_main_func = TRUE; /* Base Shader Body */ - if (FAILED(shader_generate_main(shader, buffer, reg_maps, &priv_ctx))) + if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, NULL, NULL))) return -1; if (!priv_ctx.footer_written) vshader_add_footer(&priv_ctx, diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index f2fde11a24c..39aaba1e17a 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -177,6 +177,12 @@ struct glsl_vs_program GLint clip_planes_location; }; +struct glsl_hs_program +{ + struct list shader_entry; + GLuint id; +}; + struct glsl_ds_program { struct list shader_entry; @@ -228,6 +234,7 @@ struct glsl_shader_prog_link { struct wine_rb_entry program_lookup_entry; struct glsl_vs_program vs; + struct glsl_hs_program hs; struct glsl_ds_program ds; struct glsl_gs_program gs; struct glsl_ps_program ps; @@ -240,6 +247,7 @@ struct glsl_shader_prog_link struct glsl_program_key { GLuint vs_id; + GLuint hs_id; GLuint ds_id; GLuint gs_id; GLuint ps_id; @@ -273,6 +281,11 @@ struct glsl_vs_compiled_shader GLuint id; }; +struct glsl_hs_compiled_shader +{ + GLuint id; +}; + struct glsl_ds_compiled_shader { struct ds_compile_args args; @@ -295,6 +308,7 @@ struct glsl_shader_private union { struct glsl_vs_compiled_shader *vs; + struct glsl_hs_compiled_shader *hs; struct glsl_ds_compiled_shader *ds; struct glsl_gs_compiled_shader *gs; struct glsl_ps_compiled_shader *ps; @@ -6476,6 +6490,7 @@ static void add_glsl_program_entry(struct shader_glsl_priv *priv, struct glsl_sh struct glsl_program_key key; key.vs_id = entry->vs.id; + key.hs_id = entry->hs.id; key.ds_id = entry->ds.id; key.gs_id = entry->gs.id; key.ps_id = entry->ps.id; @@ -6505,6 +6520,8 @@ static void delete_glsl_program_entry(struct shader_glsl_priv *priv, const struc GL_EXTCALL(glDeleteProgram(entry->id)); if (entry->vs.id) list_remove(&entry->vs.shader_entry); + if (entry->hs.id) + list_remove(&entry->hs.shader_entry); if (entry->ds.id) list_remove(&entry->ds.shader_entry); if (entry->gs.id) @@ -7240,7 +7257,7 @@ static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context shader_glsl_input_pack(shader, buffer, &shader->input_signature, reg_maps, args, gl_info); /* Base Shader Body */ - if (FAILED(shader_generate_main(shader, buffer, reg_maps, &priv_ctx))) + if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, NULL, NULL))) return 0; /* In SM4+ the shader epilogue is generated by the "ret" instruction. */ @@ -7366,7 +7383,7 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context shader_addline(buffer, "void main()\n{\n"); /* Base Shader Body */ - if (FAILED(shader_generate_main(shader, buffer, reg_maps, &priv_ctx))) + if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, NULL, NULL))) return 0; /* In SM4+ the shader epilogue is generated by the "ret" instruction. */ @@ -7382,6 +7399,104 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context return shader_id; } +static void shader_glsl_generate_default_control_point_phase(const struct wined3d_shader *shader, + struct wined3d_string_buffer *buffer, const struct wined3d_shader_reg_maps *reg_maps) +{ + const struct wined3d_shader_signature *output_signature = &shader->output_signature; + char reg_mask[6]; + unsigned int i; + + for (i = 0; i < output_signature->element_count; ++i) + { + const struct wined3d_shader_signature_element *output = &output_signature->elements[i]; + + shader_glsl_write_mask_to_str(output->mask, reg_mask); + shader_addline(buffer, "shader_out[gl_InvocationID].reg[%u]%s = shader_in[gl_InvocationID].reg[%u]%s;\n", + output->register_idx, reg_mask, output->register_idx, reg_mask); + } +} + +static GLuint shader_glsl_generate_hull_shader(const struct wined3d_context *context, + struct shader_glsl_priv *priv, const struct wined3d_shader *shader) +{ + struct wined3d_string_buffer_list *string_buffers = &priv->string_buffers; + 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; + const struct wined3d_hull_shader *hs = &shader->u.hs; + const struct wined3d_shader_phase *phase; + struct shader_glsl_ctx_priv priv_ctx; + GLuint shader_id; + unsigned int i; + + memset(&priv_ctx, 0, sizeof(priv_ctx)); + priv_ctx.string_buffers = string_buffers; + + shader_glsl_add_version_declaration(buffer, gl_info); + + shader_glsl_enable_extensions(buffer, gl_info); + shader_addline(buffer, "#extension GL_ARB_tessellation_shader : enable\n"); + + shader_generate_glsl_declarations(context, buffer, shader, reg_maps, &priv_ctx); + + shader_addline(buffer, "layout(vertices = %u) out;\n", hs->output_vertex_count); + + shader_addline(buffer, "in shader_in_out { vec4 reg[%u]; } shader_in[];\n", shader->limits->packed_input); + shader_addline(buffer, "out shader_in_out { vec4 reg[%u]; } shader_out[];\n", shader->limits->packed_output); + + shader_addline(buffer, "void hs_control_point_phase()\n{\n"); + if ((phase = hs->phases.control_point)) + { + if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, phase->start, phase->end))) + return 0; + } + else + { + shader_glsl_generate_default_control_point_phase(shader, buffer, reg_maps); + } + shader_addline(buffer, "}\n"); + + for (i = 0; i < hs->phases.fork_count; ++i) + { + phase = &hs->phases.fork[i]; + shader_addline(buffer, "void hs_fork_phase%u()\n{\n", i); + if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, phase->start, phase->end))) + return 0; + shader_addline(buffer, "}\n"); + } + + for (i = 0; i < hs->phases.join_count; ++i) + { + phase = &hs->phases.join[i]; + shader_addline(buffer, "void hs_join_phase%u()\n{\n", i); + if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, phase->start, phase->end))) + return 0; + shader_addline(buffer, "}\n"); + } + + shader_addline(buffer, "void main()\n{\n"); + shader_addline(buffer, "hs_control_point_phase();\n"); + if (hs->phases.fork_count || hs->phases.join_count) + shader_addline(buffer, "barrier();\n"); + for (i = 0; i < hs->phases.fork_count; ++i) + { + phase = &hs->phases.fork[i]; + shader_addline(buffer, "hs_fork_phase%u();\n", i); + } + for (i = 0; i < hs->phases.join_count; ++i) + { + phase = &hs->phases.join[i]; + shader_addline(buffer, "hs_join_phase%u();\n", i); + } + shader_addline(buffer, "}\n"); + + shader_id = GL_EXTCALL(glCreateShader(GL_TESS_CONTROL_SHADER)); + TRACE("Compiling shader object %u.\n", shader_id); + shader_glsl_compile(gl_info, shader_id, buffer->buffer); + + return shader_id; +} + static void shader_glsl_generate_ds_epilogue(const struct wined3d_gl_info *gl_info, struct wined3d_string_buffer *buffer, const struct wined3d_shader *shader, const struct ds_compile_args *args) @@ -7470,7 +7585,7 @@ static GLuint shader_glsl_generate_domain_shader(const struct wined3d_context *c args->next_shader_type == WINED3D_SHADER_TYPE_PIXEL); shader_addline(buffer, "void main()\n{\n"); - if (FAILED(shader_generate_main(shader, buffer, reg_maps, &priv_ctx))) + if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, NULL, NULL))) return 0; shader_addline(buffer, "}\n"); @@ -7515,7 +7630,7 @@ static GLuint shader_glsl_generate_geometry_shader(const struct wined3d_context shader_glsl_generate_sm4_output_setup(priv, shader, args->output_count, gl_info, TRUE); shader_addline(buffer, "void main()\n{\n"); - if (FAILED(shader_generate_main(shader, buffer, reg_maps, &priv_ctx))) + if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, NULL, NULL))) return 0; shader_addline(buffer, "}\n"); @@ -7585,7 +7700,7 @@ static GLuint shader_glsl_generate_compute_shader(const struct wined3d_context * thread_group_size->x, thread_group_size->y, thread_group_size->z); shader_addline(buffer, "void main()\n{\n"); - shader_generate_main(shader, buffer, reg_maps, &priv_ctx); + shader_generate_code(shader, buffer, reg_maps, &priv_ctx, NULL, NULL); shader_addline(buffer, "}\n"); shader_id = GL_EXTCALL(glCreateShader(GL_COMPUTE_SHADER)); @@ -7754,6 +7869,52 @@ static GLuint find_glsl_vshader(const struct wined3d_context *context, struct sh return ret; } +static GLuint find_glsl_hull_shader(const struct wined3d_context *context, + struct shader_glsl_priv *priv, struct wined3d_shader *shader) +{ + struct glsl_hs_compiled_shader *gl_shaders, *new_array; + struct glsl_shader_private *shader_data; + unsigned int new_size; + GLuint ret; + + if (!shader->backend_data) + { + if (!(shader->backend_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*shader_data)))) + { + ERR("Failed to allocate backend data.\n"); + return 0; + } + } + shader_data = shader->backend_data; + gl_shaders = shader_data->gl_shaders.hs; + + if (shader_data->num_gl_shaders > 0) + { + assert(shader_data->num_gl_shaders == 1); + return gl_shaders[0].id; + } + + TRACE("No matching GL shader found for shader %p, compiling a new shader.\n", shader); + + assert(!shader_data->gl_shaders.hs); + new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array)); + new_size = 1; + if (!new_array) + { + ERR("Failed to allocate GL shaders array.\n"); + return 0; + } + shader_data->gl_shaders.hs = new_array; + shader_data->shader_array_size = new_size; + gl_shaders = new_array; + + string_buffer_clear(&priv->shader_buffer); + ret = shader_glsl_generate_hull_shader(context, priv, shader); + gl_shaders[shader_data->num_gl_shaders++].id = ret; + + return ret; +} + static GLuint find_glsl_domain_shader(const struct wined3d_context *context, struct shader_glsl_priv *priv, struct wined3d_shader *shader, const struct ds_compile_args *args) { @@ -9221,6 +9382,7 @@ static HRESULT shader_glsl_compile_compute_shader(struct shader_glsl_priv *priv, entry->id = program_id; entry->vs.id = 0; + entry->hs.id = 0; entry->ds.id = 0; entry->gs.id = 0; entry->ps.id = 0; @@ -9304,7 +9466,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const const struct wined3d_d3d_info *d3d_info = context->d3d_info; const struct ps_np2fixup_info *np2fixup_info = NULL; struct glsl_shader_prog_link *entry = NULL; - struct wined3d_shader *dshader, *gshader; + struct wined3d_shader *hshader, *dshader, *gshader; struct wined3d_shader *vshader = NULL; struct wined3d_shader *pshader = NULL; GLuint reorder_shader_id = 0; @@ -9312,6 +9474,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const GLuint program_id; unsigned int i; GLuint vs_id = 0; + GLuint hs_id = 0; GLuint ds_id = 0; GLuint gs_id = 0; GLuint ps_id = 0; @@ -9348,6 +9511,12 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const vs_list = &ffp_shader->linked_programs; } + hshader = state->shader[WINED3D_SHADER_TYPE_HULL]; + if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_HULL)) && ctx_data->glsl_program) + hs_id = ctx_data->glsl_program->hs.id; + else if (hshader) + hs_id = find_glsl_hull_shader(context, priv, hshader); + dshader = state->shader[WINED3D_SHADER_TYPE_DOMAIN]; if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_DOMAIN)) && ctx_data->glsl_program) { @@ -9404,11 +9573,12 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const } key.vs_id = vs_id; + key.hs_id = hs_id; key.ds_id = ds_id; key.gs_id = gs_id; key.ps_id = ps_id; key.cs_id = 0; - if ((!vs_id && !ds_id && !gs_id && !ps_id) || (entry = get_glsl_program_entry(priv, &key))) + if ((!vs_id && !hs_id && !ds_id && !gs_id && !ps_id) || (entry = get_glsl_program_entry(priv, &key))) { ctx_data->glsl_program = entry; return; @@ -9422,6 +9592,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const entry = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link)); entry->id = program_id; entry->vs.id = vs_id; + entry->hs.id = hs_id; entry->ds.id = ds_id; entry->gs.id = gs_id; entry->ps.id = ps_id; @@ -9503,6 +9674,15 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const } } + if (hshader) + { + TRACE("Attaching GLSL tessellation control shader object %u to program %u.\n", hs_id, program_id); + GL_EXTCALL(glAttachShader(program_id, hs_id)); + checkGLcall("glAttachShader"); + + list_add_head(&hshader->linked_programs, &entry->hs.shader_entry); + } + if (dshader) { TRACE("Attaching GLSL tessellation evaluation shader object %u to program %u.\n", ds_id, program_id); @@ -9619,6 +9799,9 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const if (entry->vs.pointsize_min_location != -1) entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_POINTSIZE; + if (hshader) + shader_glsl_load_program_resources(context, priv, program_id, hshader); + if (dshader) { if (entry->ds.pos_fixup_location != -1) @@ -9899,6 +10082,28 @@ static void shader_glsl_destroy(struct wined3d_shader *shader) break; } + case WINED3D_SHADER_TYPE_HULL: + { + struct glsl_hs_compiled_shader *gl_shaders = shader_data->gl_shaders.hs; + + for (i = 0; i < shader_data->num_gl_shaders; ++i) + { + TRACE("Deleting hull shader %u.\n", gl_shaders[i].id); + GL_EXTCALL(glDeleteShader(gl_shaders[i].id)); + checkGLcall("glDeleteShader"); + } + HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders.hs); + + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs, + struct glsl_shader_prog_link, hs.shader_entry) + { + shader_glsl_invalidate_contexts_program(device, entry); + delete_glsl_program_entry(priv, gl_info, entry); + } + + break; + } + case WINED3D_SHADER_TYPE_DOMAIN: { struct glsl_ds_compiled_shader *gl_shaders = shader_data->gl_shaders.ds; @@ -9992,6 +10197,9 @@ static int glsl_program_key_compare(const void *key, const struct wine_rb_entry if (k->ps_id > prog->ps.id) return 1; else if (k->ps_id < prog->ps.id) return -1; + if (k->hs_id > prog->hs.id) return 1; + else if (k->hs_id < prog->hs.id) return -1; + if (k->ds_id > prog->ds.id) return 1; else if (k->ds_id < prog->ds.id) return -1; diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index 146ad636976..113e46161b6 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2418,10 +2418,10 @@ static void shader_dump_src_param(struct wined3d_string_buffer *buffer, } } -/* Shared code in order to generate the bulk of the shader string. - * NOTE: A description of how to parse tokens can be found on MSDN. */ -HRESULT shader_generate_main(const struct wined3d_shader *shader, struct wined3d_string_buffer *buffer, - const struct wined3d_shader_reg_maps *reg_maps, void *backend_ctx) +/* Shared code in order to generate the bulk of the shader string. */ +HRESULT shader_generate_code(const struct wined3d_shader *shader, struct wined3d_string_buffer *buffer, + const struct wined3d_shader_reg_maps *reg_maps, void *backend_ctx, + const DWORD *start, const DWORD *end) { struct wined3d_device *device = shader->device; const struct wined3d_shader_frontend *fe = shader->frontend; @@ -2449,8 +2449,10 @@ HRESULT shader_generate_main(const struct wined3d_shader *shader, struct wined3d ins.ctx = &ctx; fe->shader_read_header(fe_data, &ptr, &shader_version); + if (start) + ptr = start; - while (!fe->shader_is_end(fe_data, &ptr)) + while (!fe->shader_is_end(fe_data, &ptr) && ptr != end) { /* Read opcode. */ fe->shader_read_instruction(fe_data, &ptr, &ins); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index f33f0e0a894..dd6f62184bd 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3833,8 +3833,9 @@ BOOL string_buffer_init(struct wined3d_string_buffer *buffer) DECLSPEC_HIDDEN; void string_buffer_free(struct wined3d_string_buffer *buffer) DECLSPEC_HIDDEN; unsigned int shader_find_free_input_register(const struct wined3d_shader_reg_maps *reg_maps, unsigned int max) DECLSPEC_HIDDEN; -HRESULT shader_generate_main(const struct wined3d_shader *shader, struct wined3d_string_buffer *buffer, - const struct wined3d_shader_reg_maps *reg_maps, void *backend_ctx) DECLSPEC_HIDDEN; +HRESULT shader_generate_code(const struct wined3d_shader *shader, struct wined3d_string_buffer *buffer, + const struct wined3d_shader_reg_maps *reg_maps, void *backend_ctx, + const DWORD *start, const DWORD *end) DECLSPEC_HIDDEN; BOOL shader_match_semantic(const char *semantic_name, enum wined3d_decl_usage usage) DECLSPEC_HIDDEN; static inline BOOL shader_is_scalar(const struct wined3d_shader_register *reg)