Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2006 VMware, Inc. |
||
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 VMWARE 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 | * Keith Whitwell |
||
30 | * Michel Dänzer |
||
31 | */ |
||
32 | |||
33 | #include "pipe/p_state.h" |
||
34 | #include "pipe/p_context.h" |
||
35 | #include "pipe/p_defines.h" |
||
36 | #include "util/u_inlines.h" |
||
37 | #include "util/u_format.h" |
||
38 | #include "util/u_math.h" |
||
39 | #include "util/u_memory.h" |
||
40 | #include "util/u_rect.h" |
||
41 | |||
42 | #include "i915_context.h" |
||
43 | #include "i915_resource.h" |
||
44 | #include "i915_screen.h" |
||
45 | #include "i915_winsys.h" |
||
46 | #include "i915_debug.h" |
||
47 | |||
48 | |||
49 | #define DEBUG_TEXTURES 0 |
||
50 | |||
51 | /* |
||
52 | * Helper function and arrays |
||
53 | */ |
||
54 | |||
55 | |||
56 | /** |
||
57 | * Initial offset for Cube map. |
||
58 | */ |
||
59 | static const int initial_offsets[6][2] = { |
||
60 | [PIPE_TEX_FACE_POS_X] = {0, 0}, |
||
61 | [PIPE_TEX_FACE_POS_Y] = {1, 0}, |
||
62 | [PIPE_TEX_FACE_POS_Z] = {1, 1}, |
||
63 | [PIPE_TEX_FACE_NEG_X] = {0, 2}, |
||
64 | [PIPE_TEX_FACE_NEG_Y] = {1, 2}, |
||
65 | [PIPE_TEX_FACE_NEG_Z] = {1, 3}, |
||
66 | }; |
||
67 | |||
68 | /** |
||
69 | * Step offsets for Cube map. |
||
70 | */ |
||
71 | static const int step_offsets[6][2] = { |
||
72 | [PIPE_TEX_FACE_POS_X] = { 0, 2}, |
||
73 | [PIPE_TEX_FACE_POS_Y] = {-1, 2}, |
||
74 | [PIPE_TEX_FACE_POS_Z] = {-1, 1}, |
||
75 | [PIPE_TEX_FACE_NEG_X] = { 0, 2}, |
||
76 | [PIPE_TEX_FACE_NEG_Y] = {-1, 2}, |
||
77 | [PIPE_TEX_FACE_NEG_Z] = {-1, 1}, |
||
78 | }; |
||
79 | |||
80 | /** |
||
81 | * For compressed level 2 |
||
82 | */ |
||
83 | static const int bottom_offsets[6] = { |
||
84 | [PIPE_TEX_FACE_POS_X] = 16 + 0 * 8, |
||
85 | [PIPE_TEX_FACE_POS_Y] = 16 + 1 * 8, |
||
86 | [PIPE_TEX_FACE_POS_Z] = 16 + 2 * 8, |
||
87 | [PIPE_TEX_FACE_NEG_X] = 16 + 3 * 8, |
||
88 | [PIPE_TEX_FACE_NEG_Y] = 16 + 4 * 8, |
||
89 | [PIPE_TEX_FACE_NEG_Z] = 16 + 5 * 8, |
||
90 | }; |
||
91 | |||
92 | static INLINE unsigned |
||
93 | align_nblocksx(enum pipe_format format, unsigned width, unsigned align_to) |
||
94 | { |
||
95 | return align(util_format_get_nblocksx(format, width), align_to); |
||
96 | } |
||
97 | |||
98 | static INLINE unsigned |
||
99 | align_nblocksy(enum pipe_format format, unsigned width, unsigned align_to) |
||
100 | { |
||
101 | return align(util_format_get_nblocksy(format, width), align_to); |
||
102 | } |
||
103 | |||
104 | static INLINE unsigned |
||
105 | get_pot_stride(enum pipe_format format, unsigned width) |
||
106 | { |
||
107 | return util_next_power_of_two(util_format_get_stride(format, width)); |
||
108 | } |
||
109 | |||
110 | static INLINE const char* |
||
111 | get_tiling_string(enum i915_winsys_buffer_tile tile) |
||
112 | { |
||
113 | switch(tile) { |
||
114 | case I915_TILE_NONE: |
||
115 | return "none"; |
||
116 | case I915_TILE_X: |
||
117 | return "x"; |
||
118 | case I915_TILE_Y: |
||
119 | return "y"; |
||
120 | default: |
||
121 | assert(FALSE); |
||
122 | return "?"; |
||
123 | } |
||
124 | } |
||
125 | |||
126 | |||
127 | /* |
||
128 | * More advanced helper funcs |
||
129 | */ |
||
130 | |||
131 | |||
132 | static void |
||
133 | i915_texture_set_level_info(struct i915_texture *tex, |
||
134 | unsigned level, unsigned nr_images) |
||
135 | { |
||
136 | assert(level < Elements(tex->nr_images)); |
||
137 | assert(nr_images); |
||
138 | assert(!tex->image_offset[level]); |
||
139 | |||
140 | tex->nr_images[level] = nr_images; |
||
141 | tex->image_offset[level] = MALLOC(nr_images * sizeof(struct offset_pair)); |
||
142 | tex->image_offset[level][0].nblocksx = 0; |
||
143 | tex->image_offset[level][0].nblocksy = 0; |
||
144 | } |
||
145 | |||
146 | unsigned i915_texture_offset(const struct i915_texture *tex, |
||
147 | unsigned level, unsigned layer) |
||
148 | { |
||
149 | unsigned x, y; |
||
150 | x = tex->image_offset[level][layer].nblocksx |
||
151 | * util_format_get_blocksize(tex->b.b.format); |
||
152 | y = tex->image_offset[level][layer].nblocksy; |
||
153 | |||
154 | return y * tex->stride + x; |
||
155 | } |
||
156 | |||
157 | static void |
||
158 | i915_texture_set_image_offset(struct i915_texture *tex, |
||
159 | unsigned level, unsigned img, |
||
160 | unsigned nblocksx, unsigned nblocksy) |
||
161 | { |
||
162 | /* for the first image and level make sure offset is zero */ |
||
163 | assert(!(img == 0 && level == 0) || (nblocksx == 0 && nblocksy == 0)); |
||
164 | assert(img < tex->nr_images[level]); |
||
165 | |||
166 | tex->image_offset[level][img].nblocksx = nblocksx; |
||
167 | tex->image_offset[level][img].nblocksy = nblocksy; |
||
168 | |||
169 | #if DEBUG_TEXTURES |
||
170 | debug_printf("%s: %p level %u, img %u (%u, %u)\n", __FUNCTION__, |
||
171 | tex, level, img, x, y); |
||
172 | #endif |
||
173 | } |
||
174 | |||
175 | static enum i915_winsys_buffer_tile |
||
176 | i915_texture_tiling(struct i915_screen *is, struct i915_texture *tex) |
||
177 | { |
||
178 | if (!is->debug.tiling) |
||
179 | return I915_TILE_NONE; |
||
180 | |||
181 | if (tex->b.b.target == PIPE_TEXTURE_1D) |
||
182 | return I915_TILE_NONE; |
||
183 | |||
184 | if (util_format_is_s3tc(tex->b.b.format)) |
||
185 | return I915_TILE_X; |
||
186 | |||
187 | if (is->debug.use_blitter) |
||
188 | return I915_TILE_X; |
||
189 | else |
||
190 | return I915_TILE_Y; |
||
191 | } |
||
192 | |||
193 | |||
194 | /* |
||
195 | * Shared layout functions |
||
196 | */ |
||
197 | |||
198 | |||
199 | /** |
||
200 | * Special case to deal with scanout textures. |
||
201 | */ |
||
202 | static boolean |
||
203 | i9x5_scanout_layout(struct i915_texture *tex) |
||
204 | { |
||
205 | struct pipe_resource *pt = &tex->b.b; |
||
206 | |||
207 | if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4) |
||
208 | return FALSE; |
||
209 | |||
210 | i915_texture_set_level_info(tex, 0, 1); |
||
211 | i915_texture_set_image_offset(tex, 0, 0, 0, 0); |
||
212 | |||
213 | if (pt->width0 >= 240) { |
||
214 | tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64); |
||
215 | tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8); |
||
216 | tex->tiling = I915_TILE_X; |
||
217 | /* special case for cursors */ |
||
218 | } else if (pt->width0 == 64 && pt->height0 == 64) { |
||
219 | tex->stride = get_pot_stride(pt->format, pt->width0); |
||
220 | tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8); |
||
221 | } else { |
||
222 | return FALSE; |
||
223 | } |
||
224 | |||
225 | #if DEBUG_TEXTURE |
||
226 | debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__, |
||
227 | pt->width0, pt->height0, util_format_get_blocksize(pt->format), |
||
228 | tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy); |
||
229 | #endif |
||
230 | |||
231 | return TRUE; |
||
232 | } |
||
233 | |||
234 | /** |
||
235 | * Special case to deal with shared textures. |
||
236 | */ |
||
237 | static boolean |
||
238 | i9x5_display_target_layout(struct i915_texture *tex) |
||
239 | { |
||
240 | struct pipe_resource *pt = &tex->b.b; |
||
241 | |||
242 | if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4) |
||
243 | return FALSE; |
||
244 | |||
245 | /* fallback to normal textures for small textures */ |
||
246 | if (pt->width0 < 240) |
||
247 | return FALSE; |
||
248 | |||
249 | i915_texture_set_level_info(tex, 0, 1); |
||
250 | i915_texture_set_image_offset(tex, 0, 0, 0, 0); |
||
251 | |||
252 | tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64); |
||
253 | tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8); |
||
254 | tex->tiling = I915_TILE_X; |
||
255 | |||
256 | #if DEBUG_TEXTURE |
||
257 | debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__, |
||
258 | pt->width0, pt->height0, util_format_get_blocksize(pt->format), |
||
259 | tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy); |
||
260 | #endif |
||
261 | |||
262 | return TRUE; |
||
263 | } |
||
264 | |||
265 | /** |
||
266 | * Helper function for special layouts |
||
267 | */ |
||
268 | static boolean |
||
269 | i9x5_special_layout(struct i915_texture *tex) |
||
270 | { |
||
271 | struct pipe_resource *pt = &tex->b.b; |
||
272 | |||
273 | /* Scanouts needs special care */ |
||
274 | if (pt->bind & PIPE_BIND_SCANOUT) |
||
275 | if (i9x5_scanout_layout(tex)) |
||
276 | return TRUE; |
||
277 | |||
278 | /* Shared buffers needs to be compatible with X servers |
||
279 | * |
||
280 | * XXX: need a better name than shared for this if it is to be part |
||
281 | * of core gallium, and probably move the flag to resource.flags, |
||
282 | * rather than bindings. |
||
283 | */ |
||
284 | if (pt->bind & (PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET)) |
||
285 | if (i9x5_display_target_layout(tex)) |
||
286 | return TRUE; |
||
287 | |||
288 | return FALSE; |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * Cube layout used on i915 and for non-compressed textures on i945. |
||
293 | */ |
||
294 | static void |
||
295 | i9x5_texture_layout_cube(struct i915_texture *tex) |
||
296 | { |
||
297 | struct pipe_resource *pt = &tex->b.b; |
||
298 | unsigned width = util_next_power_of_two(pt->width0); |
||
299 | const unsigned nblocks = util_format_get_nblocksx(pt->format, width); |
||
300 | unsigned level; |
||
301 | unsigned face; |
||
302 | |||
303 | assert(pt->width0 == pt->height0); /* cubemap images are square */ |
||
304 | |||
305 | /* double pitch for cube layouts */ |
||
306 | tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4); |
||
307 | tex->total_nblocksy = nblocks * 4; |
||
308 | |||
309 | for (level = 0; level <= pt->last_level; level++) |
||
310 | i915_texture_set_level_info(tex, level, 6); |
||
311 | |||
312 | for (face = 0; face < 6; face++) { |
||
313 | unsigned x = initial_offsets[face][0] * nblocks; |
||
314 | unsigned y = initial_offsets[face][1] * nblocks; |
||
315 | unsigned d = nblocks; |
||
316 | |||
317 | for (level = 0; level <= pt->last_level; level++) { |
||
318 | i915_texture_set_image_offset(tex, level, face, x, y); |
||
319 | d >>= 1; |
||
320 | x += step_offsets[face][0] * d; |
||
321 | y += step_offsets[face][1] * d; |
||
322 | } |
||
323 | } |
||
324 | } |
||
325 | |||
326 | |||
327 | /* |
||
328 | * i915 layout functions |
||
329 | */ |
||
330 | |||
331 | |||
332 | static void |
||
333 | i915_texture_layout_2d(struct i915_texture *tex) |
||
334 | { |
||
335 | struct pipe_resource *pt = &tex->b.b; |
||
336 | unsigned level; |
||
337 | unsigned width = util_next_power_of_two(pt->width0); |
||
338 | unsigned height = util_next_power_of_two(pt->height0); |
||
339 | unsigned nblocksy = util_format_get_nblocksy(pt->format, width); |
||
340 | unsigned align_y = 2; |
||
341 | |||
342 | if (util_format_is_s3tc(pt->format)) |
||
343 | align_y = 1; |
||
344 | |||
345 | tex->stride = align(util_format_get_stride(pt->format, width), 4); |
||
346 | tex->total_nblocksy = 0; |
||
347 | |||
348 | for (level = 0; level <= pt->last_level; level++) { |
||
349 | i915_texture_set_level_info(tex, level, 1); |
||
350 | i915_texture_set_image_offset(tex, level, 0, 0, tex->total_nblocksy); |
||
351 | |||
352 | tex->total_nblocksy += nblocksy; |
||
353 | |||
354 | width = u_minify(width, 1); |
||
355 | height = u_minify(height, 1); |
||
356 | nblocksy = align_nblocksy(pt->format, height, align_y); |
||
357 | } |
||
358 | } |
||
359 | |||
360 | static void |
||
361 | i915_texture_layout_3d(struct i915_texture *tex) |
||
362 | { |
||
363 | struct pipe_resource *pt = &tex->b.b; |
||
364 | unsigned level; |
||
365 | |||
366 | unsigned width = util_next_power_of_two(pt->width0); |
||
367 | unsigned height = util_next_power_of_two(pt->height0); |
||
368 | unsigned depth = util_next_power_of_two(pt->depth0); |
||
369 | unsigned nblocksy = util_format_get_nblocksy(pt->format, height); |
||
370 | unsigned stack_nblocksy = 0; |
||
371 | |||
372 | /* Calculate the size of a single slice. |
||
373 | */ |
||
374 | tex->stride = align(util_format_get_stride(pt->format, width), 4); |
||
375 | |||
376 | /* XXX: hardware expects/requires 9 levels at minimum. |
||
377 | */ |
||
378 | for (level = 0; level <= MAX2(8, pt->last_level); level++) { |
||
379 | i915_texture_set_level_info(tex, level, depth); |
||
380 | |||
381 | stack_nblocksy += MAX2(2, nblocksy); |
||
382 | |||
383 | width = u_minify(width, 1); |
||
384 | height = u_minify(height, 1); |
||
385 | nblocksy = util_format_get_nblocksy(pt->format, height); |
||
386 | } |
||
387 | |||
388 | /* Fixup depth image_offsets: |
||
389 | */ |
||
390 | for (level = 0; level <= pt->last_level; level++) { |
||
391 | unsigned i; |
||
392 | for (i = 0; i < depth; i++) |
||
393 | i915_texture_set_image_offset(tex, level, i, 0, i * stack_nblocksy); |
||
394 | |||
395 | depth = u_minify(depth, 1); |
||
396 | } |
||
397 | |||
398 | /* Multiply slice size by texture depth for total size. It's |
||
399 | * remarkable how wasteful of memory the i915 texture layouts |
||
400 | * are. They are largely fixed in the i945. |
||
401 | */ |
||
402 | tex->total_nblocksy = stack_nblocksy * util_next_power_of_two(pt->depth0); |
||
403 | } |
||
404 | |||
405 | static boolean |
||
406 | i915_texture_layout(struct i915_texture * tex) |
||
407 | { |
||
408 | switch (tex->b.b.target) { |
||
409 | case PIPE_TEXTURE_1D: |
||
410 | case PIPE_TEXTURE_2D: |
||
411 | case PIPE_TEXTURE_RECT: |
||
412 | if (!i9x5_special_layout(tex)) |
||
413 | i915_texture_layout_2d(tex); |
||
414 | break; |
||
415 | case PIPE_TEXTURE_3D: |
||
416 | i915_texture_layout_3d(tex); |
||
417 | break; |
||
418 | case PIPE_TEXTURE_CUBE: |
||
419 | i9x5_texture_layout_cube(tex); |
||
420 | break; |
||
421 | default: |
||
422 | assert(0); |
||
423 | return FALSE; |
||
424 | } |
||
425 | |||
426 | return TRUE; |
||
427 | } |
||
428 | |||
429 | |||
430 | /* |
||
431 | * i945 layout functions |
||
432 | */ |
||
433 | |||
434 | |||
435 | static void |
||
436 | i945_texture_layout_2d(struct i915_texture *tex) |
||
437 | { |
||
438 | struct pipe_resource *pt = &tex->b.b; |
||
439 | int align_x = 4, align_y = 2; |
||
440 | unsigned level; |
||
441 | unsigned x = 0; |
||
442 | unsigned y = 0; |
||
443 | unsigned width = util_next_power_of_two(pt->width0); |
||
444 | unsigned height = util_next_power_of_two(pt->height0); |
||
445 | unsigned nblocksx = util_format_get_nblocksx(pt->format, width); |
||
446 | unsigned nblocksy = util_format_get_nblocksy(pt->format, height); |
||
447 | |||
448 | if (util_format_is_s3tc(pt->format)) { |
||
449 | align_x = 1; |
||
450 | align_y = 1; |
||
451 | } |
||
452 | |||
453 | tex->stride = align(util_format_get_stride(pt->format, width), 4); |
||
454 | |||
455 | /* May need to adjust pitch to accommodate the placement of |
||
456 | * the 2nd mipmap level. This occurs when the alignment |
||
457 | * constraints of mipmap placement push the right edge of the |
||
458 | * 2nd mipmap level out past the width of its parent. |
||
459 | */ |
||
460 | if (pt->last_level > 0) { |
||
461 | unsigned mip1_nblocksx = |
||
462 | align_nblocksx(pt->format, u_minify(width, 1), align_x) + |
||
463 | util_format_get_nblocksx(pt->format, u_minify(width, 2)); |
||
464 | |||
465 | if (mip1_nblocksx > nblocksx) |
||
466 | tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format); |
||
467 | } |
||
468 | |||
469 | /* Pitch must be a whole number of dwords |
||
470 | */ |
||
471 | tex->stride = align(tex->stride, 64); |
||
472 | tex->total_nblocksy = 0; |
||
473 | |||
474 | for (level = 0; level <= pt->last_level; level++) { |
||
475 | i915_texture_set_level_info(tex, level, 1); |
||
476 | i915_texture_set_image_offset(tex, level, 0, x, y); |
||
477 | |||
478 | /* Because the images are packed better, the final offset |
||
479 | * might not be the maximal one: |
||
480 | */ |
||
481 | tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy); |
||
482 | |||
483 | /* Layout_below: step right after second mipmap level. |
||
484 | */ |
||
485 | if (level == 1) { |
||
486 | x += nblocksx; |
||
487 | } else { |
||
488 | y += nblocksy; |
||
489 | } |
||
490 | |||
491 | width = u_minify(width, 1); |
||
492 | height = u_minify(height, 1); |
||
493 | nblocksx = align_nblocksx(pt->format, width, align_x); |
||
494 | nblocksy = align_nblocksy(pt->format, height, align_y); |
||
495 | } |
||
496 | } |
||
497 | |||
498 | static void |
||
499 | i945_texture_layout_3d(struct i915_texture *tex) |
||
500 | { |
||
501 | struct pipe_resource *pt = &tex->b.b; |
||
502 | unsigned width = util_next_power_of_two(pt->width0); |
||
503 | unsigned height = util_next_power_of_two(pt->height0); |
||
504 | unsigned depth = util_next_power_of_two(pt->depth0); |
||
505 | unsigned nblocksy = util_format_get_nblocksy(pt->format, width); |
||
506 | unsigned pack_x_pitch, pack_x_nr; |
||
507 | unsigned pack_y_pitch; |
||
508 | unsigned level; |
||
509 | |||
510 | tex->stride = align(util_format_get_stride(pt->format, width), 4); |
||
511 | tex->total_nblocksy = 0; |
||
512 | |||
513 | pack_y_pitch = MAX2(nblocksy, 2); |
||
514 | pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format); |
||
515 | pack_x_nr = 1; |
||
516 | |||
517 | for (level = 0; level <= pt->last_level; level++) { |
||
518 | int x = 0; |
||
519 | int y = 0; |
||
520 | unsigned q, j; |
||
521 | |||
522 | i915_texture_set_level_info(tex, level, depth); |
||
523 | |||
524 | for (q = 0; q < depth;) { |
||
525 | for (j = 0; j < pack_x_nr && q < depth; j++, q++) { |
||
526 | i915_texture_set_image_offset(tex, level, q, x, y + tex->total_nblocksy); |
||
527 | x += pack_x_pitch; |
||
528 | } |
||
529 | |||
530 | x = 0; |
||
531 | y += pack_y_pitch; |
||
532 | } |
||
533 | |||
534 | tex->total_nblocksy += y; |
||
535 | |||
536 | if (pack_x_pitch > 4) { |
||
537 | pack_x_pitch >>= 1; |
||
538 | pack_x_nr <<= 1; |
||
539 | assert(pack_x_pitch * pack_x_nr * util_format_get_blocksize(pt->format) <= tex->stride); |
||
540 | } |
||
541 | |||
542 | if (pack_y_pitch > 2) { |
||
543 | pack_y_pitch >>= 1; |
||
544 | } |
||
545 | |||
546 | width = u_minify(width, 1); |
||
547 | height = u_minify(height, 1); |
||
548 | depth = u_minify(depth, 1); |
||
549 | nblocksy = util_format_get_nblocksy(pt->format, height); |
||
550 | } |
||
551 | } |
||
552 | |||
553 | static void |
||
554 | i945_texture_layout_cube(struct i915_texture *tex) |
||
555 | { |
||
556 | struct pipe_resource *pt = &tex->b.b; |
||
557 | unsigned width = util_next_power_of_two(pt->width0); |
||
558 | const unsigned nblocks = util_format_get_nblocksx(pt->format, width); |
||
559 | const unsigned dim = width; |
||
560 | unsigned level; |
||
561 | unsigned face; |
||
562 | |||
563 | assert(pt->width0 == pt->height0); /* cubemap images are square */ |
||
564 | assert(util_format_is_s3tc(pt->format)); /* compressed only */ |
||
565 | |||
566 | /* |
||
567 | * Depending on the size of the largest images, pitch can be |
||
568 | * determined either by the old-style packing of cubemap faces, |
||
569 | * or the final row of 4x4, 2x2 and 1x1 faces below this. |
||
570 | * |
||
571 | * 64 * 2 / 4 = 32 |
||
572 | * 14 * 2 = 28 |
||
573 | */ |
||
574 | if (width >= 64) |
||
575 | tex->stride = nblocks * 2 * util_format_get_blocksize(pt->format); |
||
576 | else |
||
577 | tex->stride = 14 * 2 * util_format_get_blocksize(pt->format); |
||
578 | |||
579 | /* |
||
580 | * Something similary apply for height as well. |
||
581 | */ |
||
582 | if (width >= 4) |
||
583 | tex->total_nblocksy = nblocks * 4 + 1; |
||
584 | else |
||
585 | tex->total_nblocksy = 1; |
||
586 | |||
587 | /* Set all the levels to effectively occupy the whole rectangular region */ |
||
588 | for (level = 0; level <= pt->last_level; level++) |
||
589 | i915_texture_set_level_info(tex, level, 6); |
||
590 | |||
591 | for (face = 0; face < 6; face++) { |
||
592 | /* all calculations in pixels */ |
||
593 | unsigned total_height = tex->total_nblocksy * 4; |
||
594 | unsigned x = initial_offsets[face][0] * dim; |
||
595 | unsigned y = initial_offsets[face][1] * dim; |
||
596 | unsigned d = dim; |
||
597 | |||
598 | if (dim == 4 && face >= 4) { |
||
599 | x = (face - 4) * 8; |
||
600 | y = tex->total_nblocksy * 4 - 4; /* 4 = 1 block */ |
||
601 | } else if (dim < 4 && (face > 0)) { |
||
602 | x = face * 8; |
||
603 | y = total_height - 4; |
||
604 | } |
||
605 | |||
606 | for (level = 0; level <= pt->last_level; level++) { |
||
607 | i915_texture_set_image_offset(tex, level, face, |
||
608 | util_format_get_nblocksx(pt->format, x), |
||
609 | util_format_get_nblocksy(pt->format, y)); |
||
610 | |||
611 | d >>= 1; |
||
612 | |||
613 | switch (d) { |
||
614 | case 4: |
||
615 | switch (face) { |
||
616 | case PIPE_TEX_FACE_POS_X: |
||
617 | case PIPE_TEX_FACE_NEG_X: |
||
618 | x += step_offsets[face][0] * d; |
||
619 | y += step_offsets[face][1] * d; |
||
620 | break; |
||
621 | case PIPE_TEX_FACE_POS_Y: |
||
622 | case PIPE_TEX_FACE_NEG_Y: |
||
623 | y += 12; |
||
624 | x -= 8; |
||
625 | break; |
||
626 | case PIPE_TEX_FACE_POS_Z: |
||
627 | case PIPE_TEX_FACE_NEG_Z: |
||
628 | y = total_height - 4; |
||
629 | x = (face - 4) * 8; |
||
630 | break; |
||
631 | } |
||
632 | break; |
||
633 | case 2: |
||
634 | y = total_height - 4; |
||
635 | x = bottom_offsets[face]; |
||
636 | break; |
||
637 | case 1: |
||
638 | x += 48; |
||
639 | break; |
||
640 | default: |
||
641 | x += step_offsets[face][0] * d; |
||
642 | y += step_offsets[face][1] * d; |
||
643 | break; |
||
644 | } |
||
645 | } |
||
646 | } |
||
647 | } |
||
648 | |||
649 | static boolean |
||
650 | i945_texture_layout(struct i915_texture * tex) |
||
651 | { |
||
652 | switch (tex->b.b.target) { |
||
653 | case PIPE_TEXTURE_1D: |
||
654 | case PIPE_TEXTURE_2D: |
||
655 | case PIPE_TEXTURE_RECT: |
||
656 | if (!i9x5_special_layout(tex)) |
||
657 | i945_texture_layout_2d(tex); |
||
658 | break; |
||
659 | case PIPE_TEXTURE_3D: |
||
660 | i945_texture_layout_3d(tex); |
||
661 | break; |
||
662 | case PIPE_TEXTURE_CUBE: |
||
663 | if (!util_format_is_s3tc(tex->b.b.format)) |
||
664 | i9x5_texture_layout_cube(tex); |
||
665 | else |
||
666 | i945_texture_layout_cube(tex); |
||
667 | break; |
||
668 | default: |
||
669 | assert(0); |
||
670 | return FALSE; |
||
671 | } |
||
672 | |||
673 | return TRUE; |
||
674 | } |
||
675 | |||
676 | |||
677 | |||
678 | /* |
||
679 | * Screen texture functions |
||
680 | */ |
||
681 | |||
682 | |||
683 | |||
684 | static boolean |
||
685 | i915_texture_get_handle(struct pipe_screen * screen, |
||
686 | struct pipe_resource *texture, |
||
687 | struct winsys_handle *whandle) |
||
688 | { |
||
689 | struct i915_screen *is = i915_screen(screen); |
||
690 | struct i915_texture *tex = i915_texture(texture); |
||
691 | struct i915_winsys *iws = is->iws; |
||
692 | |||
693 | return iws->buffer_get_handle(iws, tex->buffer, whandle, tex->stride); |
||
694 | } |
||
695 | |||
696 | |||
697 | static void |
||
698 | i915_texture_destroy(struct pipe_screen *screen, |
||
699 | struct pipe_resource *pt) |
||
700 | { |
||
701 | struct i915_texture *tex = i915_texture(pt); |
||
702 | struct i915_winsys *iws = i915_screen(screen)->iws; |
||
703 | uint i; |
||
704 | |||
705 | if (tex->buffer) |
||
706 | iws->buffer_destroy(iws, tex->buffer); |
||
707 | |||
708 | for (i = 0; i < Elements(tex->image_offset); i++) |
||
709 | FREE(tex->image_offset[i]); |
||
710 | |||
711 | FREE(tex); |
||
712 | } |
||
713 | |||
714 | static void * |
||
715 | i915_texture_transfer_map(struct pipe_context *pipe, |
||
716 | struct pipe_resource *resource, |
||
717 | unsigned level, |
||
718 | unsigned usage, |
||
719 | const struct pipe_box *box, |
||
720 | struct pipe_transfer **ptransfer) |
||
721 | { |
||
722 | struct i915_context *i915 = i915_context(pipe); |
||
723 | struct i915_texture *tex = i915_texture(resource); |
||
724 | struct i915_transfer *transfer = util_slab_alloc(&i915->texture_transfer_pool); |
||
725 | boolean use_staging_texture = FALSE; |
||
726 | struct i915_winsys *iws = i915_screen(pipe->screen)->iws; |
||
727 | enum pipe_format format = resource->format; |
||
728 | unsigned offset; |
||
729 | char *map; |
||
730 | |||
731 | if (transfer == NULL) |
||
732 | return NULL; |
||
733 | |||
734 | transfer->b.resource = resource; |
||
735 | transfer->b.level = level; |
||
736 | transfer->b.usage = usage; |
||
737 | transfer->b.box = *box; |
||
738 | transfer->b.stride = tex->stride; |
||
739 | transfer->staging_texture = NULL; |
||
740 | /* XXX: handle depth textures everyhwere*/ |
||
741 | transfer->b.layer_stride = 0; |
||
742 | |||
743 | /* if we use staging transfers, only support textures we can render to, |
||
744 | * because we need that for u_blitter */ |
||
745 | if (i915->blitter && |
||
746 | util_blitter_is_copy_supported(i915->blitter, resource, resource) && |
||
747 | (usage & PIPE_TRANSFER_WRITE) && |
||
748 | !(usage & (PIPE_TRANSFER_READ | PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_UNSYNCHRONIZED))) |
||
749 | use_staging_texture = TRUE; |
||
750 | |||
751 | use_staging_texture = FALSE; |
||
752 | |||
753 | if (use_staging_texture) { |
||
754 | /* |
||
755 | * Allocate the untiled staging texture. |
||
756 | * If the alloc fails, transfer->staging_texture is NULL and we fallback to a map() |
||
757 | */ |
||
758 | transfer->staging_texture = i915_texture_create(pipe->screen, resource, TRUE); |
||
759 | } |
||
760 | |||
761 | if (resource->target != PIPE_TEXTURE_3D && |
||
762 | resource->target != PIPE_TEXTURE_CUBE) |
||
763 | assert(box->z == 0); |
||
764 | |||
765 | if (transfer->staging_texture) { |
||
766 | tex = i915_texture(transfer->staging_texture); |
||
767 | } else { |
||
768 | /* TODO this is a sledgehammer */ |
||
769 | tex = i915_texture(resource); |
||
770 | pipe->flush(pipe, NULL, 0); |
||
771 | } |
||
772 | |||
773 | offset = i915_texture_offset(tex, transfer->b.level, box->z); |
||
774 | |||
775 | map = iws->buffer_map(iws, tex->buffer, |
||
776 | (transfer->b.usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE); |
||
777 | if (map == NULL) { |
||
778 | pipe_resource_reference(&transfer->staging_texture, NULL); |
||
779 | FREE(transfer); |
||
780 | return NULL; |
||
781 | } |
||
782 | |||
783 | *ptransfer = &transfer->b; |
||
784 | |||
785 | return map + offset + |
||
786 | box->y / util_format_get_blockheight(format) * transfer->b.stride + |
||
787 | box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); |
||
788 | } |
||
789 | |||
790 | static void |
||
791 | i915_texture_transfer_unmap(struct pipe_context *pipe, |
||
792 | struct pipe_transfer *transfer) |
||
793 | { |
||
794 | struct i915_context *i915 = i915_context(pipe); |
||
795 | struct i915_transfer *itransfer = (struct i915_transfer*)transfer; |
||
796 | struct i915_texture *tex = i915_texture(itransfer->b.resource); |
||
797 | struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws; |
||
798 | |||
799 | if (itransfer->staging_texture) |
||
800 | tex = i915_texture(itransfer->staging_texture); |
||
801 | |||
802 | iws->buffer_unmap(iws, tex->buffer); |
||
803 | |||
804 | if ((itransfer->staging_texture) && |
||
805 | (transfer->usage & PIPE_TRANSFER_WRITE)) { |
||
806 | struct pipe_box sbox; |
||
807 | |||
808 | u_box_origin_2d(itransfer->b.box.width, itransfer->b.box.height, &sbox); |
||
809 | pipe->resource_copy_region(pipe, itransfer->b.resource, itransfer->b.level, |
||
810 | itransfer->b.box.x, itransfer->b.box.y, itransfer->b.box.z, |
||
811 | itransfer->staging_texture, |
||
812 | 0, &sbox); |
||
813 | pipe->flush(pipe, NULL, 0); |
||
814 | pipe_resource_reference(&itransfer->staging_texture, NULL); |
||
815 | } |
||
816 | |||
817 | util_slab_free(&i915->texture_transfer_pool, itransfer); |
||
818 | } |
||
819 | |||
820 | #if 0 |
||
821 | static void i915_transfer_inline_write( struct pipe_context *pipe, |
||
822 | struct pipe_resource *resource, |
||
823 | unsigned level, |
||
824 | unsigned usage, |
||
825 | const struct pipe_box *box, |
||
826 | const void *data, |
||
827 | unsigned stride, |
||
828 | unsigned layer_stride) |
||
829 | { |
||
830 | struct pipe_transfer *transfer = NULL; |
||
831 | struct i915_transfer *itransfer = NULL; |
||
832 | const uint8_t *src_data = data; |
||
833 | unsigned i; |
||
834 | |||
835 | transfer = pipe->transfer_get(pipe, |
||
836 | resource, |
||
837 | level, |
||
838 | usage, |
||
839 | box ); |
||
840 | if (transfer == NULL) |
||
841 | goto out; |
||
842 | |||
843 | itransfer = (struct i915_transfer*)transfer; |
||
844 | |||
845 | if (itransfer->staging_texture) { |
||
846 | struct i915_texture *tex = i915_texture(itransfer->staging_texture); |
||
847 | enum pipe_format format = tex->b.b.format; |
||
848 | struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws; |
||
849 | size_t offset; |
||
850 | size_t size; |
||
851 | |||
852 | offset = i915_texture_offset(tex, transfer->level, transfer->box.z); |
||
853 | |||
854 | for (i = 0; i < box->depth; i++) { |
||
855 | if (!tex->b.b.last_level && |
||
856 | tex->b.b.width0 == transfer->box.width) { |
||
857 | unsigned nby = util_format_get_nblocksy(format, transfer->box.y); |
||
858 | assert(!offset); |
||
859 | assert(!transfer->box.x); |
||
860 | assert(tex->stride == transfer->stride); |
||
861 | |||
862 | offset += tex->stride * nby; |
||
863 | size = util_format_get_2d_size(format, transfer->stride, |
||
864 | transfer->box.height); |
||
865 | iws->buffer_write(iws, tex->buffer, offset, size, transfer->data); |
||
866 | |||
867 | } else { |
||
868 | unsigned nby = util_format_get_nblocksy(format, transfer->box.y); |
||
869 | int i; |
||
870 | offset += util_format_get_stride(format, transfer->box.x); |
||
871 | size = transfer->stride; |
||
872 | |||
873 | for (i = 0; i < nby; i++) { |
||
874 | iws->buffer_write(iws, tex->buffer, offset, size, transfer->data); |
||
875 | offset += tex->stride; |
||
876 | } |
||
877 | } |
||
878 | offset += layer_stride; |
||
879 | } |
||
880 | } else { |
||
881 | uint8_t *map = pipe_transfer_map(pipe, &itransfer->b); |
||
882 | if (map == NULL) |
||
883 | goto nomap; |
||
884 | |||
885 | for (i = 0; i < box->depth; i++) { |
||
886 | util_copy_rect(map, |
||
887 | resource->format, |
||
888 | itransfer->b.stride, /* bytes */ |
||
889 | 0, 0, |
||
890 | box->width, |
||
891 | box->height, |
||
892 | src_data, |
||
893 | stride, /* bytes */ |
||
894 | 0, 0); |
||
895 | map += itransfer->b.layer_stride; |
||
896 | src_data += layer_stride; |
||
897 | } |
||
898 | nomap: |
||
899 | if (map) |
||
900 | pipe_transfer_unmap(pipe, &itransfer->b); |
||
901 | } |
||
902 | |||
903 | out: |
||
904 | if (itransfer) |
||
905 | pipe_transfer_destroy(pipe, &itransfer->b); |
||
906 | } |
||
907 | #endif |
||
908 | |||
909 | struct u_resource_vtbl i915_texture_vtbl = |
||
910 | { |
||
911 | i915_texture_get_handle, /* get_handle */ |
||
912 | i915_texture_destroy, /* resource_destroy */ |
||
913 | i915_texture_transfer_map, /* transfer_map */ |
||
914 | u_default_transfer_flush_region, /* transfer_flush_region */ |
||
915 | i915_texture_transfer_unmap, /* transfer_unmap */ |
||
916 | u_default_transfer_inline_write /* transfer_inline_write */ |
||
917 | }; |
||
918 | |||
919 | |||
920 | struct pipe_resource * |
||
921 | i915_texture_create(struct pipe_screen *screen, |
||
922 | const struct pipe_resource *template, |
||
923 | boolean force_untiled) |
||
924 | { |
||
925 | struct i915_screen *is = i915_screen(screen); |
||
926 | struct i915_winsys *iws = is->iws; |
||
927 | struct i915_texture *tex = CALLOC_STRUCT(i915_texture); |
||
928 | unsigned buf_usage = 0; |
||
929 | |||
930 | if (!tex) |
||
931 | return NULL; |
||
932 | |||
933 | tex->b.b = *template; |
||
934 | tex->b.vtbl = &i915_texture_vtbl; |
||
935 | pipe_reference_init(&tex->b.b.reference, 1); |
||
936 | tex->b.b.screen = screen; |
||
937 | |||
938 | if ( (force_untiled) || (template->usage == PIPE_USAGE_STREAM) ) |
||
939 | tex->tiling = I915_TILE_NONE; |
||
940 | else |
||
941 | tex->tiling = i915_texture_tiling(is, tex); |
||
942 | |||
943 | if (is->is_i945) { |
||
944 | if (!i945_texture_layout(tex)) |
||
945 | goto fail; |
||
946 | } else { |
||
947 | if (!i915_texture_layout(tex)) |
||
948 | goto fail; |
||
949 | } |
||
950 | |||
951 | /* for scanouts and cursors, cursors arn't scanouts */ |
||
952 | |||
953 | /* XXX: use a custom flag for cursors, don't rely on magically |
||
954 | * guessing that this is Xorg asking for a cursor |
||
955 | */ |
||
956 | if ((template->bind & PIPE_BIND_SCANOUT) && template->width0 != 64) |
||
957 | buf_usage = I915_NEW_SCANOUT; |
||
958 | else |
||
959 | buf_usage = I915_NEW_TEXTURE; |
||
960 | |||
961 | tex->buffer = iws->buffer_create_tiled(iws, &tex->stride, tex->total_nblocksy, |
||
962 | &tex->tiling, buf_usage); |
||
963 | if (!tex->buffer) |
||
964 | goto fail; |
||
965 | |||
966 | I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__, |
||
967 | tex, tex->stride, |
||
968 | tex->stride / util_format_get_blocksize(tex->b.b.format), |
||
969 | tex->total_nblocksy, get_tiling_string(tex->tiling)); |
||
970 | |||
971 | return &tex->b.b; |
||
972 | |||
973 | fail: |
||
974 | FREE(tex); |
||
975 | return NULL; |
||
976 | } |
||
977 | |||
978 | struct pipe_resource * |
||
979 | i915_texture_from_handle(struct pipe_screen * screen, |
||
980 | const struct pipe_resource *template, |
||
981 | struct winsys_handle *whandle) |
||
982 | { |
||
983 | struct i915_screen *is = i915_screen(screen); |
||
984 | struct i915_texture *tex; |
||
985 | struct i915_winsys *iws = is->iws; |
||
986 | struct i915_winsys_buffer *buffer; |
||
987 | unsigned stride; |
||
988 | enum i915_winsys_buffer_tile tiling; |
||
989 | |||
990 | assert(screen); |
||
991 | |||
992 | buffer = iws->buffer_from_handle(iws, whandle, template->height0, &tiling, &stride); |
||
993 | |||
994 | /* Only supports one type */ |
||
995 | if ((template->target != PIPE_TEXTURE_2D && |
||
996 | template->target != PIPE_TEXTURE_RECT) || |
||
997 | template->last_level != 0 || |
||
998 | template->depth0 != 1) { |
||
999 | return NULL; |
||
1000 | } |
||
1001 | |||
1002 | tex = CALLOC_STRUCT(i915_texture); |
||
1003 | if (!tex) |
||
1004 | return NULL; |
||
1005 | |||
1006 | tex->b.b = *template; |
||
1007 | tex->b.vtbl = &i915_texture_vtbl; |
||
1008 | pipe_reference_init(&tex->b.b.reference, 1); |
||
1009 | tex->b.b.screen = screen; |
||
1010 | |||
1011 | tex->stride = stride; |
||
1012 | tex->tiling = tiling; |
||
1013 | tex->total_nblocksy = align_nblocksy(tex->b.b.format, tex->b.b.height0, 8); |
||
1014 | |||
1015 | i915_texture_set_level_info(tex, 0, 1); |
||
1016 | i915_texture_set_image_offset(tex, 0, 0, 0, 0); |
||
1017 | |||
1018 | tex->buffer = buffer; |
||
1019 | |||
1020 | I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__, |
||
1021 | tex, tex->stride, |
||
1022 | tex->stride / util_format_get_blocksize(tex->b.b.format), |
||
1023 | tex->total_nblocksy, get_tiling_string(tex->tiling)); |
||
1024 | |||
1025 | return &tex->b.b; |
||
1026 | }>>>>=>>>=>=>=><=>>>>=>=>>=>=>=>=>>=>>>> |
||
1027 |