[PATCH 6/6] wined3d: Introduce a scratch string buffers framework.

Matteo Bruni mbruni at codeweavers.com
Wed Apr 22 12:30:37 CDT 2015


It's somewhat of an RFC at this point. In particular I'd like some
feedback about the API.
An obvious variant would be to store the pointer to the parent
wined3d_shader_buffer structure right before the string and just
return the string itself (thus avoiding having to add ->buffer to
all the uses of the string).
---
 dlls/wined3d/glsl_shader.c     | 133 +++++++++++++++++++++++------------------
 dlls/wined3d/shader.c          | 114 ++++++++++++++++++++++++++++++++++-
 dlls/wined3d/wined3d_private.h |   6 ++
 3 files changed, 191 insertions(+), 62 deletions(-)

diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index c40d42b..4e03b09 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -92,6 +92,7 @@ struct constant_heap
 /* GLSL shader private data */
 struct shader_glsl_priv {
     struct wined3d_shader_buffer shader_buffer;
+    struct list string_buffers;
     struct wine_rb_tree program_lookup;
     struct constant_heap vconst_heap;
     struct constant_heap pconst_heap;
@@ -425,11 +426,11 @@ static void shader_glsl_validate_link(const struct wined3d_gl_info *gl_info, GLu
 }
 
 /* Context activation is done by the caller. */
-static void shader_glsl_load_samplers(const struct wined3d_gl_info *gl_info,
+static void shader_glsl_load_samplers(const struct wined3d_gl_info *gl_info, struct shader_glsl_priv *priv,
         const DWORD *tex_unit_map, GLuint program_id)
 {
     unsigned int mapped_unit;
-    char sampler_name[20];
+    struct wined3d_shader_buffer *sampler_name = shader_get_buffer(&priv->string_buffers);
     const char *prefix;
     unsigned int i, j;
     GLint name_loc;
@@ -452,23 +453,24 @@ static void shader_glsl_load_samplers(const struct wined3d_gl_info *gl_info,
 
         for (j = 0; j < sampler_info[i].count; ++j)
         {
-            snprintf(sampler_name, sizeof(sampler_name), "%s_sampler%u", prefix, j);
-            name_loc = GL_EXTCALL(glGetUniformLocation(program_id, sampler_name));
+            shader_sprintf(sampler_name, "%s_sampler%u", prefix, j);
+            name_loc = GL_EXTCALL(glGetUniformLocation(program_id, sampler_name->buffer));
             if (name_loc == -1)
                 continue;
 
             mapped_unit = tex_unit_map[sampler_info[i].base_idx + j];
             if (mapped_unit == WINED3D_UNMAPPED_STAGE || mapped_unit >= gl_info->limits.combined_samplers)
             {
-                ERR("Trying to load sampler %s on unsupported unit %u.\n", sampler_name, mapped_unit);
+                ERR("Trying to load sampler %s on unsupported unit %u.\n", sampler_name->buffer, mapped_unit);
                 continue;
             }
 
-            TRACE("Loading sampler %s on unit %u.\n", sampler_name, mapped_unit);
+            TRACE("Loading sampler %s on unit %u.\n", sampler_name->buffer, mapped_unit);
             GL_EXTCALL(glUniform1i(name_loc, mapped_unit));
         }
     }
     checkGLcall("glUniform1i");
+    shader_release_buffer(&priv->string_buffers, sampler_name);
 }
 
 /* Context activation is done by the caller. */
@@ -4596,7 +4598,7 @@ static void delete_glsl_program_entry(struct shader_glsl_priv *priv, const struc
 }
 
 static void handle_ps3_input(struct wined3d_shader_buffer *buffer,
-        const struct wined3d_gl_info *gl_info, const DWORD *map,
+        const struct wined3d_gl_info *gl_info, struct shader_glsl_priv *priv, const DWORD *map,
         const struct wined3d_shader_signature *input_signature,
         const struct wined3d_shader_reg_maps *reg_maps_in,
         const struct wined3d_shader_signature *output_signature,
@@ -4607,7 +4609,7 @@ static void handle_ps3_input(struct wined3d_shader_buffer *buffer,
     DWORD in_idx;
     unsigned int in_count = vec4_varyings(3, gl_info);
     char reg_mask[6];
-    char destination[50];
+    struct wined3d_shader_buffer *destination = shader_get_buffer(&priv->string_buffers);
 
     set = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*set) * (in_count + 2));
 
@@ -4629,11 +4631,11 @@ static void handle_ps3_input(struct wined3d_shader_buffer *buffer,
         }
 
         if (in_idx == in_count)
-            sprintf(destination, "gl_FrontColor");
+            shader_sprintf(destination, "gl_FrontColor");
         else if (in_idx == in_count + 1)
-            sprintf(destination, "gl_FrontSecondaryColor");
+            shader_sprintf(destination, "gl_FrontSecondaryColor");
         else
-            sprintf(destination, "ps_link[%u]", in_idx);
+            shader_sprintf(destination, "ps_link[%u]", in_idx);
 
         if (!set[in_idx])
             set[in_idx] = ~0u;
@@ -4656,7 +4658,7 @@ static void handle_ps3_input(struct wined3d_shader_buffer *buffer,
             shader_glsl_write_mask_to_str(mask, reg_mask);
 
             shader_addline(buffer, "%s%s = vs_out[%u]%s;\n",
-                    destination, reg_mask, output->register_idx, reg_mask);
+                    destination->buffer, reg_mask, output->register_idx, reg_mask);
         }
     }
 
@@ -4677,21 +4679,23 @@ static void handle_ps3_input(struct wined3d_shader_buffer *buffer,
         reg_mask[size] = '\0';
 
         if (i == in_count)
-            sprintf(destination, "gl_FrontColor");
+            shader_sprintf(destination, "gl_FrontColor");
         else if (i == in_count + 1)
-            sprintf(destination, "gl_FrontSecondaryColor");
+            shader_sprintf(destination, "gl_FrontSecondaryColor");
         else
-            sprintf(destination, "ps_link[%u]", i);
+            shader_sprintf(destination, "ps_link[%u]", i);
 
-        if (size == 1) shader_addline(buffer, "%s.%s = 0.0;\n", destination, reg_mask);
-        else shader_addline(buffer, "%s.%s = vec%u(0.0);\n", destination, reg_mask, size);
+        if (size == 1) shader_addline(buffer, "%s.%s = 0.0;\n", destination->buffer, reg_mask);
+        else shader_addline(buffer, "%s.%s = vec%u(0.0);\n", destination->buffer, reg_mask, size);
     }
 
     HeapFree(GetProcessHeap(), 0, set);
+    shader_release_buffer(&priv->string_buffers, destination);
 }
 
 /* Context activation is done by the caller. */
 static GLuint generate_param_reorder_function(struct wined3d_shader_buffer *buffer,
+        struct shader_glsl_priv *priv,
         const struct wined3d_shader *vs, const struct wined3d_shader *ps,
         const struct wined3d_gl_info *gl_info)
 {
@@ -4793,7 +4797,7 @@ static GLuint generate_param_reorder_function(struct wined3d_shader_buffer *buff
         }
 
         /* Then, fix the pixel shader input */
-        handle_ps3_input(buffer, gl_info, ps->u.ps.input_reg_map, &ps->input_signature,
+        handle_ps3_input(buffer, gl_info, priv, ps->u.ps.input_reg_map, &ps->input_signature,
                 &ps->reg_maps, &vs->output_signature, &vs->reg_maps);
 
         shader_addline(buffer, "}\n");
@@ -5700,7 +5704,8 @@ static void shader_glsl_ffp_fragment_op(struct wined3d_shader_buffer *buffer, un
 
 /* Context activation is done by the caller. */
 static GLuint shader_glsl_generate_ffp_fragment_shader(struct wined3d_shader_buffer *buffer,
-        const struct ffp_frag_settings *settings, const struct wined3d_gl_info *gl_info)
+        const struct ffp_frag_settings *settings, const struct wined3d_gl_info *gl_info,
+        struct shader_glsl_priv *priv)
 {
     BYTE lum_map = 0, bump_map = 0, tex_map = 0, tss_const_map = 0;
     BOOL tempreg_used = FALSE, tfactor_used = FALSE;
@@ -5850,7 +5855,7 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct wined3d_shader_buf
     for (stage = 0; stage < MAX_TEXTURES && settings->op[stage].cop != WINED3D_TOP_DISABLE; ++stage)
     {
         const char *texture_function, *coord_mask;
-        char tex_reg_name[8];
+        const char *tex_reg_name;
         BOOL proj;
 
         if (!(tex_map & (1 << stage)))
@@ -5980,7 +5985,7 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct wined3d_shader_buf
                     stage, texture_function, stage, stage, coord_mask);
         }
 
-        sprintf(tex_reg_name, "tex%u", stage);
+        tex_reg_name = shader_sprintf_unsafe(&priv->string_buffers, "tex%u", stage);
         shader_glsl_color_correction_ext(buffer, tex_reg_name, WINED3DSP_WRITEMASK_ALL,
                 settings->op[stage].color_fixup);
     }
@@ -6091,7 +6096,7 @@ static struct glsl_ffp_fragment_shader *shader_glsl_find_ffp_fragment_shader(str
         return NULL;
 
     glsl_desc->entry.settings = *args;
-    glsl_desc->id = shader_glsl_generate_ffp_fragment_shader(&priv->shader_buffer, args, gl_info);
+    glsl_desc->id = shader_glsl_generate_ffp_fragment_shader(&priv->shader_buffer, args, gl_info, priv);
     list_init(&glsl_desc->linked_programs);
     add_ffp_frag_shader(&priv->ffp_fragment_shaders, &glsl_desc->entry);
 
@@ -6100,31 +6105,31 @@ static struct glsl_ffp_fragment_shader *shader_glsl_find_ffp_fragment_shader(str
 
 
 static void shader_glsl_init_vs_uniform_locations(const struct wined3d_gl_info *gl_info,
-        GLuint program_id, struct glsl_vs_program *vs, unsigned int vs_c_count)
+        struct shader_glsl_priv *priv, GLuint program_id, struct glsl_vs_program *vs, unsigned int vs_c_count)
 {
     unsigned int i;
-    char name[32];
+    struct wined3d_shader_buffer *name = shader_get_buffer(&priv->string_buffers);
 
     vs->uniform_f_locations = HeapAlloc(GetProcessHeap(), 0,
             sizeof(GLuint) * gl_info->limits.glsl_vs_float_constants);
     for (i = 0; i < vs_c_count; ++i)
     {
-        snprintf(name, sizeof(name), "vs_c[%u]", i);
-        vs->uniform_f_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
+        shader_sprintf(name, "vs_c[%u]", i);
+        vs->uniform_f_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
     }
     memset(&vs->uniform_f_locations[vs_c_count], 0xff,
             (gl_info->limits.glsl_vs_float_constants - vs_c_count) * sizeof(GLuint));
 
     for (i = 0; i < MAX_CONST_I; ++i)
     {
-        snprintf(name, sizeof(name), "vs_i[%u]", i);
-        vs->uniform_i_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
+        shader_sprintf(name, "vs_i[%u]", i);
+        vs->uniform_i_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
     }
 
     for (i = 0; i < MAX_CONST_B; ++i)
     {
-        snprintf(name, sizeof(name), "vs_b[%u]", i);
-        vs->uniform_b_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
+        shader_sprintf(name, "vs_b[%u]", i);
+        vs->uniform_b_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
     }
 
     vs->pos_fixup_location = GL_EXTCALL(glGetUniformLocation(program_id, "posFixup"));
@@ -6132,46 +6137,48 @@ static void shader_glsl_init_vs_uniform_locations(const struct wined3d_gl_info *
     vs->modelview_matrix_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_modelview_matrix"));
     vs->projection_matrix_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_projection_matrix"));
     vs->normal_matrix_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_normal_matrix"));
+
+    shader_release_buffer(&priv->string_buffers, name);
 }
 
 static void shader_glsl_init_ps_uniform_locations(const struct wined3d_gl_info *gl_info,
-        GLuint program_id, struct glsl_ps_program *ps, unsigned int ps_c_count)
+        struct shader_glsl_priv *priv, GLuint program_id, struct glsl_ps_program *ps, unsigned int ps_c_count)
 {
     unsigned int i;
-    char name[32];
+    struct wined3d_shader_buffer *name = shader_get_buffer(&priv->string_buffers);
 
     ps->uniform_f_locations = HeapAlloc(GetProcessHeap(), 0,
             sizeof(GLuint) * gl_info->limits.glsl_ps_float_constants);
     for (i = 0; i < ps_c_count; ++i)
     {
-        snprintf(name, sizeof(name), "ps_c[%u]", i);
-        ps->uniform_f_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
+        shader_sprintf(name, "ps_c[%u]", i);
+        ps->uniform_f_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
     }
     memset(&ps->uniform_f_locations[ps_c_count], 0xff,
             (gl_info->limits.glsl_ps_float_constants - ps_c_count) * sizeof(GLuint));
 
     for (i = 0; i < MAX_CONST_I; ++i)
     {
-        snprintf(name, sizeof(name), "ps_i[%u]", i);
-        ps->uniform_i_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
+        shader_sprintf(name, "ps_i[%u]", i);
+        ps->uniform_i_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
     }
 
     for (i = 0; i < MAX_CONST_B; ++i)
     {
-        snprintf(name, sizeof(name), "ps_b[%u]", i);
-        ps->uniform_b_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
+        shader_sprintf(name, "ps_b[%u]", i);
+        ps->uniform_b_locations[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
     }
 
     for (i = 0; i < MAX_TEXTURES; ++i)
     {
-        snprintf(name, sizeof(name), "bumpenv_mat%u", i);
-        ps->bumpenv_mat_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
-        snprintf(name, sizeof(name), "bumpenv_lum_scale%u", i);
-        ps->bumpenv_lum_scale_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
-        snprintf(name, sizeof(name), "bumpenv_lum_offset%u", i);
-        ps->bumpenv_lum_offset_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
-        snprintf(name, sizeof(name), "tss_const%u", i);
-        ps->tss_constant_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
+        shader_sprintf(name, "bumpenv_mat%u", i);
+        ps->bumpenv_mat_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
+        shader_sprintf(name, "bumpenv_lum_scale%u", i);
+        ps->bumpenv_lum_scale_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
+        shader_sprintf(name, "bumpenv_lum_offset%u", i);
+        ps->bumpenv_lum_offset_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
+        shader_sprintf(name, "tss_const%u", i);
+        ps->tss_constant_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name->buffer));
     }
 
     ps->tex_factor_location = GL_EXTCALL(glGetUniformLocation(program_id, "tex_factor"));
@@ -6179,26 +6186,30 @@ static void shader_glsl_init_ps_uniform_locations(const struct wined3d_gl_info *
     ps->np2_fixup_location = GL_EXTCALL(glGetUniformLocation(program_id, "ps_samplerNP2Fixup"));
     ps->ycorrection_location = GL_EXTCALL(glGetUniformLocation(program_id, "ycorrection"));
     ps->color_key_location = GL_EXTCALL(glGetUniformLocation(program_id, "color_key"));
+
+    shader_release_buffer(&priv->string_buffers, name);
 }
 
-static void shader_glsl_init_uniform_block_bindings(const struct wined3d_gl_info *gl_info, GLuint program_id,
+static void shader_glsl_init_uniform_block_bindings(const struct wined3d_gl_info *gl_info,
+        struct shader_glsl_priv *priv, GLuint program_id,
         const struct wined3d_shader_reg_maps *reg_maps, unsigned int base, unsigned int count)
 {
     const char *prefix = shader_glsl_get_prefix(reg_maps->shader_version.type);
     GLuint block_idx;
     unsigned int i;
-    char name[16];
+    struct wined3d_shader_buffer *name = shader_get_buffer(&priv->string_buffers);
 
     for (i = 0; i < count; ++i)
     {
         if (!reg_maps->cb_sizes[i])
             continue;
 
-        snprintf(name, sizeof(name), "block_%s_cb%u", prefix, i);
-        block_idx = GL_EXTCALL(glGetUniformBlockIndex(program_id, name));
+        shader_sprintf(name, "block_%s_cb%u", prefix, i);
+        block_idx = GL_EXTCALL(glGetUniformBlockIndex(program_id, name->buffer));
         GL_EXTCALL(glUniformBlockBinding(program_id, block_idx, base + i));
     }
     checkGLcall("glUniformBlockBinding");
+    shader_release_buffer(&priv->string_buffers, name);
 }
 
 /* Context activation is done by the caller. */
@@ -6324,9 +6335,10 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
     if (vshader)
     {
         WORD map = vshader->reg_maps.input_registers;
-        char tmp_name[10];
+        const char *tmp_name;
 
-        reorder_shader_id = generate_param_reorder_function(&priv->shader_buffer, vshader, pshader, gl_info);
+        reorder_shader_id = generate_param_reorder_function(&priv->shader_buffer, priv,
+                vshader, pshader, gl_info);
         TRACE("Attaching GLSL shader object %u to program %u.\n", reorder_shader_id, program_id);
         GL_EXTCALL(glAttachShader(program_id, reorder_shader_id));
         checkGLcall("glAttachShader");
@@ -6348,7 +6360,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
         {
             if (!(map & 1)) continue;
 
-            snprintf(tmp_name, sizeof(tmp_name), "vs_in%u", i);
+            tmp_name = shader_sprintf_unsafe(&priv->string_buffers, "vs_in%u", i);
             GL_EXTCALL(glBindAttribLocation(program_id, i, tmp_name));
         }
         checkGLcall("glBindAttribLocation");
@@ -6390,9 +6402,9 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
     GL_EXTCALL(glLinkProgram(program_id));
     shader_glsl_validate_link(gl_info, program_id);
 
-    shader_glsl_init_vs_uniform_locations(gl_info, program_id, &entry->vs,
+    shader_glsl_init_vs_uniform_locations(gl_info, priv, program_id, &entry->vs,
             vshader ? min(vshader->limits->constant_float, gl_info->limits.glsl_vs_float_constants) : 0);
-    shader_glsl_init_ps_uniform_locations(gl_info, program_id, &entry->ps,
+    shader_glsl_init_ps_uniform_locations(gl_info, priv, program_id, &entry->ps,
             pshader ? min(pshader->limits->constant_float, gl_info->limits.glsl_ps_float_constants) : 0);
     checkGLcall("Find glsl program uniform locations");
 
@@ -6418,7 +6430,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
      * supports enough samplers to allow the max number of vertex samplers with all possible
      * fixed function fragment processing setups. So once the program is linked these samplers
      * won't change. */
-    shader_glsl_load_samplers(gl_info, context->tex_unit_map, program_id);
+    shader_glsl_load_samplers(gl_info, priv, context->tex_unit_map, program_id);
 
     entry->constant_update_mask = 0;
     if (vshader)
@@ -6430,7 +6442,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
             entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_B;
         entry->constant_update_mask |= WINED3D_SHADER_CONST_VS_POS_FIXUP;
 
-        shader_glsl_init_uniform_block_bindings(gl_info, program_id, &vshader->reg_maps,
+        shader_glsl_init_uniform_block_bindings(gl_info, priv, program_id, &vshader->reg_maps,
                 0, gl_info->limits.vertex_uniform_blocks);
     }
     else
@@ -6440,7 +6452,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
     }
 
     if (gshader)
-        shader_glsl_init_uniform_block_bindings(gl_info, program_id, &gshader->reg_maps,
+        shader_glsl_init_uniform_block_bindings(gl_info, priv, program_id, &gshader->reg_maps,
                 gl_info->limits.vertex_uniform_blocks, gl_info->limits.geometry_uniform_blocks);
 
     if (ps_id)
@@ -6455,7 +6467,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
             if (entry->ps.ycorrection_location != -1)
                 entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_Y_CORR;
 
-            shader_glsl_init_uniform_block_bindings(gl_info, program_id, &pshader->reg_maps,
+            shader_glsl_init_uniform_block_bindings(gl_info, priv, program_id, &pshader->reg_maps,
                     gl_info->limits.vertex_uniform_blocks + gl_info->limits.geometry_uniform_blocks,
                     gl_info->limits.fragment_uniform_blocks);
         }
@@ -6913,6 +6925,8 @@ static HRESULT shader_glsl_alloc(struct wined3d_device *device, const struct win
     struct fragment_caps fragment_caps;
     void *vertex_priv, *fragment_priv;
 
+    list_init(&priv->string_buffers);
+
     if (!(vertex_priv = vertex_pipe->vp_alloc(&glsl_shader_backend, priv)))
     {
         ERR("Failed to initialize vertex pipe.\n");
@@ -7005,6 +7019,7 @@ static void shader_glsl_free(struct wined3d_device *device)
     constant_heap_free(&priv->pconst_heap);
     constant_heap_free(&priv->vconst_heap);
     HeapFree(GetProcessHeap(), 0, priv->stack);
+    shader_buffer_list_free(&priv->string_buffers);
     shader_buffer_free(&priv->shader_buffer);
     priv->fragment_pipe->free_private(device);
     priv->vertex_pipe->vp_free(device);
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index d5a90c0..2bdc815 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -255,7 +255,7 @@ void shader_buffer_clear(struct wined3d_shader_buffer *buffer)
 
 BOOL shader_buffer_init(struct wined3d_shader_buffer *buffer)
 {
-    buffer->buffer_size = 16384;
+    buffer->buffer_size = 32;
     if (!(buffer->buffer = HeapAlloc(GetProcessHeap(), 0, buffer->buffer_size)))
     {
         ERR("Failed to allocate shader buffer memory.\n");
@@ -276,13 +276,17 @@ int shader_vaddline(struct wined3d_shader_buffer *buffer, const char *format, va
     char *base = buffer->buffer + buffer->content_size;
     int rc;
     char *new_buffer;
+    unsigned int new_buffer_size;
 
     while(1)
     {
         rc = vsnprintf(base, buffer->buffer_size - buffer->content_size, format, args);
         if (rc < 0 /* C89 */ || (unsigned int)rc >= buffer->buffer_size - buffer->content_size /* C99 */)
         {
-            new_buffer = HeapReAlloc(GetProcessHeap(), 0, buffer->buffer, buffer->buffer_size * 2);
+            new_buffer_size = buffer->buffer_size * 2;
+            while (rc > 0 && (unsigned int)rc >= new_buffer_size - buffer->content_size)
+                new_buffer_size *= 2;
+            new_buffer = HeapReAlloc(GetProcessHeap(), 0, buffer->buffer, new_buffer_size);
             if (!new_buffer)
             {
                 ERR("The buffer allocated for the shader program string is too small at %d bytes.\n", buffer->buffer_size);
@@ -290,7 +294,7 @@ int shader_vaddline(struct wined3d_shader_buffer *buffer, const char *format, va
                 return -1;
             }
             buffer->buffer = new_buffer;
-            buffer->buffer_size = buffer->buffer_size * 2;
+            buffer->buffer_size = new_buffer_size;
             base = buffer->buffer + buffer->content_size;
         }
         else
@@ -331,6 +335,110 @@ int shader_addline(struct wined3d_shader_buffer *buffer, const char *format, ...
     return ret;
 }
 
+static char shader_empty_string[] = "";
+
+struct wined3d_shader_buffer *shader_get_buffer(struct list *list)
+{
+    struct wined3d_shader_buffer *buffer;
+
+    if (list_empty(list))
+    {
+        buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(*buffer));
+        if (!buffer || !shader_buffer_init(buffer))
+        {
+            ERR("Couldn't allocate buffer for temporary string.\n");
+            return NULL;
+        }
+    }
+    else
+    {
+        buffer = LIST_ENTRY(list_head(list), struct wined3d_shader_buffer, entry);
+        list_remove(&buffer->entry);
+    }
+    return buffer;
+}
+
+static void shader_sprintf_va_list(struct wined3d_shader_buffer *buffer, const char *format, va_list args)
+{
+    int ret;
+    char *new_buffer;
+    unsigned int new_buffer_size;
+
+    if (!buffer)
+        return;
+    while (1)
+    {
+        ret = vsnprintf(buffer->buffer, buffer->buffer_size, format, args);
+        if (ret < 0 || (unsigned int)ret >= buffer->buffer_size)
+        {
+            new_buffer_size = buffer->buffer_size * 2;
+            while (ret > 0 && (unsigned int)ret >= new_buffer_size)
+                new_buffer_size *= 2;
+            new_buffer = HeapReAlloc(GetProcessHeap(), 0, buffer->buffer, new_buffer_size);
+            if (!new_buffer)
+            {
+                ERR("Couldn't allocate buffer for temporary string.\n");
+                buffer->buffer[0] = 0;
+                return;
+            }
+            buffer->buffer = new_buffer;
+            buffer->buffer_size = new_buffer_size;
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+void shader_sprintf(struct wined3d_shader_buffer *buffer, const char *format, ...)
+{
+    va_list args;
+
+    va_start(args, format);
+    shader_sprintf_va_list(buffer, format, args);
+    va_end(args);
+}
+
+/* This function immediately puts the buffer back into the free list (it's
+ * intended to be used when the string is to be used and discarded immediately,
+ * mostly useful to avoid having to move the string pointer out of the block). */
+const char *shader_sprintf_unsafe(struct list *buffer_list, const char *format, ...)
+{
+    va_list args;
+    struct wined3d_shader_buffer *buffer;
+
+    buffer = shader_get_buffer(buffer_list);
+
+    va_start(args, format);
+    shader_sprintf_va_list(buffer, format, args);
+    va_end(args);
+
+    if (!buffer)
+        return shader_empty_string;
+
+    shader_release_buffer(buffer_list, buffer);
+    return buffer->buffer;
+}
+
+void shader_release_buffer(struct list *list, struct wined3d_shader_buffer *buffer)
+{
+    if (!buffer)
+        return;
+    list_add_head(list, &buffer->entry);
+}
+
+void shader_buffer_list_free(struct list *list)
+{
+    struct wined3d_shader_buffer *buffer, *buffer_next;
+
+    LIST_FOR_EACH_ENTRY_SAFE(buffer, buffer_next, list, struct wined3d_shader_buffer, entry)
+    {
+        shader_buffer_free(buffer);
+        HeapFree(GetProcessHeap(), 0, buffer);
+    }
+}
+
 /* Convert floating point offset relative to a register file to an absolute
  * offset for float constants. */
 static unsigned int shader_get_float_offset(enum wined3d_shader_register_type register_type, UINT register_idx)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 782f54f..0eddfa1 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -437,6 +437,7 @@ enum wined3d_shader_rel_op
 
 struct wined3d_shader_buffer
 {
+    struct list entry;
     char *buffer;
     unsigned int buffer_size;
     unsigned int content_size;
@@ -2896,6 +2897,11 @@ struct wined3d_shader_limits
 /* Base Shader utility functions. */
 int shader_addline(struct wined3d_shader_buffer *buffer, const char *fmt, ...) PRINTF_ATTR(2,3) DECLSPEC_HIDDEN;
 int shader_vaddline(struct wined3d_shader_buffer *buffer, const char *fmt, va_list args) DECLSPEC_HIDDEN;
+struct wined3d_shader_buffer *shader_get_buffer(struct list *list) DECLSPEC_HIDDEN;
+void shader_sprintf(struct wined3d_shader_buffer *buffer, const char *format, ...) PRINTF_ATTR(2, 3) DECLSPEC_HIDDEN;
+const char *shader_sprintf_unsafe(struct list *buffer_list, const char *format, ...) PRINTF_ATTR(2, 3) DECLSPEC_HIDDEN;
+void shader_release_buffer(struct list *list, struct wined3d_shader_buffer *buffer) DECLSPEC_HIDDEN;
+void shader_buffer_list_free(struct list *list) DECLSPEC_HIDDEN;
 
 /* Vertex shader utility functions */
 BOOL vshader_get_input(const struct wined3d_shader *shader,
-- 
2.0.5




More information about the wine-patches mailing list