diff options
| author | Marek Olšák <maraeo@gmail.com> | 2010-06-08 23:46:40 +0200 | 
|---|---|---|
| committer | Marek Olšák <maraeo@gmail.com> | 2010-06-13 17:43:37 +0200 | 
| commit | 028459b0bf2bb778b55493f9b23ab7f2c9b355a0 (patch) | |
| tree | 8876c86860c090fad870e67d32b3caa05f08081c | |
| parent | 1384a7bccab3d5b36729d59944a76538375f5494 (diff) | |
r300g: add fallback for unaligned/unsupported vertex stride/offset/format
There is a problem though, the translate module cannot emit half float
vertices.
| -rw-r--r-- | src/gallium/drivers/r300/Makefile | 1 | ||||
| -rw-r--r-- | src/gallium/drivers/r300/SConscript | 1 | ||||
| -rw-r--r-- | src/gallium/drivers/r300/r300_context.c | 4 | ||||
| -rw-r--r-- | src/gallium/drivers/r300/r300_context.h | 18 | ||||
| -rw-r--r-- | src/gallium/drivers/r300/r300_render.c | 28 | ||||
| -rw-r--r-- | src/gallium/drivers/r300/r300_render_translate.c | 165 | ||||
| -rw-r--r-- | src/gallium/drivers/r300/r300_state.c | 1 | 
7 files changed, 209 insertions, 9 deletions
| diff --git a/src/gallium/drivers/r300/Makefile b/src/gallium/drivers/r300/Makefile index 6bb82e5ed0..edd15f6a66 100644 --- a/src/gallium/drivers/r300/Makefile +++ b/src/gallium/drivers/r300/Makefile @@ -14,6 +14,7 @@ C_SOURCES = \  	r300_hyperz.c \  	r300_query.c \  	r300_render.c \ +	r300_render_translate.c \  	r300_resource.c \  	r300_screen.c \  	r300_screen_buffer.c \ diff --git a/src/gallium/drivers/r300/SConscript b/src/gallium/drivers/r300/SConscript index eb3e1d365e..cef49c9ed4 100644 --- a/src/gallium/drivers/r300/SConscript +++ b/src/gallium/drivers/r300/SConscript @@ -24,6 +24,7 @@ r300 = env.ConvenienceLibrary(          'r300_hyperz.c',          'r300_query.c',          'r300_render.c', +        'r300_render_translate.c',          'r300_resource.c',          'r300_screen.c',          'r300_screen_buffer.c', diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c index 88ce186798..9425f93a27 100644 --- a/src/gallium/drivers/r300/r300_context.c +++ b/src/gallium/drivers/r300/r300_context.c @@ -66,6 +66,8 @@ static void r300_destroy_context(struct pipe_context* context)      u_upload_destroy(r300->upload_vb);      u_upload_destroy(r300->upload_ib); +    translate_cache_destroy(r300->tran.translate_cache); +      FREE(r300->blend_color_state.state);      FREE(r300->clip_state.state);      FREE(r300->fb_state.state); @@ -227,6 +229,8 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen,      if (r300->upload_vb == NULL)          goto no_upload_vb; +    r300->tran.translate_cache = translate_cache_create(); +      return &r300->context;   no_upload_ib: diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h index cca11f8045..c99c2af55e 100644 --- a/src/gallium/drivers/r300/r300_context.h +++ b/src/gallium/drivers/r300/r300_context.h @@ -31,6 +31,8 @@  #include "util/u_inlines.h"  #include "util/u_transfer.h" +#include "translate/translate_cache.h" +  #include "r300_defines.h"  #include "r300_screen.h" @@ -340,6 +342,17 @@ struct r300_vertex_element_state {      struct r300_vertex_stream_state vertex_stream;  }; +struct r300_translate_context { +    /* Translate cache for incompatible vertex offset/stride/format fallback. */ +    struct translate_cache *translate_cache; + +    /* The vertex buffer slot containing the translated buffer. */ +    unsigned vb_slot; + +    /* Saved and new vertex element state. */ +    void *saved_velems, *new_velems; +}; +  struct r300_context {      /* Parent class */      struct pipe_context context; @@ -354,6 +367,8 @@ struct r300_context {      struct blitter_context* blitter;      /* Stencil two-sided reference value fallback. */      struct r300_stencilref_context *stencilref_fallback; +    /* For translating vertex buffers having incompatible vertex layout. */ +    struct r300_translate_context tran;      /* Vertex buffer for rendering. */      struct pipe_resource* vbo; @@ -489,6 +504,9 @@ void r300_init_render_functions(struct r300_context *r300);  void r300_init_state_functions(struct r300_context* r300);  void r300_init_resource_functions(struct r300_context* r300); +void r300_begin_vertex_translate(struct r300_context *r300); +void r300_end_vertex_translate(struct r300_context *r300); +  boolean r300_check_cs(struct r300_context *r300, unsigned size);  void r300_finish(struct r300_context *r300);  void r500_dump_rs_block(struct r300_rs_block *rs); diff --git a/src/gallium/drivers/r300/r300_render.c b/src/gallium/drivers/r300/r300_render.c index 80dea8be98..e2617b8409 100644 --- a/src/gallium/drivers/r300/r300_render.c +++ b/src/gallium/drivers/r300/r300_render.c @@ -605,18 +605,20 @@ static void r300_draw_range_elements(struct pipe_context* pipe,                              r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0);      unsigned short_count;      int buffer_offset = 0, index_offset = 0; /* for index bias emulation */ +    boolean translate = FALSE;      if (r300->skip_rendering) {          return;      } -    if (r300->incompatible_vb_layout || -        r300->velems->incompatible_layout) { +    if (!u_trim_pipe_prim(mode, &count)) {          return;      } -    if (!u_trim_pipe_prim(mode, &count)) { -        return; +    /* Set up fallback for incompatible vertex layout if needed. */ +    if (r300->incompatible_vb_layout || r300->velems->incompatible_layout) { +        r300_begin_vertex_translate(r300); +        translate = TRUE;      }      if (indexBias && !index_bias_supported(r300)) { @@ -681,6 +683,10 @@ static void r300_draw_range_elements(struct pipe_context* pipe,      if (indexBuffer != orgIndexBuffer) {          pipe_resource_reference( &indexBuffer, NULL );      } + +    if (translate) { +        r300_end_vertex_translate(r300); +    }  }  /* Simple helpers for context setup. Should probably be moved to util. */ @@ -704,18 +710,20 @@ static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode,                              count > 65536 &&                              r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0);      unsigned short_count; +    boolean translate = FALSE;      if (r300->skip_rendering) {          return;      } -    if (r300->incompatible_vb_layout || -        r300->velems->incompatible_layout) { +    if (!u_trim_pipe_prim(mode, &count)) {          return;      } -    if (!u_trim_pipe_prim(mode, &count)) { -        return; +    /* Set up fallback for incompatible vertex layout if needed. */ +    if (r300->incompatible_vb_layout || r300->velems->incompatible_layout) { +        r300_begin_vertex_translate(r300); +        translate = TRUE;      }      r300_update_derived_state(r300); @@ -747,6 +755,10 @@ static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode,          }  	u_upload_flush(r300->upload_vb);      } + +    if (translate) { +        r300_end_vertex_translate(r300); +    }  }  /**************************************************************************** diff --git a/src/gallium/drivers/r300/r300_render_translate.c b/src/gallium/drivers/r300/r300_render_translate.c new file mode 100644 index 0000000000..b03582aac3 --- /dev/null +++ b/src/gallium/drivers/r300/r300_render_translate.c @@ -0,0 +1,165 @@ +/* + * Copyright 2010 Marek Olšák <maraeo@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/** + * The functions below translate vertex buffers to the layout compatible + * with the hardware, so that all vertex fetches are be DWORD-aligned and all + * used vertex formats are supported. + */ + +#include "r300_context.h" +#include "translate/translate.h" + +void r300_begin_vertex_translate(struct r300_context *r300) +{ +    struct pipe_context *pipe = &r300->context; +    struct translate_key key = {0}; +    struct translate_element *te; +    unsigned tr_elem_index[PIPE_MAX_ATTRIBS] = {0}; +    struct translate *tr; +    struct r300_vertex_element_state *ve = r300->velems; +    boolean vb_translated[PIPE_MAX_ATTRIBS] = {0}; +    void *vb_map[PIPE_MAX_ATTRIBS] = {0}, *out_map; +    struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS] = {0}, *out_transfer; +    struct pipe_resource *out_buffer; +    unsigned i, num_verts; + +    /* Initialize the translate key, i.e. the recipe how vertices should be +     * translated. */ +    for (i = 0; i < ve->count; i++) { +        struct pipe_vertex_buffer *vb = +                &r300->vertex_buffer[ve->velem[i].vertex_buffer_index]; + +        /* Check for support. */ +        if (ve->velem[i].src_format == ve->hw_format[i] && +            (vb->buffer_offset + ve->velem[i].src_offset) % 4 == 0 && +            vb->stride % 4 == 0) { +            continue; +        } + +        /* Add this vertex element. */ +        te = &key.element[key.nr_elements]; +        /*te->type; +        te->instance_divisor;*/ +        te->input_buffer = ve->velem[i].vertex_buffer_index; +        te->input_format = ve->velem[i].src_format; +        te->input_offset = vb->buffer_offset + ve->velem[i].src_offset; +        te->output_format = ve->hw_format[i]; +        te->output_offset = key.output_stride; + +        key.output_stride += ve->hw_format_size[i]; +        vb_translated[ve->velem[i].vertex_buffer_index] = TRUE; +        tr_elem_index[i] = key.nr_elements; +        key.nr_elements++; +    } + +    /* Get a translate object. */ +    tr = translate_cache_find(r300->tran.translate_cache, &key); + +    /* Map buffers we want to translate. */ +    for (i = 0; i < r300->vertex_buffer_count; i++) { +        if (vb_translated[i]) { +            struct pipe_vertex_buffer *vb = &r300->vertex_buffer[i]; + +            vb_map[i] = pipe_buffer_map(pipe, vb->buffer, +                                        PIPE_TRANSFER_READ, &vb_transfer[i]); + +            tr->set_buffer(tr, i, vb_map[i], vb->stride, vb->max_index); +        } +    } + +    /* Create and map the output buffer. */ +    num_verts = r300->vertex_buffer_max_index + 1; + +    out_buffer = pipe_buffer_create(&r300->screen->screen, +                                    PIPE_BIND_VERTEX_BUFFER, +                                    key.output_stride * num_verts); + +    out_map = pipe_buffer_map(pipe, out_buffer, PIPE_TRANSFER_WRITE, +                              &out_transfer); + +    /* Translate. */ +    tr->run(tr, 0, num_verts, 0, out_map); + +    /* Unmap all buffers. */ +    for (i = 0; i < r300->vertex_buffer_count; i++) { +        if (vb_translated[i]) { +            pipe_buffer_unmap(pipe, r300->vertex_buffer[i].buffer, +                              vb_transfer[i]); +        } +    } + +    pipe_buffer_unmap(pipe, out_buffer, out_transfer); + +    /* Setup the new vertex buffer in the first free slot. */ +    for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { +        struct pipe_vertex_buffer *vb = &r300->vertex_buffer[i]; + +        if (!vb->buffer) { +            pipe_resource_reference(&vb->buffer, out_buffer); +            vb->buffer_offset = 0; +            vb->max_index = num_verts - 1; +            vb->stride = key.output_stride; +            r300->tran.vb_slot = i; +            break; +        } +    } + +    /* Save and replace vertex elements. */ +    { +        struct pipe_vertex_element new_velems[PIPE_MAX_ATTRIBS]; + +        r300->tran.saved_velems = r300->velems; + +        for (i = 0; i < ve->count; i++) { +            if (vb_translated[ve->velem[i].vertex_buffer_index]) { +                te = &key.element[tr_elem_index[i]]; +                new_velems[i].instance_divisor = ve->velem[i].instance_divisor; +                new_velems[i].src_format = te->output_format; +                new_velems[i].src_offset = te->output_offset; +                new_velems[i].vertex_buffer_index = r300->tran.vb_slot; +            } else { +                memcpy(&new_velems[i], &ve->velem[i], +                       sizeof(struct pipe_vertex_element)); +            } +        } + +        r300->tran.new_velems = +            pipe->create_vertex_elements_state(pipe, ve->count, new_velems); +        pipe->bind_vertex_elements_state(pipe, r300->tran.new_velems); +    } + +    pipe_resource_reference(&out_buffer, NULL); +} + +void r300_end_vertex_translate(struct r300_context *r300) +{ +    struct pipe_context *pipe = &r300->context; + +    /* Restore vertex elements. */ +    pipe->bind_vertex_elements_state(pipe, r300->tran.saved_velems); +    pipe->delete_vertex_elements_state(pipe, r300->tran.new_velems); + +    /* Delete the now-unused VBO. */ +    pipe_resource_reference(&r300->vertex_buffer[r300->tran.vb_slot].buffer, +                            NULL); +} diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c index d19563c18a..afcb4d147d 100644 --- a/src/gallium/drivers/r300/r300_state.c +++ b/src/gallium/drivers/r300/r300_state.c @@ -1296,7 +1296,6 @@ static void* r300_create_vertex_elements_state(struct pipe_context* pipe,      if (velems != NULL) {          velems->count = count;          memcpy(velems->velem, attribs, sizeof(struct pipe_vertex_element) * count); -        velems->incompatible_layout = FALSE;          if (r300_screen(pipe->screen)->caps.has_tcl) {              /* Set the best hw format in case the original format is not | 
