i915_resource_texture.c 22.9 KB
Newer Older
Keith Whitwell's avatar
Keith Whitwell committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/**************************************************************************
 * 
 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
 * All Rights Reserved.
 * 
 * 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 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 TUNGSTEN GRAPHICS AND/OR ITS 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.
 * 
 **************************************************************************/
 /*
  * Authors:
  *   Keith Whitwell <keith@tungstengraphics.com>
  *   Michel Dänzer <michel@tungstengraphics.com>
  */

#include "pipe/p_state.h"
#include "pipe/p_context.h"
35
#include "pipe/p_defines.h"
36
#include "util/u_inlines.h"
37
#include "util/u_format.h"
38 39
#include "util/u_math.h"
#include "util/u_memory.h"
40

41
#include "i915_context.h"
42
#include "i915_resource.h"
43
#include "i915_screen.h"
44
#include "i915_winsys.h"
Keith Whitwell's avatar
Keith Whitwell committed
45

46

47 48 49 50
/*
 * Helper function and arrays
 */

51

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
/**
 * Initial offset for Cube map.
 */
static const int initial_offsets[6][2] = {
   {0, 0},
   {0, 2},
   {1, 0},
   {1, 2},
   {1, 1},
   {1, 3}
};

/**
 * Step offsets for Cube map.
 */
static const int step_offsets[6][2] = {
   {0, 2},
   {0, 2},
   {-1, 2},
   {-1, 2},
   {-1, 1},
   {-1, 1}
};
Keith Whitwell's avatar
Keith Whitwell committed
75

76 77 78
/* XXX really need twice the size if x is already pot?
   Otherwise just use util_next_power_of_two?
*/
79 80 81 82
static unsigned
power_of_two(unsigned x)
{
   unsigned value = 1;
83
   while (value < x)
84 85 86 87 88 89 90
      value = value << 1;
   return value;
}

/*
 * More advanced helper funcs
 */
Keith Whitwell's avatar
Keith Whitwell committed
91 92 93


static void
94
i915_texture_set_level_info(struct i915_texture *tex,
95 96
                             unsigned level,
                             unsigned nr_images,
97
                             unsigned w, unsigned h, unsigned d)
Keith Whitwell's avatar
Keith Whitwell committed
98
{
99
   assert(level < Elements(tex->nr_images));
Keith Whitwell's avatar
Keith Whitwell committed
100

101
   tex->nr_images[level] = nr_images;
Keith Whitwell's avatar
Keith Whitwell committed
102 103 104

   /*
   DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
105
       level, w, h, d, x, y, tex->level_offset[level]);
Keith Whitwell's avatar
Keith Whitwell committed
106 107 108 109
   */

   /* Not sure when this would happen, but anyway: 
    */
110 111 112
   if (tex->image_offset[level]) {
      FREE(tex->image_offset[level]);
      tex->image_offset[level] = NULL;
Keith Whitwell's avatar
Keith Whitwell committed
113 114 115
   }

   assert(nr_images);
116
   assert(!tex->image_offset[level]);
Keith Whitwell's avatar
Keith Whitwell committed
117

118 119
   tex->image_offset[level] = (unsigned *) MALLOC(nr_images * sizeof(unsigned));
   tex->image_offset[level][0] = 0;
Keith Whitwell's avatar
Keith Whitwell committed
120 121 122
}

static void
123
i915_texture_set_image_offset(struct i915_texture *tex,
124
                              unsigned level, unsigned img, unsigned x, unsigned y)
Keith Whitwell's avatar
Keith Whitwell committed
125 126 127 128
{
   if (img == 0 && level == 0)
      assert(x == 0 && y == 0);

129
   assert(img < tex->nr_images[level]);
Keith Whitwell's avatar
Keith Whitwell committed
130

131
   tex->image_offset[level][img] = y * tex->stride + x * util_format_get_blocksize(tex->b.b.format);
132

Keith Whitwell's avatar
Keith Whitwell committed
133
   /*
134
   printf("%s level %d img %d pos %d,%d image_offset %x\n",
135
       __FUNCTION__, level, img, x, y, tex->image_offset[level][img]);
Keith Whitwell's avatar
Keith Whitwell committed
136 137 138
   */
}

139

140
/*
141
 * i915 layout functions, some used by i945
142 143
 */

144 145

/**
146
 * Special case to deal with scanout textures.
147 148
 */
static boolean
149
i915_scanout_layout(struct i915_texture *tex)
150
{
151
   struct pipe_resource *pt = &tex->b.b;
152

153
   if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
Jakob Bornecrantz's avatar
Jakob Bornecrantz committed
154
      return FALSE;
155

156
   i915_texture_set_level_info(tex, 0, 1,
157 158
                               pt->width0,
                               pt->height0,
159
                               1);
160
   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
161

162
   if (pt->width0 >= 240) {
163 164
      tex->stride = power_of_two(util_format_get_stride(pt->format, pt->width0));
      tex->total_nblocksy = align(util_format_get_nblocksy(pt->format, pt->height0), 8);
165
      tex->hw_tiled = I915_TILE_X;
166
   } else if (pt->width0 == 64 && pt->height0 == 64) {
167 168
      tex->stride = power_of_two(util_format_get_stride(pt->format, pt->width0));
      tex->total_nblocksy = align(util_format_get_nblocksy(pt->format, pt->height0), 8);
169
   } else {
170
      return FALSE;
171 172
   }

173
   debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
174
      pt->width0, pt->height0, util_format_get_blocksize(pt->format),
175
      tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
176

177
   return TRUE;
178 179
}

180 181 182 183 184 185
/**
 * Special case to deal with shared textures.
 */
static boolean
i915_display_target_layout(struct i915_texture *tex)
{
186
   struct pipe_resource *pt = &tex->b.b;
187

188
   if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
189 190 191
      return FALSE;

   /* fallback to normal textures for small textures */
192
   if (pt->width0 < 240)
193 194
      return FALSE;

195
   i915_texture_set_level_info(tex, 0, 1,
196 197
                               pt->width0,
                               pt->height0,
198
                               1);
199
   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
200

201 202
   tex->stride = power_of_two(util_format_get_stride(pt->format, pt->width0));
   tex->total_nblocksy = align(util_format_get_nblocksy(pt->format, pt->height0), 8);
203
   tex->hw_tiled = I915_TILE_X;
204 205

   debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
206
      pt->width0, pt->height0, util_format_get_blocksize(pt->format),
207 208 209 210 211
      tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);

   return TRUE;
}

212
static void
213
i915_texture_layout_2d(struct i915_texture *tex)
214
{
215
   struct pipe_resource *pt = &tex->b.b;
216
   unsigned level;
217 218
   unsigned width = pt->width0;
   unsigned height = pt->height0;
219
   unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0);
220

221
   /* used for scanouts that need special layouts */
Keith Whitwell's avatar
Keith Whitwell committed
222
   if (pt->bind & PIPE_BIND_SCANOUT)
223 224 225
      if (i915_scanout_layout(tex))
         return;

Keith Whitwell's avatar
Keith Whitwell committed
226 227 228 229 230 231 232
   /* shared buffers needs to be compatible with X servers 
    * 
    * XXX: need a better name than shared for this if it is to be part
    * of core gallium, and probably move the flag to resource.flags,
    * rather than bindings.
    */
   if (pt->bind & PIPE_BIND_SHARED)
233 234 235
      if (i915_display_target_layout(tex))
         return;

236
   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
237 238 239
   tex->total_nblocksy = 0;

   for (level = 0; level <= pt->last_level; level++) {
240 241
      i915_texture_set_level_info(tex, level, 1, width, height, 1);
      i915_texture_set_image_offset(tex, level, 0, 0, tex->total_nblocksy);
242

243
      nblocksy = align(MAX2(2, nblocksy), 2);
244 245 246

      tex->total_nblocksy += nblocksy;

247 248
      width = u_minify(width, 1);
      height = u_minify(height, 1);
249
      nblocksy = util_format_get_nblocksy(pt->format, height);
250 251 252 253
   }
}

static void
254
i915_texture_layout_3d(struct i915_texture *tex)
255
{
256
   struct pipe_resource *pt = &tex->b.b;
257 258
   unsigned level;

259 260 261
   unsigned width = pt->width0;
   unsigned height = pt->height0;
   unsigned depth = pt->depth0;
262
   unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0);
263 264 265 266
   unsigned stack_nblocksy = 0;

   /* Calculate the size of a single slice. 
    */
267
   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
268 269 270 271

   /* XXX: hardware expects/requires 9 levels at minimum.
    */
   for (level = 0; level <= MAX2(8, pt->last_level); level++) {
272
      i915_texture_set_level_info(tex, level, depth, width, height, depth);
273 274 275

      stack_nblocksy += MAX2(2, nblocksy);

276 277
      width = u_minify(width, 1);
      height = u_minify(height, 1);
278
      nblocksy = util_format_get_nblocksy(pt->format, height);
279 280 281 282 283 284 285
   }

   /* Fixup depth image_offsets: 
    */
   for (level = 0; level <= pt->last_level; level++) {
      unsigned i;
      for (i = 0; i < depth; i++) 
286
         i915_texture_set_image_offset(tex, level, i, 0, i * stack_nblocksy);
287

288
      depth = u_minify(depth, 1);
289 290 291 292 293 294
   }

   /* Multiply slice size by texture depth for total size.  It's
    * remarkable how wasteful of memory the i915 texture layouts
    * are.  They are largely fixed in the i945.
    */
295
   tex->total_nblocksy = stack_nblocksy * pt->depth0;
296 297 298
}

static void
299
i915_texture_layout_cube(struct i915_texture *tex)
300
{
301
   struct pipe_resource *pt = &tex->b.b;
302
   unsigned width = pt->width0, height = pt->height0;
303
   const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0);
304 305 306 307 308 309
   unsigned level;
   unsigned face;

   assert(width == height); /* cubemap images are square */

   /* double pitch for cube layouts */
310
   tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4);
311 312 313
   tex->total_nblocksy = nblocks * 4;

   for (level = 0; level <= pt->last_level; level++) {
314
      i915_texture_set_level_info(tex, level, 6, width, height, 1);
315 316 317 318 319 320 321 322 323 324
      width /= 2;
      height /= 2;
   }

   for (face = 0; face < 6; face++) {
      unsigned x = initial_offsets[face][0] * nblocks;
      unsigned y = initial_offsets[face][1] * nblocks;
      unsigned d = nblocks;

      for (level = 0; level <= pt->last_level; level++) {
325
         i915_texture_set_image_offset(tex, level, face, x, y);
326 327 328 329 330 331 332 333
         d >>= 1;
         x += step_offsets[face][0] * d;
         y += step_offsets[face][1] * d;
      }
   }
}

static boolean
334
i915_texture_layout(struct i915_texture * tex)
335
{
336
   struct pipe_resource *pt = &tex->b.b;
337 338 339 340

   switch (pt->target) {
   case PIPE_TEXTURE_1D:
   case PIPE_TEXTURE_2D:
341
      i915_texture_layout_2d(tex);
342 343
      break;
   case PIPE_TEXTURE_3D:
344
      i915_texture_layout_3d(tex);
345 346
      break;
   case PIPE_TEXTURE_CUBE:
347
      i915_texture_layout_cube(tex);
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
      break;
   default:
      assert(0);
      return FALSE;
   }

   return TRUE;
}


/*
 * i945 layout functions
 */


Keith Whitwell's avatar
Keith Whitwell committed
363
static void
364
i945_texture_layout_2d(struct i915_texture *tex)
Keith Whitwell's avatar
Keith Whitwell committed
365
{
366
   struct pipe_resource *pt = &tex->b.b;
367
   const int align_x = 2, align_y = 4;
368 369 370
   unsigned level;
   unsigned x = 0;
   unsigned y = 0;
371 372
   unsigned width = pt->width0;
   unsigned height = pt->height0;
373 374
   unsigned nblocksx = util_format_get_nblocksx(pt->format, pt->width0);
   unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0);
Keith Whitwell's avatar
Keith Whitwell committed
375

376
   /* used for scanouts that need special layouts */
Keith Whitwell's avatar
Keith Whitwell committed
377
   if (tex->b.b.bind & PIPE_BIND_SCANOUT)
378
      if (i915_scanout_layout(tex))
379
         return;
380

381
   /* shared buffers needs to be compatible with X servers */
Keith Whitwell's avatar
Keith Whitwell committed
382
   if (tex->b.b.bind & PIPE_BIND_SHARED)
383 384 385
      if (i915_display_target_layout(tex))
         return;

386
   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
Keith Whitwell's avatar
Keith Whitwell committed
387 388

   /* May need to adjust pitch to accomodate the placement of
389
    * the 2nd mipmap level.  This occurs when the alignment
Keith Whitwell's avatar
Keith Whitwell committed
390
    * constraints of mipmap placement push the right edge of the
391
    * 2nd mipmap level out past the width of its parent.
Keith Whitwell's avatar
Keith Whitwell committed
392
    */
393
   if (pt->last_level > 0) {
394
      unsigned mip1_nblocksx 
395 396
         = align(util_format_get_nblocksx(pt->format, u_minify(width, 1)), align_x)
         + util_format_get_nblocksx(pt->format, u_minify(width, 2));
Keith Whitwell's avatar
Keith Whitwell committed
397

398
      if (mip1_nblocksx > nblocksx)
399
         tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format);
Keith Whitwell's avatar
Keith Whitwell committed
400 401
   }

402
   /* Pitch must be a whole number of dwords
Keith Whitwell's avatar
Keith Whitwell committed
403
    */
404
   tex->stride = align(tex->stride, 64);
405
   tex->total_nblocksy = 0;
Keith Whitwell's avatar
Keith Whitwell committed
406

407
   for (level = 0; level <= pt->last_level; level++) {
408 409
      i915_texture_set_level_info(tex, level, 1, width, height, 1);
      i915_texture_set_image_offset(tex, level, 0, x, y);
Keith Whitwell's avatar
Keith Whitwell committed
410

411
      nblocksy = align(nblocksy, align_y);
Keith Whitwell's avatar
Keith Whitwell committed
412 413 414 415

      /* Because the images are packed better, the final offset
       * might not be the maximal one:
       */
416
      tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
Keith Whitwell's avatar
Keith Whitwell committed
417

418
      /* Layout_below: step right after second mipmap level.
Keith Whitwell's avatar
Keith Whitwell committed
419
       */
420
      if (level == 1) {
421
         x += align(nblocksx, align_x);
Keith Whitwell's avatar
Keith Whitwell committed
422 423
      }
      else {
424
         y += nblocksy;
Keith Whitwell's avatar
Keith Whitwell committed
425 426
      }

427 428
      width  = u_minify(width, 1);
      height = u_minify(height, 1);
429 430
      nblocksx = util_format_get_nblocksx(pt->format, width);
      nblocksy = util_format_get_nblocksy(pt->format, height);
Keith Whitwell's avatar
Keith Whitwell committed
431 432 433
   }
}

434
static void
435
i945_texture_layout_3d(struct i915_texture *tex)
436
{
437
   struct pipe_resource *pt = &tex->b.b;
438 439 440
   unsigned width = pt->width0;
   unsigned height = pt->height0;
   unsigned depth = pt->depth0;
441
   unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0);
442 443 444 445
   unsigned pack_x_pitch, pack_x_nr;
   unsigned pack_y_pitch;
   unsigned level;

446
   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
447 448
   tex->total_nblocksy = 0;

449
   pack_y_pitch = MAX2(nblocksy, 2);
450
   pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format);
451 452 453 454 455 456 457
   pack_x_nr = 1;

   for (level = 0; level <= pt->last_level; level++) {
      int x = 0;
      int y = 0;
      unsigned q, j;

458
      i915_texture_set_level_info(tex, level, depth, width, height, depth);
459 460 461

      for (q = 0; q < depth;) {
         for (j = 0; j < pack_x_nr && q < depth; j++, q++) {
462
            i915_texture_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
463 464 465 466 467 468 469 470 471 472 473 474
            x += pack_x_pitch;
         }

         x = 0;
         y += pack_y_pitch;
      }

      tex->total_nblocksy += y;

      if (pack_x_pitch > 4) {
         pack_x_pitch >>= 1;
         pack_x_nr <<= 1;
475
         assert(pack_x_pitch * pack_x_nr * util_format_get_blocksize(pt->format) <= tex->stride);
476 477 478 479 480 481
      }

      if (pack_y_pitch > 2) {
         pack_y_pitch >>= 1;
      }

482 483 484
      width = u_minify(width, 1);
      height = u_minify(height, 1);
      depth = u_minify(depth, 1);
485
      nblocksy = util_format_get_nblocksy(pt->format, height);
486 487 488
   }
}

489
static void
490
i945_texture_layout_cube(struct i915_texture *tex)
491
{
492
   struct pipe_resource *pt = &tex->b.b;
493
   unsigned level;
Keith Whitwell's avatar
Keith Whitwell committed
494

495
   const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0);
496
   unsigned face;
497 498
   unsigned width = pt->width0;
   unsigned height = pt->height0;
Keith Whitwell's avatar
Keith Whitwell committed
499

500
   /*
501
   printf("%s %i, %i\n", __FUNCTION__, pt->width0, pt->height0);
502 503
   */

504
   assert(width == height); /* cubemap images are square */
505

506 507 508 509 510
   /*
    * XXX Should only be used for compressed formats. But lets
    * keep this code active just in case.
    *
    * Depending on the size of the largest images, pitch can be
511 512 513
    * determined either by the old-style packing of cubemap faces,
    * or the final row of 4x4, 2x2 and 1x1 faces below this.
    */
514
   if (nblocks > 32)
515
      tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4);
516
   else
517
      tex->stride = 14 * 8 * util_format_get_blocksize(pt->format);
518

519
   tex->total_nblocksy = nblocks * 4;
520 521 522 523

   /* Set all the levels to effectively occupy the whole rectangular region.
   */
   for (level = 0; level <= pt->last_level; level++) {
524
      i915_texture_set_level_info(tex, level, 6, width, height, 1);
525 526
      width /= 2;
      height /= 2;
527
   }
Keith Whitwell's avatar
Keith Whitwell committed
528

529
   for (face = 0; face < 6; face++) {
530 531 532
      unsigned x = initial_offsets[face][0] * nblocks;
      unsigned y = initial_offsets[face][1] * nblocks;
      unsigned d = nblocks;
533

534
#if 0 /* Fix and enable this code for compressed formats */
535
      if (nblocks == 4 && face >= 4) {
536 537 538
         y = tex->total_height - 4;
         x = (face - 4) * 8;
      }
539
      else if (nblocks < 4 && (face > 0)) {
540 541 542
         y = tex->total_height - 4;
         x = face * 8;
      }
543
#endif
544 545

      for (level = 0; level <= pt->last_level; level++) {
546
         i915_texture_set_image_offset(tex, level, face, x, y);
547 548 549

         d >>= 1;

550
#if 0 /* Fix and enable this code for compressed formats */
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
         switch (d) {
            case 4:
               switch (face) {
                  case PIPE_TEX_FACE_POS_X:
                  case PIPE_TEX_FACE_NEG_X:
                     x += step_offsets[face][0] * d;
                     y += step_offsets[face][1] * d;
                     break;
                  case PIPE_TEX_FACE_POS_Y:
                  case PIPE_TEX_FACE_NEG_Y:
                     y += 12;
                     x -= 8;
                     break;
                  case PIPE_TEX_FACE_POS_Z:
                  case PIPE_TEX_FACE_NEG_Z:
                     y = tex->total_height - 4;
                     x = (face - 4) * 8;
                     break;
               }
            case 2:
               y = tex->total_height - 4;
               x = 16 + face * 8;
               break;

            case 1:
               x += 48;
               break;
            default:
579
#endif
580 581
               x += step_offsets[face][0] * d;
               y += step_offsets[face][1] * d;
582
#if 0
583 584
               break;
         }
585
#endif
586 587 588
      }
   }
}
Keith Whitwell's avatar
Keith Whitwell committed
589

590
static boolean
591
i945_texture_layout(struct i915_texture * tex)
Keith Whitwell's avatar
Keith Whitwell committed
592
{
593
   struct pipe_resource *pt = &tex->b.b;
Keith Whitwell's avatar
Keith Whitwell committed
594

595
   switch (pt->target) {
596 597
   case PIPE_TEXTURE_1D:
   case PIPE_TEXTURE_2D:
598
      i945_texture_layout_2d(tex);
599 600
      break;
   case PIPE_TEXTURE_3D:
601
      i945_texture_layout_3d(tex);
602
      break;
603
   case PIPE_TEXTURE_CUBE:
604
      i945_texture_layout_cube(tex);
605
      break;
Keith Whitwell's avatar
Keith Whitwell committed
606
   default:
607 608
      assert(0);
      return FALSE;
Keith Whitwell's avatar
Keith Whitwell committed
609 610
   }

611
   return TRUE;
Keith Whitwell's avatar
Keith Whitwell committed
612 613
}

614

615

616 617 618 619 620
/*
 * Screen texture functions
 */


621 622 623 624 625 626 627 628

static boolean
i915_texture_get_handle(struct pipe_screen * screen,
                        struct pipe_resource *texture,
                        struct winsys_handle *whandle)
{
   struct i915_screen *is = i915_screen(screen);
   struct i915_texture *tex = i915_texture(texture);
629
   struct i915_winsys *iws = is->iws;
630 631 632 633 634 635 636 637 638 639

   return iws->buffer_get_handle(iws, tex->buffer, whandle, tex->stride);
}


static void
i915_texture_destroy(struct pipe_screen *screen,
		     struct pipe_resource *pt)
{
   struct i915_texture *tex = i915_texture(pt);
640
   struct i915_winsys *iws = i915_screen(screen)->iws;
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
   uint i;

   /*
     DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
   */

   iws->buffer_destroy(iws, tex->buffer);

   for (i = 0; i < Elements(tex->image_offset); i++)
      if (tex->image_offset[i])
         FREE(tex->image_offset[i]);

   FREE(tex);
}

656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
static struct pipe_transfer * 
i915_texture_get_transfer(struct pipe_context *context,
			  struct pipe_resource *resource,
			  struct pipe_subresource sr,
			  unsigned usage,
			  const struct pipe_box *box)
{
   struct i915_texture *tex = i915_texture(resource);
   struct pipe_transfer *transfer = CALLOC_STRUCT(pipe_transfer);
   if (transfer == NULL)
      return NULL;

   transfer->resource = resource;
   transfer->sr = sr;
   transfer->usage = usage;
   transfer->box = *box;
   transfer->stride = tex->stride;

   return transfer;
}
676 677 678 679 680 681 682 683


static void *
i915_texture_transfer_map(struct pipe_context *pipe,
			  struct pipe_transfer *transfer)
{
   struct pipe_resource *resource = transfer->resource;
   struct i915_texture *tex = i915_texture(resource);
684
   struct i915_winsys *iws = i915_screen(pipe->screen)->iws;
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
   struct pipe_subresource sr = transfer->sr;
   struct pipe_box *box = &transfer->box;
   enum pipe_format format = resource->format;
   unsigned offset;
   char *map;

   if (resource->target == PIPE_TEXTURE_CUBE) {
      offset = tex->image_offset[sr.level][sr.face];
   }
   else if (resource->target == PIPE_TEXTURE_3D) {
      offset = tex->image_offset[sr.level][box->z];
   }
   else {
      offset = tex->image_offset[sr.level][0];
      assert(sr.face == 0);
      assert(box->z == 0);
   }

703 704 705
   map = iws->buffer_map(iws,
			 tex->buffer,
			 (transfer->usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE);
706 707 708 709 710 711 712 713 714 715 716 717 718
   if (map == NULL)
      return NULL;

   return map + offset +
      box->y / util_format_get_blockheight(format) * transfer->stride +
      box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
}

static void
i915_texture_transfer_unmap(struct pipe_context *pipe,
			    struct pipe_transfer *transfer)
{
   struct i915_texture *tex = i915_texture(transfer->resource);
719
   struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws;
720 721 722 723 724 725 726 727 728
   iws->buffer_unmap(iws, tex->buffer);
}



struct u_resource_vtbl i915_texture_vtbl = 
{
   i915_texture_get_handle,	      /* get_handle */
   i915_texture_destroy,	      /* resource_destroy */
729
   NULL,			      /* is_resource_referenced */
730
   i915_texture_get_transfer,	      /* get_transfer */
731 732 733 734 735 736 737 738 739 740 741
   u_default_transfer_destroy,	      /* transfer_destroy */
   i915_texture_transfer_map,	      /* transfer_map */
   u_default_transfer_flush_region,   /* transfer_flush_region */
   i915_texture_transfer_unmap,	      /* transfer_unmap */
   u_default_transfer_inline_write    /* transfer_inline_write */
};




struct pipe_resource *
742
i915_texture_create(struct pipe_screen *screen,
743
                    const struct pipe_resource *template)
744
{
745
   struct i915_screen *is = i915_screen(screen);
746
   struct i915_winsys *iws = is->iws;
747
   struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
748
   size_t tex_size;
749
   unsigned buf_usage = 0;
750

751
   if (!tex)
752
      return NULL;
753

754 755 756 757
   tex->b.b = *template;
   tex->b.vtbl = &i915_texture_vtbl;
   pipe_reference_init(&tex->b.b.reference, 1);
   tex->b.b.screen = screen;
758

759
   if (is->is_i945) {
760
      if (!i945_texture_layout(tex))
761
         goto fail;
762
   } else {
763
      if (!i915_texture_layout(tex))
764
         goto fail;
765 766
   }

767 768
   tex_size = tex->stride * tex->total_nblocksy;

769
   /* for scanouts and cursors, cursors arn't scanouts */
Keith Whitwell's avatar
Keith Whitwell committed
770 771 772 773 774

   /* XXX: use a custom flag for cursors, don't rely on magically
    * guessing that this is Xorg asking for a cursor
    */
   if ((template->bind & PIPE_BIND_SCANOUT) && template->width0 != 64)
775
      buf_usage = I915_NEW_SCANOUT;
776
   else
777
      buf_usage = I915_NEW_TEXTURE;
778

779
   tex->buffer = iws->buffer_create(iws, tex_size, 64, buf_usage);
780 781
   if (!tex->buffer)
      goto fail;
782

783 784
   /* setup any hw fences */
   if (tex->hw_tiled) {
785
      assert(tex->sw_tiled == I915_TILE_NONE);
786 787 788 789
      iws->buffer_set_fence_reg(iws, tex->buffer, tex->stride, tex->hw_tiled);
   }

   
790
#if 0
Zack Rusin's avatar
Zack Rusin committed
791
   void *ptr = ws->buffer_map(ws, tex->buffer,
792 793
      PIPE_BUFFER_USAGE_CPU_WRITE);
   memset(ptr, 0x80, tex_size);
Zack Rusin's avatar
Zack Rusin committed
794
   ws->buffer_unmap(ws, tex->buffer);
795 796
#endif

797
   return &tex->b.b;
798

799
fail:
800 801
   FREE(tex);
   return NULL;
802 803
}

804
struct pipe_resource *
805
i915_texture_from_handle(struct pipe_screen * screen,
806 807
			  const struct pipe_resource *template,
			  struct winsys_handle *whandle)
808 809 810
{
   struct i915_screen *is = i915_screen(screen);
   struct i915_texture *tex;
811 812
   struct i915_winsys *iws = is->iws;
   struct i915_winsys_buffer *buffer;
813 814 815 816 817 818 819
   unsigned stride;

   assert(screen);

   buffer = iws->buffer_from_handle(iws, whandle, &stride);

   /* Only supports one type */
820 821 822
   if (template->target != PIPE_TEXTURE_2D ||
       template->last_level != 0 ||
       template->depth0 != 1) {
823 824 825 826 827 828 829
      return NULL;
   }

   tex = CALLOC_STRUCT(i915_texture);
   if (!tex)
      return NULL;

830 831 832 833
   tex->b.b = *template;
   tex->b.vtbl = &i915_texture_vtbl;
   pipe_reference_init(&tex->b.b.reference, 1);
   tex->b.b.screen = screen;
834 835 836

   tex->stride = stride;

837 838
   i915_texture_set_level_info(tex, 0, 1, template->width0, template->height0, 1);
   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
839 840 841

   tex->buffer = buffer;

842
   return &tex->b.b;
843 844
}