From: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com --- dlls/wined3d/glsl_shader.c | 148 +++++++++++++++++++++++++++++++++++---------- dlls/wined3d/utils.c | 2 +- 2 files changed, 118 insertions(+), 32 deletions(-)
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 2acb202abc0..64a2604ab7d 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -12267,6 +12267,7 @@ struct wined3d_glsl_blitter struct wined3d_blitter blitter; struct wined3d_string_buffer_list string_buffers; struct wine_rb_tree programs; + GLuint palette_texture; };
static int glsl_blitter_args_compare(const void *key, const struct wine_rb_entry *entry) @@ -12292,6 +12293,7 @@ static void glsl_free_blitter_program(struct wine_rb_entry *entry, void *ctx) /* Context activation is done by the caller. */ static void glsl_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) { + const struct wined3d_gl_info *gl_info = context->gl_info; struct wined3d_glsl_blitter *glsl_blitter; struct wined3d_blitter *next;
@@ -12300,12 +12302,44 @@ static void glsl_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d
glsl_blitter = CONTAINING_RECORD(blitter, struct wined3d_glsl_blitter, blitter);
+ if (glsl_blitter->palette_texture) + gl_info->gl_ops.gl.p_glDeleteTextures(1, &glsl_blitter->palette_texture); + wine_rb_destroy(&glsl_blitter->programs, glsl_free_blitter_program, context); string_buffer_list_cleanup(&glsl_blitter->string_buffers);
heap_free(glsl_blitter); }
+static void glsl_blitter_generate_p8_shader(struct wined3d_string_buffer *buffer, + const struct wined3d_gl_info *gl_info, const struct glsl_blitter_args *args, + const char *output, const char *tex_type, const char *swizzle) +{ + shader_addline(buffer, "uniform sampler1D sampler_palette;\n"); + shader_addline(buffer, "\nvoid main()\n{\n"); + /* The alpha-component contains the palette index. */ + shader_addline(buffer, " float index = texture%s(sampler, out_texcoord.%s).w;\n", + needs_legacy_glsl_syntax(gl_info) ? tex_type : "", swizzle); + /* Scale the index by 255/256 and add a bias of 0.5 in order to sample in + * the middle. */ + shader_addline(buffer, " index = (index * 255.0 + 0.5) / 256.0;\n"); + shader_addline(buffer, " %s = texture%s(sampler_palette, index);\n", + output, needs_legacy_glsl_syntax(gl_info) ? "1D" : ""); + shader_addline(buffer, "}\n"); +} + +static void glsl_blitter_generate_plain_shader(struct wined3d_string_buffer *buffer, + const struct wined3d_gl_info *gl_info, const struct glsl_blitter_args *args, + const char *output, const char *tex_type, const char *swizzle) +{ + shader_addline(buffer, "\nvoid main()\n{\n"); + shader_addline(buffer, " %s = texture%s(sampler, out_texcoord.%s);\n", + output, needs_legacy_glsl_syntax(gl_info) ? tex_type : "", swizzle); + shader_glsl_color_correction_ext(buffer, output, WINED3DSP_WRITEMASK_ALL, args->fixup); + shader_addline(buffer, "}\n"); +} + +/* Context activation is done by the caller. */ static GLuint glsl_blitter_generate_program(struct wined3d_glsl_blitter *blitter, const struct wined3d_gl_info *gl_info, const struct glsl_blitter_args *args) { @@ -12328,14 +12362,12 @@ static GLuint glsl_blitter_generate_program(struct wined3d_glsl_blitter *blitter " gl_Position = vec4(pos, 0.0, 1.0);\n" " out_texcoord = texcoord;\n" "}\n"; - static const char fshader_header[] = - "\n" - "void main()\n" - "{\n"; - struct wined3d_string_buffer *buffer, *string; + enum complex_fixup complex_fixup = get_complex_fixup(args->fixup); + struct wined3d_string_buffer *buffer, *output; GLuint program, vshader_id, fshader_id; const char *tex_type, *swizzle, *ptr; unsigned int i; + GLint loc;
for (i = 0; i < ARRAY_SIZE(texture_data); ++i) { @@ -12377,14 +12409,15 @@ static GLuint glsl_blitter_generate_program(struct wined3d_glsl_blitter *blitter if (!needs_legacy_glsl_syntax(gl_info)) shader_addline(buffer, "out vec4 ps_out[1];\n");
- shader_addline(buffer, fshader_header); - string = string_buffer_get(&blitter->string_buffers); - string_buffer_sprintf(string, "%s[0]", get_fragment_output(gl_info)); - shader_addline(buffer, " %s = texture%s(sampler, out_texcoord.%s);\n", - string->buffer, needs_legacy_glsl_syntax(gl_info) ? tex_type : "", swizzle); - shader_glsl_color_correction_ext(buffer, string->buffer, WINED3DSP_WRITEMASK_ALL, args->fixup); - string_buffer_release(&blitter->string_buffers, string); - shader_addline(buffer, "}\n"); + output = string_buffer_get(&blitter->string_buffers); + string_buffer_sprintf(output, "%s[0]", get_fragment_output(gl_info)); + + if (complex_fixup == COMPLEX_FIXUP_P8) + glsl_blitter_generate_p8_shader(buffer, gl_info, args, output->buffer, tex_type, swizzle); + else + glsl_blitter_generate_plain_shader(buffer, gl_info, args, output->buffer, tex_type, swizzle); + + string_buffer_release(&blitter->string_buffers, output);
ptr = buffer->buffer; GL_EXTCALL(glShaderSource(fshader_id, 1, &ptr, NULL)); @@ -12404,15 +12437,61 @@ static GLuint glsl_blitter_generate_program(struct wined3d_glsl_blitter *blitter print_glsl_info_log(gl_info, fshader_id, FALSE); GL_EXTCALL(glLinkProgram(program)); shader_glsl_validate_link(gl_info, program); + + GL_EXTCALL(glUseProgram(program)); + loc = GL_EXTCALL(glGetUniformLocation(program, "sampler")); + GL_EXTCALL(glUniform1i(loc, 0)); + if (complex_fixup == COMPLEX_FIXUP_P8) + { + loc = GL_EXTCALL(glGetUniformLocation(program, "sampler_palette")); + GL_EXTCALL(glUniform1i(loc, 1)); + } + return program; }
/* Context activation is done by the caller. */ -static GLuint glsl_blitter_get_program(struct wined3d_glsl_blitter *blitter, +static void glsl_blitter_upload_palette(struct wined3d_glsl_blitter *blitter, + struct wined3d_context *context, const struct wined3d_texture *texture) +{ + const struct wined3d_gl_info *gl_info = context->gl_info; + const struct wined3d_palette *palette; + + palette = texture->swapchain ? texture->swapchain->palette : NULL; + + if (!blitter->palette_texture) + gl_info->gl_ops.gl.p_glGenTextures(1, &blitter->palette_texture); + + context_active_texture(context, gl_info, 1); + gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D, blitter->palette_texture); + gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + + if (palette) + { + gl_info->gl_ops.gl.p_glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 256, 0, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, palette->colors); + } + else + { + static const DWORD black; + + FIXME("P8 texture loaded without a palette.\n"); + gl_info->gl_ops.gl.p_glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 1, 0, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, &black); + } + + context_active_texture(context, gl_info, 0); +} + +/* Context activation is done by the caller. */ +static struct glsl_blitter_program *glsl_blitter_get_program(struct wined3d_glsl_blitter *blitter, struct wined3d_context *context, const struct wined3d_texture *texture) { const struct wined3d_gl_info *gl_info = context->gl_info; struct glsl_blitter_program *program; + enum complex_fixup complex_fixup; struct glsl_blitter_args args; struct wine_rb_entry *entry;
@@ -12420,22 +12499,20 @@ static GLuint glsl_blitter_get_program(struct wined3d_glsl_blitter *blitter, args.texture_type = texture->target; args.fixup = texture->resource.format->color_fixup;
- if (is_complex_fixup(args.fixup)) + complex_fixup = get_complex_fixup(args.fixup); + if (complex_fixup && complex_fixup != COMPLEX_FIXUP_P8) { - FIXME("Complex fixups not supported.\n"); - return 0; + FIXME("Complex fixup %#x not supported.\n", complex_fixup); + return NULL; }
if ((entry = wine_rb_get(&blitter->programs, &args))) - { - program = WINE_RB_ENTRY_VALUE(entry, struct glsl_blitter_program, entry); - return program->id; - } + return WINE_RB_ENTRY_VALUE(entry, struct glsl_blitter_program, entry);
if (!(program = heap_alloc(sizeof(*program)))) { ERR("Failed to allocate blitter program memory.\n"); - return 0; + return NULL; }
program->args = args; @@ -12443,7 +12520,7 @@ static GLuint glsl_blitter_get_program(struct wined3d_glsl_blitter *blitter, { WARN("Failed to generate blitter program.\n"); heap_free(program); - return 0; + return NULL; }
if (wine_rb_put(&blitter->programs, &program->args, &program->entry) == -1) @@ -12451,10 +12528,10 @@ static GLuint glsl_blitter_get_program(struct wined3d_glsl_blitter *blitter, ERR("Failed to store blitter program.\n"); GL_EXTCALL(glDeleteProgram(program->id)); heap_free(program); - return 0; + return NULL; }
- return program->id; + return program; }
static BOOL glsl_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_context *context, @@ -12465,6 +12542,7 @@ static BOOL glsl_blitter_supported(enum wined3d_blit_op blit_op, const struct wi const struct wined3d_resource *dst_resource = &dst_texture->resource; const struct wined3d_format *src_format = src_resource->format; const struct wined3d_format *dst_format = dst_resource->format; + enum complex_fixup complex_fixup = COMPLEX_FIXUP_NONE; BOOL decompress;
if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_format->id == src_format->id) @@ -12506,11 +12584,16 @@ static BOOL glsl_blitter_supported(enum wined3d_blit_op blit_op, const struct wi
if (is_complex_fixup(src_format->color_fixup)) { - TRACE("Complex source fixups are not supported.\n"); - return FALSE; + complex_fixup = get_complex_fixup(src_format->color_fixup); + if (complex_fixup != COMPLEX_FIXUP_P8) + { + TRACE("Complex source fixup %#x not supported.\n", complex_fixup); + return FALSE; + } }
- if (!is_identity_fixup(dst_format->color_fixup)) + if (!is_identity_fixup(dst_format->color_fixup) + && (dst_format->id != src_format->id || dst_location != WINED3D_LOCATION_DRAWABLE)) { TRACE("Destination fixups are not supported.\n"); return FALSE; @@ -12530,9 +12613,9 @@ static DWORD glsl_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_bli const struct wined3d_gl_info *gl_info = context->gl_info; struct wined3d_texture *staging_texture = NULL; struct wined3d_glsl_blitter *glsl_blitter; + struct glsl_blitter_program *program; struct wined3d_blitter *next; unsigned int src_level; - GLuint program_id; RECT s, d;
TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, " @@ -12644,12 +12727,14 @@ static DWORD glsl_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_bli context_invalidate_state(context, STATE_FRAMEBUFFER); }
- if (!(program_id = glsl_blitter_get_program(glsl_blitter, context, src_texture))) + if (!(program = glsl_blitter_get_program(glsl_blitter, context, src_texture))) { ERR("Failed to get blitter program.\n"); return dst_location; } - GL_EXTCALL(glUseProgram(program_id)); + GL_EXTCALL(glUseProgram(program->id)); + if (get_complex_fixup(program->args.fixup) == COMPLEX_FIXUP_P8) + glsl_blitter_upload_palette(glsl_blitter, context, src_texture); context_draw_shaded_quad(context, src_texture, src_sub_resource_idx, src_rect, dst_rect, filter); GL_EXTCALL(glUseProgram(0));
@@ -12703,5 +12788,6 @@ void wined3d_glsl_blitter_create(struct wined3d_blitter **next, const struct win blitter->blitter.next = *next; string_buffer_list_init(&blitter->string_buffers); wine_rb_init(&blitter->programs, glsl_blitter_args_compare); + blitter->palette_texture = 0; *next = &blitter->blitter; } diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index c0bb4f17abe..49b08bfbe4b 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -3285,7 +3285,7 @@ static void apply_format_fixups(struct wined3d_adapter *adapter, struct wined3d_ 0, CHANNEL_SOURCE_X, 0, CHANNEL_SOURCE_X, 0, CHANNEL_SOURCE_X, 0, CHANNEL_SOURCE_ONE); }
- if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) + if (gl_info->supported[ARB_FRAGMENT_PROGRAM] || gl_info->supported[ARB_FRAGMENT_SHADER]) { idx = get_format_idx(WINED3DFMT_P8_UINT); gl_info->formats[idx].color_fixup = create_complex_fixup_desc(COMPLEX_FIXUP_P8);