r300g: rework vertex format fallback
[mesa.git] / src / gallium / drivers / r300 / r300_render_translate.c
1 /*
2 * Copyright 2010 Marek Olšák <maraeo@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 /**
24 * The functions below translate vertex and index buffers to the layout
25 * compatible with the hardware, so that all vertex and index fetches are
26 * DWORD-aligned and all used vertex and index formats are supported.
27 * For indices, an optional index offset is added to each index.
28 */
29
30 #include "r300_context.h"
31 #include "translate/translate.h"
32 #include "util/u_index_modify.h"
33 #include "util/u_upload_mgr.h"
34
35 void r300_begin_vertex_translate(struct r300_context *r300,
36 int min_index, int max_index)
37 {
38 struct pipe_context *pipe = &r300->context;
39 struct translate_key key = {0};
40 struct translate_element *te;
41 unsigned tr_elem_index[PIPE_MAX_ATTRIBS] = {0};
42 struct translate *tr;
43 struct r300_vertex_element_state *ve = r300->velems;
44 boolean vb_translated[PIPE_MAX_ATTRIBS] = {0};
45 uint8_t *vb_map[PIPE_MAX_ATTRIBS] = {0}, *out_map;
46 struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS] = {0};
47 struct pipe_resource *out_buffer = NULL;
48 unsigned i, num_verts, out_offset;
49 struct pipe_vertex_element new_velems[PIPE_MAX_ATTRIBS];
50 boolean flushed;
51
52 /* Initialize the translate key, i.e. the recipe how vertices should be
53 * translated. */
54 for (i = 0; i < ve->count; i++) {
55 struct pipe_vertex_buffer *vb =
56 &r300->vertex_buffer[ve->velem[i].vertex_buffer_index];
57 enum pipe_format output_format = ve->hw_format[i];
58 unsigned output_format_size = ve->hw_format_size[i];
59
60 /* Check for support. */
61 if (ve->velem[i].src_format == ve->hw_format[i] &&
62 /* These two are r300-specific. */
63 (vb->buffer_offset + ve->velem[i].src_offset) % 4 == 0 &&
64 vb->stride % 4 == 0) {
65 continue;
66 }
67
68 /* Workaround for translate: output floats instead of halfs. */
69 switch (output_format) {
70 case PIPE_FORMAT_R16_FLOAT:
71 output_format = PIPE_FORMAT_R32_FLOAT;
72 output_format_size = 4;
73 break;
74 case PIPE_FORMAT_R16G16_FLOAT:
75 output_format = PIPE_FORMAT_R32G32_FLOAT;
76 output_format_size = 8;
77 break;
78 case PIPE_FORMAT_R16G16B16_FLOAT:
79 output_format = PIPE_FORMAT_R32G32B32_FLOAT;
80 output_format_size = 12;
81 break;
82 case PIPE_FORMAT_R16G16B16A16_FLOAT:
83 output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
84 output_format_size = 16;
85 break;
86 default:;
87 }
88
89 /* Add this vertex element. */
90 te = &key.element[key.nr_elements];
91 /*te->type;
92 te->instance_divisor;*/
93 te->input_buffer = ve->velem[i].vertex_buffer_index;
94 te->input_format = ve->velem[i].src_format;
95 te->input_offset = ve->velem[i].src_offset;
96 te->output_format = output_format;
97 te->output_offset = key.output_stride;
98
99 key.output_stride += output_format_size;
100 vb_translated[ve->velem[i].vertex_buffer_index] = TRUE;
101 tr_elem_index[i] = key.nr_elements;
102 key.nr_elements++;
103 }
104
105 /* Get a translate object. */
106 tr = translate_cache_find(r300->tran.translate_cache, &key);
107
108 /* Map buffers we want to translate. */
109 for (i = 0; i < r300->vertex_buffer_count; i++) {
110 if (vb_translated[i]) {
111 struct pipe_vertex_buffer *vb = &r300->vertex_buffer[i];
112
113 vb_map[i] = pipe_buffer_map(pipe, vb->buffer,
114 PIPE_TRANSFER_READ, &vb_transfer[i]);
115
116 tr->set_buffer(tr, i,
117 vb_map[i] + vb->buffer_offset + vb->stride * min_index,
118 vb->stride, ~0);
119 }
120 }
121
122 /* Create and map the output buffer. */
123 num_verts = max_index + 1 - min_index;
124
125 u_upload_alloc(r300->upload_vb,
126 key.output_stride * min_index,
127 key.output_stride * num_verts,
128 &out_offset, &out_buffer, &flushed,
129 (void**)&out_map);
130
131 out_offset -= key.output_stride * min_index;
132
133 /* Translate. */
134 tr->run(tr, 0, num_verts, 0, out_map);
135
136 /* Unmap all buffers. */
137 for (i = 0; i < r300->vertex_buffer_count; i++) {
138 if (vb_translated[i]) {
139 pipe_buffer_unmap(pipe, vb_transfer[i]);
140 }
141 }
142
143 /* Setup the new vertex buffer in the first free slot. */
144 r300->tran.vb_slot = ~0;
145 for (i = 0; i < PIPE_MAX_ATTRIBS; i++) {
146 if (!r300->vertex_buffer[i].buffer) {
147 r300->tran.vb_slot = i;
148
149 if (i >= r300->vertex_buffer_count) {
150 r300->real_vertex_buffer_count = i+1;
151 }
152
153 /* r300-specific: */
154 r300->validate_buffers = TRUE;
155 r300->vertex_arrays_dirty = TRUE;
156 break;
157 }
158 }
159
160 if (r300->tran.vb_slot != ~0) {
161 /* Setup the new vertex buffer. */
162 pipe_resource_reference(&r300->real_vertex_buffer[r300->tran.vb_slot], out_buffer);
163 r300->vertex_buffer[r300->tran.vb_slot].buffer_offset = out_offset;
164 r300->vertex_buffer[r300->tran.vb_slot].stride = key.output_stride;
165
166 /* Setup new vertex elements. */
167 for (i = 0; i < ve->count; i++) {
168 if (vb_translated[ve->velem[i].vertex_buffer_index]) {
169 te = &key.element[tr_elem_index[i]];
170 new_velems[i].instance_divisor = ve->velem[i].instance_divisor;
171 new_velems[i].src_format = te->output_format;
172 new_velems[i].src_offset = te->output_offset;
173 new_velems[i].vertex_buffer_index = r300->tran.vb_slot;
174 } else {
175 memcpy(&new_velems[i], &ve->velem[i],
176 sizeof(struct pipe_vertex_element));
177 }
178 }
179
180 r300->tran.saved_velems = r300->velems;
181 r300->tran.new_velems =
182 pipe->create_vertex_elements_state(pipe, ve->count, new_velems);
183 pipe->bind_vertex_elements_state(pipe, r300->tran.new_velems);
184 }
185
186 pipe_resource_reference(&out_buffer, NULL);
187 }
188
189 void r300_end_vertex_translate(struct r300_context *r300)
190 {
191 struct pipe_context *pipe = &r300->context;
192
193 if (r300->tran.new_velems == NULL) {
194 return;
195 }
196
197 /* Restore vertex elements. */
198 pipe->bind_vertex_elements_state(pipe, r300->tran.saved_velems);
199 r300->tran.saved_velems = NULL;
200 pipe->delete_vertex_elements_state(pipe, r300->tran.new_velems);
201 r300->tran.new_velems = NULL;
202
203 /* Delete the now-unused VBO. */
204 pipe_resource_reference(&r300->real_vertex_buffer[r300->tran.vb_slot], NULL);
205 r300->real_vertex_buffer_count = r300->vertex_buffer_count;
206 }
207
208 /* XXX Use the uploader. */
209 void r300_translate_index_buffer(struct r300_context *r300,
210 struct pipe_resource **index_buffer,
211 unsigned *index_size, unsigned index_offset,
212 unsigned *start, unsigned count)
213 {
214 switch (*index_size) {
215 case 1:
216 util_shorten_ubyte_elts(&r300->context, index_buffer, index_offset, *start, count);
217 *index_size = 2;
218 *start = 0;
219 r300->validate_buffers = TRUE;
220 break;
221
222 case 2:
223 if (index_offset) {
224 util_rebuild_ushort_elts(&r300->context, index_buffer, index_offset, *start, count);
225 *start = 0;
226 r300->validate_buffers = TRUE;
227 }
228 break;
229
230 case 4:
231 if (index_offset) {
232 util_rebuild_uint_elts(&r300->context, index_buffer, index_offset, *start, count);
233 *start = 0;
234 r300->validate_buffers = TRUE;
235 }
236 break;
237 }
238 }