[PATCH 3/3] wined3d: Implement P8 blits in the GLSL blitter.

Henri Verbeet hverbeet at codeweavers.com
Fri Apr 27 18:20:48 CDT 2018


From: Matteo Bruni <mbruni at codeweavers.com>

Signed-off-by: Henri Verbeet <hverbeet at 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);
-- 
2.11.0




More information about the wine-devel mailing list