Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. |
||
4 | * All Rights Reserved. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * copy of this software and associated documentation files (the |
||
8 | * "Software"), to deal in the Software without restriction, including |
||
9 | * without limitation the rights to use, copy, modify, merge, publish, |
||
10 | * distribute, sub license, and/or sell copies of the Software, and to |
||
11 | * permit persons to whom the Software is furnished to do so, subject to |
||
12 | * the following conditions: |
||
13 | * |
||
14 | * The above copyright notice and this permission notice (including the |
||
15 | * next paragraph) shall be included in all copies or substantial portions |
||
16 | * of the Software. |
||
17 | * |
||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
||
21 | * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
||
22 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||
24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
25 | * |
||
26 | **************************************************************************/ |
||
27 | |||
28 | /* Authors: |
||
29 | * Brian Paul |
||
30 | */ |
||
31 | |||
32 | #include "util/u_inlines.h" |
||
33 | #include "util/u_memory.h" |
||
34 | |||
35 | #include "draw/draw_context.h" |
||
36 | |||
37 | #include "lp_context.h" |
||
38 | #include "lp_screen.h" |
||
39 | #include "lp_state.h" |
||
40 | #include "lp_debug.h" |
||
41 | #include "state_tracker/sw_winsys.h" |
||
42 | |||
43 | |||
44 | static void * |
||
45 | llvmpipe_create_sampler_state(struct pipe_context *pipe, |
||
46 | const struct pipe_sampler_state *sampler) |
||
47 | { |
||
48 | struct pipe_sampler_state *state = mem_dup(sampler, sizeof *sampler); |
||
49 | |||
50 | if (LP_PERF & PERF_NO_MIP_LINEAR) { |
||
51 | if (state->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR) |
||
52 | state->min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; |
||
53 | } |
||
54 | |||
55 | if (LP_PERF & PERF_NO_MIPMAPS) |
||
56 | state->min_mip_filter = PIPE_TEX_MIPFILTER_NONE; |
||
57 | |||
58 | if (LP_PERF & PERF_NO_LINEAR) { |
||
59 | state->mag_img_filter = PIPE_TEX_FILTER_NEAREST; |
||
60 | state->min_img_filter = PIPE_TEX_FILTER_NEAREST; |
||
61 | } |
||
62 | |||
63 | return state; |
||
64 | } |
||
65 | |||
66 | |||
67 | static void |
||
68 | llvmpipe_bind_sampler_states(struct pipe_context *pipe, |
||
69 | unsigned shader, |
||
70 | unsigned start, |
||
71 | unsigned num, |
||
72 | void **samplers) |
||
73 | { |
||
74 | struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe); |
||
75 | unsigned i; |
||
76 | |||
77 | assert(shader < PIPE_SHADER_TYPES); |
||
78 | assert(start + num <= Elements(llvmpipe->samplers[shader])); |
||
79 | |||
80 | /* Check for no-op */ |
||
81 | if (start + num <= llvmpipe->num_samplers[shader] && |
||
82 | !memcmp(llvmpipe->samplers[shader] + start, samplers, |
||
83 | num * sizeof(void *))) { |
||
84 | return; |
||
85 | } |
||
86 | |||
87 | draw_flush(llvmpipe->draw); |
||
88 | |||
89 | /* set the new samplers */ |
||
90 | for (i = 0; i < num; i++) { |
||
91 | llvmpipe->samplers[shader][start + i] = samplers[i]; |
||
92 | } |
||
93 | |||
94 | /* find highest non-null samplers[] entry */ |
||
95 | { |
||
96 | unsigned j = MAX2(llvmpipe->num_samplers[shader], start + num); |
||
97 | while (j > 0 && llvmpipe->samplers[shader][j - 1] == NULL) |
||
98 | j--; |
||
99 | llvmpipe->num_samplers[shader] = j; |
||
100 | } |
||
101 | |||
102 | if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) { |
||
103 | draw_set_samplers(llvmpipe->draw, |
||
104 | shader, |
||
105 | llvmpipe->samplers[shader], |
||
106 | llvmpipe->num_samplers[shader]); |
||
107 | } |
||
108 | |||
109 | llvmpipe->dirty |= LP_NEW_SAMPLER; |
||
110 | } |
||
111 | |||
112 | |||
113 | static void |
||
114 | llvmpipe_bind_fragment_sampler_states(struct pipe_context *pipe, |
||
115 | unsigned num, void **samplers) |
||
116 | { |
||
117 | llvmpipe_bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, num, samplers); |
||
118 | } |
||
119 | |||
120 | |||
121 | static void |
||
122 | llvmpipe_bind_vertex_sampler_states(struct pipe_context *pipe, |
||
123 | unsigned num, void **samplers) |
||
124 | { |
||
125 | llvmpipe_bind_sampler_states(pipe, PIPE_SHADER_VERTEX, 0, num, samplers); |
||
126 | } |
||
127 | |||
128 | |||
129 | static void |
||
130 | llvmpipe_bind_geometry_sampler_states(struct pipe_context *pipe, |
||
131 | unsigned num, void **samplers) |
||
132 | { |
||
133 | llvmpipe_bind_sampler_states(pipe, PIPE_SHADER_GEOMETRY, 0, num, samplers); |
||
134 | } |
||
135 | |||
136 | static void |
||
137 | llvmpipe_set_sampler_views(struct pipe_context *pipe, |
||
138 | unsigned shader, |
||
139 | unsigned start, |
||
140 | unsigned num, |
||
141 | struct pipe_sampler_view **views) |
||
142 | { |
||
143 | struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe); |
||
144 | uint i; |
||
145 | |||
146 | assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS); |
||
147 | |||
148 | assert(shader < PIPE_SHADER_TYPES); |
||
149 | assert(start + num <= Elements(llvmpipe->sampler_views[shader])); |
||
150 | |||
151 | /* Check for no-op */ |
||
152 | if (start + num <= llvmpipe->num_sampler_views[shader] && |
||
153 | !memcmp(llvmpipe->sampler_views[shader] + start, views, |
||
154 | num * sizeof(struct pipe_sampler_view *))) { |
||
155 | return; |
||
156 | } |
||
157 | |||
158 | draw_flush(llvmpipe->draw); |
||
159 | |||
160 | /* set the new sampler views */ |
||
161 | for (i = 0; i < num; i++) { |
||
162 | pipe_sampler_view_reference(&llvmpipe->sampler_views[shader][start + i], |
||
163 | views[i]); |
||
164 | } |
||
165 | |||
166 | /* find highest non-null sampler_views[] entry */ |
||
167 | { |
||
168 | unsigned j = MAX2(llvmpipe->num_sampler_views[shader], start + num); |
||
169 | while (j > 0 && llvmpipe->sampler_views[shader][j - 1] == NULL) |
||
170 | j--; |
||
171 | llvmpipe->num_sampler_views[shader] = j; |
||
172 | } |
||
173 | |||
174 | if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) { |
||
175 | draw_set_sampler_views(llvmpipe->draw, |
||
176 | shader, |
||
177 | llvmpipe->sampler_views[shader], |
||
178 | llvmpipe->num_sampler_views[shader]); |
||
179 | } |
||
180 | |||
181 | llvmpipe->dirty |= LP_NEW_SAMPLER_VIEW; |
||
182 | } |
||
183 | |||
184 | |||
185 | static void |
||
186 | llvmpipe_set_fragment_sampler_views(struct pipe_context *pipe, |
||
187 | unsigned num, |
||
188 | struct pipe_sampler_view **views) |
||
189 | { |
||
190 | llvmpipe_set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, num, views); |
||
191 | } |
||
192 | |||
193 | |||
194 | static void |
||
195 | llvmpipe_set_vertex_sampler_views(struct pipe_context *pipe, |
||
196 | unsigned num, |
||
197 | struct pipe_sampler_view **views) |
||
198 | { |
||
199 | llvmpipe_set_sampler_views(pipe, PIPE_SHADER_VERTEX, 0, num, views); |
||
200 | } |
||
201 | |||
202 | |||
203 | static void |
||
204 | llvmpipe_set_geometry_sampler_views(struct pipe_context *pipe, |
||
205 | unsigned num, |
||
206 | struct pipe_sampler_view **views) |
||
207 | { |
||
208 | llvmpipe_set_sampler_views(pipe, PIPE_SHADER_GEOMETRY, 0, num, views); |
||
209 | } |
||
210 | |||
211 | static struct pipe_sampler_view * |
||
212 | llvmpipe_create_sampler_view(struct pipe_context *pipe, |
||
213 | struct pipe_resource *texture, |
||
214 | const struct pipe_sampler_view *templ) |
||
215 | { |
||
216 | struct pipe_sampler_view *view = CALLOC_STRUCT(pipe_sampler_view); |
||
217 | /* |
||
218 | * XXX we REALLY want to see the correct bind flag here but the OpenGL |
||
219 | * state tracker can't guarantee that at least for texture buffer objects. |
||
220 | */ |
||
221 | if (!(texture->bind & PIPE_BIND_SAMPLER_VIEW)) |
||
222 | debug_printf("Illegal sampler view creation without bind flag\n"); |
||
223 | |||
224 | if (view) { |
||
225 | *view = *templ; |
||
226 | view->reference.count = 1; |
||
227 | view->texture = NULL; |
||
228 | pipe_resource_reference(&view->texture, texture); |
||
229 | view->context = pipe; |
||
230 | } |
||
231 | |||
232 | return view; |
||
233 | } |
||
234 | |||
235 | |||
236 | static void |
||
237 | llvmpipe_sampler_view_destroy(struct pipe_context *pipe, |
||
238 | struct pipe_sampler_view *view) |
||
239 | { |
||
240 | pipe_resource_reference(&view->texture, NULL); |
||
241 | FREE(view); |
||
242 | } |
||
243 | |||
244 | |||
245 | static void |
||
246 | llvmpipe_delete_sampler_state(struct pipe_context *pipe, |
||
247 | void *sampler) |
||
248 | { |
||
249 | FREE( sampler ); |
||
250 | } |
||
251 | |||
252 | |||
253 | static void |
||
254 | prepare_shader_sampling( |
||
255 | struct llvmpipe_context *lp, |
||
256 | unsigned num, |
||
257 | struct pipe_sampler_view **views, |
||
258 | unsigned shader_type, |
||
259 | struct pipe_resource *mapped_tex[PIPE_MAX_SHADER_SAMPLER_VIEWS]) |
||
260 | { |
||
261 | |||
262 | unsigned i; |
||
263 | uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS]; |
||
264 | uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS]; |
||
265 | uint32_t mip_offsets[PIPE_MAX_TEXTURE_LEVELS]; |
||
266 | const void *addr; |
||
267 | |||
268 | assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS); |
||
269 | if (!num) |
||
270 | return; |
||
271 | |||
272 | for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) { |
||
273 | struct pipe_sampler_view *view = i < num ? views[i] : NULL; |
||
274 | |||
275 | if (view) { |
||
276 | struct pipe_resource *tex = view->texture; |
||
277 | struct llvmpipe_resource *lp_tex = llvmpipe_resource(tex); |
||
278 | unsigned width0 = tex->width0; |
||
279 | unsigned num_layers = tex->depth0; |
||
280 | unsigned first_level = 0; |
||
281 | unsigned last_level = 0; |
||
282 | |||
283 | /* We're referencing the texture's internal data, so save a |
||
284 | * reference to it. |
||
285 | */ |
||
286 | pipe_resource_reference(&mapped_tex[i], tex); |
||
287 | |||
288 | if (!lp_tex->dt) { |
||
289 | /* regular texture - setup array of mipmap level offsets */ |
||
290 | struct pipe_resource *res = view->texture; |
||
291 | int j; |
||
292 | void *mip_ptr; |
||
293 | |||
294 | if (llvmpipe_resource_is_texture(res)) { |
||
295 | first_level = view->u.tex.first_level; |
||
296 | last_level = view->u.tex.last_level; |
||
297 | assert(first_level <= last_level); |
||
298 | assert(last_level <= res->last_level); |
||
299 | |||
300 | /* must trigger allocation first before we can get base ptr */ |
||
301 | /* XXX this may fail due to OOM ? */ |
||
302 | mip_ptr = llvmpipe_get_texture_image_all(lp_tex, view->u.tex.first_level, |
||
303 | LP_TEX_USAGE_READ); |
||
304 | addr = lp_tex->linear_img.data; |
||
305 | |||
306 | for (j = first_level; j <= last_level; j++) { |
||
307 | mip_ptr = llvmpipe_get_texture_image_all(lp_tex, j, |
||
308 | LP_TEX_USAGE_READ); |
||
309 | mip_offsets[j] = (uint8_t *)mip_ptr - (uint8_t *)addr; |
||
310 | /* |
||
311 | * could get mip offset directly but need call above to |
||
312 | * invoke tiled->linear conversion. |
||
313 | */ |
||
314 | assert(lp_tex->linear_mip_offsets[j] == mip_offsets[j]); |
||
315 | row_stride[j] = lp_tex->row_stride[j]; |
||
316 | img_stride[j] = lp_tex->img_stride[j]; |
||
317 | } |
||
318 | if (res->target == PIPE_TEXTURE_1D_ARRAY || |
||
319 | res->target == PIPE_TEXTURE_2D_ARRAY) { |
||
320 | num_layers = view->u.tex.last_layer - view->u.tex.first_layer + 1; |
||
321 | for (j = first_level; j <= last_level; j++) { |
||
322 | mip_offsets[j] += view->u.tex.first_layer * |
||
323 | lp_tex->img_stride[j]; |
||
324 | } |
||
325 | assert(view->u.tex.first_layer <= view->u.tex.last_layer); |
||
326 | assert(view->u.tex.last_layer < res->array_size); |
||
327 | } |
||
328 | } |
||
329 | else { |
||
330 | unsigned view_blocksize = util_format_get_blocksize(view->format); |
||
331 | mip_ptr = lp_tex->data; |
||
332 | addr = mip_ptr; |
||
333 | /* probably don't really need to fill that out */ |
||
334 | mip_offsets[0] = 0; |
||
335 | row_stride[0] = 0; |
||
336 | row_stride[0] = 0; |
||
337 | |||
338 | /* everything specified in number of elements here. */ |
||
339 | width0 = view->u.buf.last_element - view->u.buf.first_element + 1; |
||
340 | addr = (uint8_t *)addr + view->u.buf.first_element * |
||
341 | view_blocksize; |
||
342 | assert(view->u.buf.first_element <= view->u.buf.last_element); |
||
343 | assert(view->u.buf.last_element * view_blocksize < res->width0); |
||
344 | } |
||
345 | } |
||
346 | else { |
||
347 | /* display target texture/surface */ |
||
348 | /* |
||
349 | * XXX: Where should this be unmapped? |
||
350 | */ |
||
351 | struct llvmpipe_screen *screen = llvmpipe_screen(tex->screen); |
||
352 | struct sw_winsys *winsys = screen->winsys; |
||
353 | addr = winsys->displaytarget_map(winsys, lp_tex->dt, |
||
354 | PIPE_TRANSFER_READ); |
||
355 | row_stride[0] = lp_tex->row_stride[0]; |
||
356 | img_stride[0] = lp_tex->img_stride[0]; |
||
357 | mip_offsets[0] = 0; |
||
358 | assert(addr); |
||
359 | } |
||
360 | draw_set_mapped_texture(lp->draw, |
||
361 | shader_type, |
||
362 | i, |
||
363 | width0, tex->height0, num_layers, |
||
364 | first_level, last_level, |
||
365 | addr, |
||
366 | row_stride, img_stride, mip_offsets); |
||
367 | } |
||
368 | } |
||
369 | } |
||
370 | |||
371 | |||
372 | /** |
||
373 | * Called during state validation when LP_NEW_SAMPLER_VIEW is set. |
||
374 | */ |
||
375 | void |
||
376 | llvmpipe_prepare_vertex_sampling(struct llvmpipe_context *lp, |
||
377 | unsigned num, |
||
378 | struct pipe_sampler_view **views) |
||
379 | { |
||
380 | prepare_shader_sampling(lp, num, views, PIPE_SHADER_VERTEX, |
||
381 | lp->mapped_vs_tex); |
||
382 | } |
||
383 | |||
384 | void |
||
385 | llvmpipe_cleanup_vertex_sampling(struct llvmpipe_context *ctx) |
||
386 | { |
||
387 | unsigned i; |
||
388 | for (i = 0; i < Elements(ctx->mapped_vs_tex); i++) { |
||
389 | pipe_resource_reference(&ctx->mapped_vs_tex[i], NULL); |
||
390 | } |
||
391 | } |
||
392 | |||
393 | |||
394 | /** |
||
395 | * Called during state validation when LP_NEW_SAMPLER_VIEW is set. |
||
396 | */ |
||
397 | void |
||
398 | llvmpipe_prepare_geometry_sampling(struct llvmpipe_context *lp, |
||
399 | unsigned num, |
||
400 | struct pipe_sampler_view **views) |
||
401 | { |
||
402 | prepare_shader_sampling(lp, num, views, PIPE_SHADER_GEOMETRY, |
||
403 | lp->mapped_gs_tex); |
||
404 | } |
||
405 | |||
406 | void |
||
407 | llvmpipe_cleanup_geometry_sampling(struct llvmpipe_context *ctx) |
||
408 | { |
||
409 | unsigned i; |
||
410 | for (i = 0; i < Elements(ctx->mapped_gs_tex); i++) { |
||
411 | pipe_resource_reference(&ctx->mapped_gs_tex[i], NULL); |
||
412 | } |
||
413 | } |
||
414 | |||
415 | void |
||
416 | llvmpipe_init_sampler_funcs(struct llvmpipe_context *llvmpipe) |
||
417 | { |
||
418 | llvmpipe->pipe.create_sampler_state = llvmpipe_create_sampler_state; |
||
419 | |||
420 | llvmpipe->pipe.bind_fragment_sampler_states = llvmpipe_bind_fragment_sampler_states; |
||
421 | llvmpipe->pipe.bind_vertex_sampler_states = llvmpipe_bind_vertex_sampler_states; |
||
422 | llvmpipe->pipe.bind_geometry_sampler_states = llvmpipe_bind_geometry_sampler_states; |
||
423 | llvmpipe->pipe.set_fragment_sampler_views = llvmpipe_set_fragment_sampler_views; |
||
424 | llvmpipe->pipe.set_vertex_sampler_views = llvmpipe_set_vertex_sampler_views; |
||
425 | llvmpipe->pipe.set_geometry_sampler_views = llvmpipe_set_geometry_sampler_views; |
||
426 | llvmpipe->pipe.create_sampler_view = llvmpipe_create_sampler_view; |
||
427 | llvmpipe->pipe.sampler_view_destroy = llvmpipe_sampler_view_destroy; |
||
428 | llvmpipe->pipe.delete_sampler_state = llvmpipe_delete_sampler_state; |
||
429 | }>>>=>>=>=>=>=>=>>>=>>=>=>>=>>=>=>> |