Merge branch 'master' into gallium-0.2
[mesa.git] / src / gallium / drivers / i915simple / i915_texture.c
1 /**************************************************************************
2 *
3 * Copyright 2006 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 * Keith Whitwell <keith@tungstengraphics.com>
30 * Michel Dänzer <michel@tungstengraphics.com>
31 */
32
33 #include "pipe/p_state.h"
34 #include "pipe/p_context.h"
35 #include "pipe/p_defines.h"
36 #include "pipe/p_inlines.h"
37 #include "pipe/p_winsys.h"
38 #include "util/u_math.h"
39 #include "util/u_memory.h"
40
41 #include "i915_context.h"
42 #include "i915_texture.h"
43 #include "i915_debug.h"
44 #include "i915_screen.h"
45
46 /*
47 * Helper function and arrays
48 */
49
50 /**
51 * Initial offset for Cube map.
52 */
53 static const int initial_offsets[6][2] = {
54 {0, 0},
55 {0, 2},
56 {1, 0},
57 {1, 2},
58 {1, 1},
59 {1, 3}
60 };
61
62 /**
63 * Step offsets for Cube map.
64 */
65 static const int step_offsets[6][2] = {
66 {0, 2},
67 {0, 2},
68 {-1, 2},
69 {-1, 2},
70 {-1, 1},
71 {-1, 1}
72 };
73
74 static unsigned minify( unsigned d )
75 {
76 return MAX2(1, d>>1);
77 }
78
79 static unsigned
80 power_of_two(unsigned x)
81 {
82 unsigned value = 1;
83 while (value < x)
84 value = value << 1;
85 return value;
86 }
87
88 static unsigned
89 round_up(unsigned n, unsigned multiple)
90 {
91 return (n + multiple - 1) & ~(multiple - 1);
92 }
93
94
95 /*
96 * More advanced helper funcs
97 */
98
99
100 static void
101 i915_miptree_set_level_info(struct i915_texture *tex,
102 unsigned level,
103 unsigned nr_images,
104 unsigned w, unsigned h, unsigned d)
105 {
106 struct pipe_texture *pt = &tex->base;
107
108 assert(level < PIPE_MAX_TEXTURE_LEVELS);
109
110 pt->width[level] = w;
111 pt->height[level] = h;
112 pt->depth[level] = d;
113
114 pt->nblocksx[level] = pf_get_nblocksx(&pt->block, w);
115 pt->nblocksy[level] = pf_get_nblocksy(&pt->block, h);
116
117 tex->nr_images[level] = nr_images;
118
119 /*
120 DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
121 level, w, h, d, x, y, tex->level_offset[level]);
122 */
123
124 /* Not sure when this would happen, but anyway:
125 */
126 if (tex->image_offset[level]) {
127 FREE(tex->image_offset[level]);
128 tex->image_offset[level] = NULL;
129 }
130
131 assert(nr_images);
132 assert(!tex->image_offset[level]);
133
134 tex->image_offset[level] = (unsigned *) MALLOC(nr_images * sizeof(unsigned));
135 tex->image_offset[level][0] = 0;
136 }
137
138 static void
139 i915_miptree_set_image_offset(struct i915_texture *tex,
140 unsigned level, unsigned img, unsigned x, unsigned y)
141 {
142 if (img == 0 && level == 0)
143 assert(x == 0 && y == 0);
144
145 assert(img < tex->nr_images[level]);
146
147 tex->image_offset[level][img] = y * tex->stride + x * tex->base.block.size;
148
149 /*
150 printf("%s level %d img %d pos %d,%d image_offset %x\n",
151 __FUNCTION__, level, img, x, y, tex->image_offset[level][img]);
152 */
153 }
154
155
156 /*
157 * Layout functions
158 */
159
160
161 /**
162 * Special case to deal with display targets.
163 */
164 static boolean
165 i915_displaytarget_layout(struct i915_texture *tex)
166 {
167 struct pipe_texture *pt = &tex->base;
168
169 if (pt->last_level > 0 || pt->block.size != 4)
170 return 0;
171
172 i915_miptree_set_level_info( tex, 0, 1,
173 tex->base.width[0],
174 tex->base.height[0],
175 1 );
176 i915_miptree_set_image_offset( tex, 0, 0, 0, 0 );
177
178 if (tex->base.width[0] >= 128) {
179 tex->stride = power_of_two(tex->base.nblocksx[0] * pt->block.size);
180 tex->total_nblocksy = round_up(tex->base.nblocksy[0], 8);
181 tex->tiled = 1;
182 } else {
183 tex->stride = round_up(tex->base.nblocksx[0] * pt->block.size, 64);
184 tex->total_nblocksy = tex->base.nblocksy[0];
185 }
186
187 /*
188 printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
189 tex->base.width[0], tex->base.height[0], pt->block.size,
190 tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
191 */
192
193 return 1;
194 }
195
196 static void
197 i945_miptree_layout_2d( struct i915_texture *tex )
198 {
199 struct pipe_texture *pt = &tex->base;
200 const int align_x = 2, align_y = 4;
201 unsigned level;
202 unsigned x = 0;
203 unsigned y = 0;
204 unsigned width = pt->width[0];
205 unsigned height = pt->height[0];
206 unsigned nblocksx = pt->nblocksx[0];
207 unsigned nblocksy = pt->nblocksy[0];
208
209 #if 0 /* used for tiled display targets */
210 if (pt->last_level == 0 && pt->block.size == 4)
211 if (i915_displaytarget_layout(tex))
212 return;
213 #endif
214
215 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
216
217 /* May need to adjust pitch to accomodate the placement of
218 * the 2nd mipmap level. This occurs when the alignment
219 * constraints of mipmap placement push the right edge of the
220 * 2nd mipmap level out past the width of its parent.
221 */
222 if (pt->last_level > 0) {
223 unsigned mip1_nblocksx
224 = align(pf_get_nblocksx(&pt->block, minify(width)), align_x)
225 + pf_get_nblocksx(&pt->block, minify(minify(width)));
226
227 if (mip1_nblocksx > nblocksx)
228 tex->stride = mip1_nblocksx * pt->block.size;
229 }
230
231 /* Pitch must be a whole number of dwords
232 */
233 tex->stride = align(tex->stride, 64);
234 tex->total_nblocksy = 0;
235
236 for (level = 0; level <= pt->last_level; level++) {
237 i915_miptree_set_level_info(tex, level, 1, width, height, 1);
238 i915_miptree_set_image_offset(tex, level, 0, x, y);
239
240 nblocksy = align(nblocksy, align_y);
241
242 /* Because the images are packed better, the final offset
243 * might not be the maximal one:
244 */
245 tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
246
247 /* Layout_below: step right after second mipmap level.
248 */
249 if (level == 1) {
250 x += align(nblocksx, align_x);
251 }
252 else {
253 y += nblocksy;
254 }
255
256 width = minify(width);
257 height = minify(height);
258 nblocksx = pf_get_nblocksx(&pt->block, width);
259 nblocksy = pf_get_nblocksy(&pt->block, height);
260 }
261 }
262
263 static void
264 i945_miptree_layout_cube(struct i915_texture *tex)
265 {
266 struct pipe_texture *pt = &tex->base;
267 unsigned level;
268
269 const unsigned nblocks = pt->nblocksx[0];
270 unsigned face;
271 unsigned width = pt->width[0];
272 unsigned height = pt->height[0];
273
274 /*
275 printf("%s %i, %i\n", __FUNCTION__, pt->width[0], pt->height[0]);
276 */
277
278 assert(width == height); /* cubemap images are square */
279
280 /*
281 * XXX Should only be used for compressed formats. But lets
282 * keep this code active just in case.
283 *
284 * Depending on the size of the largest images, pitch can be
285 * determined either by the old-style packing of cubemap faces,
286 * or the final row of 4x4, 2x2 and 1x1 faces below this.
287 */
288 if (nblocks > 32)
289 tex->stride = round_up(nblocks * pt->block.size * 2, 4);
290 else
291 tex->stride = 14 * 8 * pt->block.size;
292
293 tex->total_nblocksy = nblocks * 4;
294
295 /* Set all the levels to effectively occupy the whole rectangular region.
296 */
297 for (level = 0; level <= pt->last_level; level++) {
298 i915_miptree_set_level_info(tex, level, 6, width, height, 1);
299 width /= 2;
300 height /= 2;
301 }
302
303 for (face = 0; face < 6; face++) {
304 unsigned x = initial_offsets[face][0] * nblocks;
305 unsigned y = initial_offsets[face][1] * nblocks;
306 unsigned d = nblocks;
307
308 #if 0 /* Fix and enable this code for compressed formats */
309 if (nblocks == 4 && face >= 4) {
310 y = tex->total_height - 4;
311 x = (face - 4) * 8;
312 }
313 else if (nblocks < 4 && (face > 0)) {
314 y = tex->total_height - 4;
315 x = face * 8;
316 }
317 #endif
318
319 for (level = 0; level <= pt->last_level; level++) {
320 i915_miptree_set_image_offset(tex, level, face, x, y);
321
322 d >>= 1;
323
324 #if 0 /* Fix and enable this code for compressed formats */
325 switch (d) {
326 case 4:
327 switch (face) {
328 case PIPE_TEX_FACE_POS_X:
329 case PIPE_TEX_FACE_NEG_X:
330 x += step_offsets[face][0] * d;
331 y += step_offsets[face][1] * d;
332 break;
333 case PIPE_TEX_FACE_POS_Y:
334 case PIPE_TEX_FACE_NEG_Y:
335 y += 12;
336 x -= 8;
337 break;
338 case PIPE_TEX_FACE_POS_Z:
339 case PIPE_TEX_FACE_NEG_Z:
340 y = tex->total_height - 4;
341 x = (face - 4) * 8;
342 break;
343 }
344 case 2:
345 y = tex->total_height - 4;
346 x = 16 + face * 8;
347 break;
348
349 case 1:
350 x += 48;
351 break;
352 default:
353 #endif
354 x += step_offsets[face][0] * d;
355 y += step_offsets[face][1] * d;
356 #if 0
357 break;
358 }
359 #endif
360 }
361 }
362 }
363
364 static boolean
365 i915_miptree_layout(struct i915_texture * tex)
366 {
367 struct pipe_texture *pt = &tex->base;
368 unsigned level;
369
370 switch (pt->target) {
371 case PIPE_TEXTURE_CUBE: {
372 const unsigned nblocks = pt->nblocksx[0];
373 unsigned face;
374 unsigned width = pt->width[0], height = pt->height[0];
375
376 assert(width == height); /* cubemap images are square */
377
378 /* double pitch for cube layouts */
379 tex->stride = round_up(nblocks * pt->block.size * 2, 4);
380 tex->total_nblocksy = nblocks * 4;
381
382 for (level = 0; level <= pt->last_level; level++) {
383 i915_miptree_set_level_info(tex, level, 6,
384 width, height,
385 1);
386 width /= 2;
387 height /= 2;
388 }
389
390 for (face = 0; face < 6; face++) {
391 unsigned x = initial_offsets[face][0] * nblocks;
392 unsigned y = initial_offsets[face][1] * nblocks;
393 unsigned d = nblocks;
394
395 for (level = 0; level <= pt->last_level; level++) {
396 i915_miptree_set_image_offset(tex, level, face, x, y);
397 d >>= 1;
398 x += step_offsets[face][0] * d;
399 y += step_offsets[face][1] * d;
400 }
401 }
402 break;
403 }
404 case PIPE_TEXTURE_3D:{
405 unsigned width = pt->width[0];
406 unsigned height = pt->height[0];
407 unsigned depth = pt->depth[0];
408 unsigned nblocksx = pt->nblocksx[0];
409 unsigned nblocksy = pt->nblocksy[0];
410 unsigned stack_nblocksy = 0;
411
412 /* Calculate the size of a single slice.
413 */
414 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
415
416 /* XXX: hardware expects/requires 9 levels at minimum.
417 */
418 for (level = 0; level <= MAX2(8, pt->last_level);
419 level++) {
420 i915_miptree_set_level_info(tex, level, depth,
421 width, height, depth);
422
423
424 stack_nblocksy += MAX2(2, nblocksy);
425
426 width = minify(width);
427 height = minify(height);
428 depth = minify(depth);
429 nblocksx = pf_get_nblocksx(&pt->block, width);
430 nblocksy = pf_get_nblocksy(&pt->block, height);
431 }
432
433 /* Fixup depth image_offsets:
434 */
435 depth = pt->depth[0];
436 for (level = 0; level <= pt->last_level; level++) {
437 unsigned i;
438 for (i = 0; i < depth; i++)
439 i915_miptree_set_image_offset(tex, level, i,
440 0, i * stack_nblocksy);
441
442 depth = minify(depth);
443 }
444
445
446 /* Multiply slice size by texture depth for total size. It's
447 * remarkable how wasteful of memory the i915 texture layouts
448 * are. They are largely fixed in the i945.
449 */
450 tex->total_nblocksy = stack_nblocksy * pt->depth[0];
451 break;
452 }
453
454 default:{
455 unsigned width = pt->width[0];
456 unsigned height = pt->height[0];
457 unsigned nblocksx = pt->nblocksx[0];
458 unsigned nblocksy = pt->nblocksy[0];
459
460 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
461 tex->total_nblocksy = 0;
462
463 for (level = 0; level <= pt->last_level; level++) {
464 i915_miptree_set_level_info(tex, level, 1,
465 width, height, 1);
466 i915_miptree_set_image_offset(tex, level, 0,
467 0, tex->total_nblocksy);
468
469 nblocksy = round_up(MAX2(2, nblocksy), 2);
470
471 tex->total_nblocksy += nblocksy;
472
473 width = minify(width);
474 height = minify(height);
475 nblocksx = pf_get_nblocksx(&pt->block, width);
476 nblocksy = pf_get_nblocksy(&pt->block, height);
477 }
478 break;
479 }
480 }
481 /*
482 DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
483 tex->pitch,
484 tex->total_nblocksy, pt->block.size, tex->stride * tex->total_nblocksy);
485 */
486
487 return TRUE;
488 }
489
490
491 static boolean
492 i945_miptree_layout(struct i915_texture * tex)
493 {
494 struct pipe_texture *pt = &tex->base;
495 unsigned level;
496
497 switch (pt->target) {
498 case PIPE_TEXTURE_CUBE:
499 i945_miptree_layout_cube(tex);
500 break;
501 case PIPE_TEXTURE_3D:{
502 unsigned width = pt->width[0];
503 unsigned height = pt->height[0];
504 unsigned depth = pt->depth[0];
505 unsigned nblocksx = pt->nblocksx[0];
506 unsigned nblocksy = pt->nblocksy[0];
507 unsigned pack_x_pitch, pack_x_nr;
508 unsigned pack_y_pitch;
509
510 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
511 tex->total_nblocksy = 0;
512
513 pack_y_pitch = MAX2(pt->nblocksy[0], 2);
514 pack_x_pitch = tex->stride / pt->block.size;
515 pack_x_nr = 1;
516
517 for (level = 0; level <= pt->last_level; level++) {
518 unsigned nr_images = pt->target == PIPE_TEXTURE_3D ? depth : 6;
519 int x = 0;
520 int y = 0;
521 unsigned q, j;
522
523 i915_miptree_set_level_info(tex, level, nr_images,
524 width, height, depth);
525
526 for (q = 0; q < nr_images;) {
527 for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) {
528 i915_miptree_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
529 x += pack_x_pitch;
530 }
531
532 x = 0;
533 y += pack_y_pitch;
534 }
535
536
537 tex->total_nblocksy += y;
538
539 if (pack_x_pitch > 4) {
540 pack_x_pitch >>= 1;
541 pack_x_nr <<= 1;
542 assert(pack_x_pitch * pack_x_nr * pt->block.size <= tex->stride);
543 }
544
545 if (pack_y_pitch > 2) {
546 pack_y_pitch >>= 1;
547 }
548
549 width = minify(width);
550 height = minify(height);
551 depth = minify(depth);
552 nblocksx = pf_get_nblocksx(&pt->block, width);
553 nblocksy = pf_get_nblocksy(&pt->block, height);
554 }
555 break;
556 }
557
558 case PIPE_TEXTURE_1D:
559 case PIPE_TEXTURE_2D:
560 // case PIPE_TEXTURE_RECTANGLE:
561 i945_miptree_layout_2d(tex);
562 break;
563 default:
564 assert(0);
565 return FALSE;
566 }
567
568 /*
569 DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
570 tex->pitch,
571 tex->total_nblocksy, pt->block.size, tex->stride * tex->total_nblocksy);
572 */
573
574 return TRUE;
575 }
576
577
578 static struct pipe_texture *
579 i915_texture_create(struct pipe_screen *screen,
580 const struct pipe_texture *templat)
581 {
582 struct i915_screen *i915screen = i915_screen(screen);
583 struct pipe_winsys *ws = screen->winsys;
584 struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
585 size_t tex_size;
586
587 if (!tex)
588 return NULL;
589
590 tex->base = *templat;
591 tex->base.refcount = 1;
592 tex->base.screen = screen;
593
594 tex->base.nblocksx[0] = pf_get_nblocksx(&tex->base.block, tex->base.width[0]);
595 tex->base.nblocksy[0] = pf_get_nblocksy(&tex->base.block, tex->base.height[0]);
596
597 if (i915screen->is_i945) {
598 if (!i945_miptree_layout(tex))
599 goto fail;
600 } else {
601 if (!i915_miptree_layout(tex))
602 goto fail;
603 }
604
605 tex_size = tex->stride * tex->total_nblocksy;
606
607 tex->buffer = ws->buffer_create(ws, 64,
608 PIPE_BUFFER_USAGE_PIXEL,
609 tex_size);
610
611 if (!tex->buffer)
612 goto fail;
613
614 #if 0
615 void *ptr = ws->buffer_map(ws, tex->buffer,
616 PIPE_BUFFER_USAGE_CPU_WRITE);
617 memset(ptr, 0x80, tex_size);
618 ws->buffer_unmap(ws, tex->buffer);
619 #endif
620
621 return &tex->base;
622
623 fail:
624 FREE(tex);
625 return NULL;
626 }
627
628
629 static void
630 i915_texture_release(struct pipe_screen *screen,
631 struct pipe_texture **pt)
632 {
633 if (!*pt)
634 return;
635
636 /*
637 DBG("%s %p refcount will be %d\n",
638 __FUNCTION__, (void *) *pt, (*pt)->refcount - 1);
639 */
640 if (--(*pt)->refcount <= 0) {
641 struct i915_texture *tex = (struct i915_texture *)*pt;
642 uint i;
643
644 /*
645 DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
646 */
647
648 pipe_buffer_reference(screen, &tex->buffer, NULL);
649
650 for (i = 0; i < PIPE_MAX_TEXTURE_LEVELS; i++)
651 if (tex->image_offset[i])
652 FREE(tex->image_offset[i]);
653
654 FREE(tex);
655 }
656 *pt = NULL;
657 }
658
659 static struct pipe_surface *
660 i915_get_tex_surface(struct pipe_screen *screen,
661 struct pipe_texture *pt,
662 unsigned face, unsigned level, unsigned zslice,
663 unsigned flags)
664 {
665 struct i915_texture *tex = (struct i915_texture *)pt;
666 struct pipe_winsys *ws = screen->winsys;
667 struct pipe_surface *ps;
668 unsigned offset; /* in bytes */
669
670 if (pt->target == PIPE_TEXTURE_CUBE) {
671 offset = tex->image_offset[level][face];
672 }
673 else if (pt->target == PIPE_TEXTURE_3D) {
674 offset = tex->image_offset[level][zslice];
675 }
676 else {
677 offset = tex->image_offset[level][0];
678 assert(face == 0);
679 assert(zslice == 0);
680 }
681
682 ps = CALLOC_STRUCT(pipe_surface);
683 if (ps) {
684 ps->refcount = 1;
685 ps->winsys = ws;
686 pipe_texture_reference(&ps->texture, pt);
687 pipe_buffer_reference(screen, &ps->buffer, tex->buffer);
688 ps->format = pt->format;
689 ps->width = pt->width[level];
690 ps->height = pt->height[level];
691 ps->block = pt->block;
692 ps->nblocksx = pt->nblocksx[level];
693 ps->nblocksy = pt->nblocksy[level];
694 ps->stride = tex->stride;
695 ps->offset = offset;
696 ps->usage = flags;
697 ps->status = PIPE_SURFACE_STATUS_DEFINED;
698 }
699 return ps;
700 }
701
702 static struct pipe_texture *
703 i915_texture_blanket(struct pipe_screen * screen,
704 const struct pipe_texture *base,
705 const unsigned *stride,
706 struct pipe_buffer *buffer)
707 {
708 struct i915_texture *tex;
709 assert(screen);
710
711 /* Only supports one type */
712 if (base->target != PIPE_TEXTURE_2D ||
713 base->last_level != 0 ||
714 base->depth[0] != 1) {
715 return NULL;
716 }
717
718 tex = CALLOC_STRUCT(i915_texture);
719 if (!tex)
720 return NULL;
721
722 tex->base = *base;
723 tex->base.refcount = 1;
724 tex->base.screen = screen;
725
726 tex->stride = stride[0];
727
728 i915_miptree_set_level_info(tex, 0, 1, base->width[0], base->height[0], 1);
729 i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
730
731 pipe_buffer_reference(screen, &tex->buffer, buffer);
732
733 return &tex->base;
734 }
735
736 void
737 i915_init_texture_functions(struct i915_context *i915)
738 {
739 // i915->pipe.texture_update = i915_texture_update;
740 }
741
742 static void
743 i915_tex_surface_release(struct pipe_screen *screen,
744 struct pipe_surface **surface)
745 {
746 struct pipe_surface *surf = *surface;
747
748 if (--surf->refcount == 0) {
749
750 /* This really should not be possible, but it's actually
751 * happening quite a bit... Will fix.
752 */
753 if (surf->status == PIPE_SURFACE_STATUS_CLEAR) {
754 debug_printf("XXX destroying a surface with pending clears...\n");
755 assert(0);
756 }
757
758 pipe_texture_reference(&surf->texture, NULL);
759 pipe_buffer_reference(screen, &surf->buffer, NULL);
760 FREE(surf);
761 }
762
763 *surface = NULL;
764 }
765
766 void
767 i915_init_screen_texture_functions(struct pipe_screen *screen)
768 {
769 screen->texture_create = i915_texture_create;
770 screen->texture_release = i915_texture_release;
771 screen->get_tex_surface = i915_get_tex_surface;
772 screen->texture_blanket = i915_texture_blanket;
773 screen->tex_surface_release = i915_tex_surface_release;
774 }