i915_texture.c 24.3 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 42
#include "i915_context.h"
#include "i915_texture.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_miptree_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_miptree_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->base.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 152
   struct pipe_texture *pt = &tex->base;

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_miptree_set_level_info(tex, 0, 1,
157 158
                               pt->width0,
                               pt->height0,
159 160
                               1);
   i915_miptree_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 186 187
/**
 * Special case to deal with shared textures.
 */
static boolean
i915_display_target_layout(struct i915_texture *tex)
{
   struct pipe_texture *pt = &tex->base;

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 195
      return FALSE;

   i915_miptree_set_level_info(tex, 0, 1,
196 197
                               pt->width0,
                               pt->height0,
198 199 200
                               1);
   i915_miptree_set_image_offset(tex, 0, 0, 0, 0);

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 213 214 215 216
static void
i915_miptree_layout_2d(struct i915_texture *tex)
{
   struct pipe_texture *pt = &tex->base;
   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 */
222
   if (pt->tex_usage & PIPE_TEXTURE_USAGE_SCANOUT)
223 224 225
      if (i915_scanout_layout(tex))
         return;

226 227
   /* shared buffers needs to be compatible with X servers */
   if (pt->tex_usage & PIPE_TEXTURE_USAGE_SHARED)
228 229 230
      if (i915_display_target_layout(tex))
         return;

231
   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
232 233 234 235 236 237
   tex->total_nblocksy = 0;

   for (level = 0; level <= pt->last_level; level++) {
      i915_miptree_set_level_info(tex, level, 1, width, height, 1);
      i915_miptree_set_image_offset(tex, level, 0, 0, tex->total_nblocksy);

238
      nblocksy = align(MAX2(2, nblocksy), 2);
239 240 241

      tex->total_nblocksy += nblocksy;

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

static void
i915_miptree_layout_3d(struct i915_texture *tex)
{
   struct pipe_texture *pt = &tex->base;
   unsigned level;

254 255 256
   unsigned width = pt->width0;
   unsigned height = pt->height0;
   unsigned depth = pt->depth0;
257
   unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0);
258 259 260 261
   unsigned stack_nblocksy = 0;

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

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

      stack_nblocksy += MAX2(2, nblocksy);

271 272
      width = u_minify(width, 1);
      height = u_minify(height, 1);
273
      nblocksy = util_format_get_nblocksy(pt->format, height);
274 275 276 277 278 279 280 281 282
   }

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

283
      depth = u_minify(depth, 1);
284 285 286 287 288 289
   }

   /* 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.
    */
290
   tex->total_nblocksy = stack_nblocksy * pt->depth0;
291 292 293 294 295 296
}

static void
i915_miptree_layout_cube(struct i915_texture *tex)
{
   struct pipe_texture *pt = &tex->base;
297
   unsigned width = pt->width0, height = pt->height0;
298
   const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0);
299 300 301 302 303 304
   unsigned level;
   unsigned face;

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

   /* double pitch for cube layouts */
305
   tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4);
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
   tex->total_nblocksy = nblocks * 4;

   for (level = 0; level <= pt->last_level; level++) {
      i915_miptree_set_level_info(tex, level, 6, width, height, 1);
      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++) {
         i915_miptree_set_image_offset(tex, level, face, x, y);
         d >>= 1;
         x += step_offsets[face][0] * d;
         y += step_offsets[face][1] * d;
      }
   }
}

static boolean
i915_miptree_layout(struct i915_texture * tex)
{
   struct pipe_texture *pt = &tex->base;

   switch (pt->target) {
   case PIPE_TEXTURE_1D:
   case PIPE_TEXTURE_2D:
      i915_miptree_layout_2d(tex);
      break;
   case PIPE_TEXTURE_3D:
      i915_miptree_layout_3d(tex);
      break;
   case PIPE_TEXTURE_CUBE:
      i915_miptree_layout_cube(tex);
      break;
   default:
      assert(0);
      return FALSE;
   }

   return TRUE;
}


/*
 * i945 layout functions
 */


Keith Whitwell's avatar
Keith Whitwell committed
358
static void
359
i945_miptree_layout_2d(struct i915_texture *tex)
Keith Whitwell's avatar
Keith Whitwell committed
360
{
361
   struct pipe_texture *pt = &tex->base;
362
   const int align_x = 2, align_y = 4;
363 364 365
   unsigned level;
   unsigned x = 0;
   unsigned y = 0;
366 367
   unsigned width = pt->width0;
   unsigned height = pt->height0;
368 369
   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
370

371
   /* used for scanouts that need special layouts */
372
   if (tex->base.tex_usage & PIPE_TEXTURE_USAGE_SCANOUT)
373
      if (i915_scanout_layout(tex))
374
         return;
375

376 377
   /* shared buffers needs to be compatible with X servers */
   if (tex->base.tex_usage & PIPE_TEXTURE_USAGE_SHARED)
378 379 380
      if (i915_display_target_layout(tex))
         return;

381
   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
Keith Whitwell's avatar
Keith Whitwell committed
382 383

   /* May need to adjust pitch to accomodate the placement of
384
    * the 2nd mipmap level.  This occurs when the alignment
Keith Whitwell's avatar
Keith Whitwell committed
385
    * constraints of mipmap placement push the right edge of the
386
    * 2nd mipmap level out past the width of its parent.
Keith Whitwell's avatar
Keith Whitwell committed
387
    */
388
   if (pt->last_level > 0) {
389
      unsigned mip1_nblocksx 
390 391
         = 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
392

393
      if (mip1_nblocksx > nblocksx)
394
         tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format);
Keith Whitwell's avatar
Keith Whitwell committed
395 396
   }

397
   /* Pitch must be a whole number of dwords
Keith Whitwell's avatar
Keith Whitwell committed
398
    */
399
   tex->stride = align(tex->stride, 64);
400
   tex->total_nblocksy = 0;
Keith Whitwell's avatar
Keith Whitwell committed
401

402
   for (level = 0; level <= pt->last_level; level++) {
403 404
      i915_miptree_set_level_info(tex, level, 1, width, height, 1);
      i915_miptree_set_image_offset(tex, level, 0, x, y);
Keith Whitwell's avatar
Keith Whitwell committed
405

406
      nblocksy = align(nblocksy, align_y);
Keith Whitwell's avatar
Keith Whitwell committed
407 408 409 410

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

413
      /* Layout_below: step right after second mipmap level.
Keith Whitwell's avatar
Keith Whitwell committed
414
       */
415
      if (level == 1) {
416
         x += align(nblocksx, align_x);
Keith Whitwell's avatar
Keith Whitwell committed
417 418
      }
      else {
419
         y += nblocksy;
Keith Whitwell's avatar
Keith Whitwell committed
420 421
      }

422 423
      width  = u_minify(width, 1);
      height = u_minify(height, 1);
424 425
      nblocksx = util_format_get_nblocksx(pt->format, width);
      nblocksy = util_format_get_nblocksy(pt->format, height);
Keith Whitwell's avatar
Keith Whitwell committed
426 427 428
   }
}

429 430 431 432
static void
i945_miptree_layout_3d(struct i915_texture *tex)
{
   struct pipe_texture *pt = &tex->base;
433 434 435
   unsigned width = pt->width0;
   unsigned height = pt->height0;
   unsigned depth = pt->depth0;
436
   unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0);
437 438 439 440
   unsigned pack_x_pitch, pack_x_nr;
   unsigned pack_y_pitch;
   unsigned level;

441
   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
442 443
   tex->total_nblocksy = 0;

444
   pack_y_pitch = MAX2(nblocksy, 2);
445
   pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format);
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
   pack_x_nr = 1;

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

      i915_miptree_set_level_info(tex, level, depth, width, height, depth);

      for (q = 0; q < depth;) {
         for (j = 0; j < pack_x_nr && q < depth; j++, q++) {
            i915_miptree_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
            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;
470
         assert(pack_x_pitch * pack_x_nr * util_format_get_blocksize(pt->format) <= tex->stride);
471 472 473 474 475 476
      }

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

477 478 479
      width = u_minify(width, 1);
      height = u_minify(height, 1);
      depth = u_minify(depth, 1);
480
      nblocksy = util_format_get_nblocksy(pt->format, height);
481 482 483
   }
}

484 485 486 487 488
static void
i945_miptree_layout_cube(struct i915_texture *tex)
{
   struct pipe_texture *pt = &tex->base;
   unsigned level;
Keith Whitwell's avatar
Keith Whitwell committed
489

490
   const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0);
491
   unsigned face;
492 493
   unsigned width = pt->width0;
   unsigned height = pt->height0;
Keith Whitwell's avatar
Keith Whitwell committed
494

495
   /*
496
   printf("%s %i, %i\n", __FUNCTION__, pt->width0, pt->height0);
497 498
   */

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

501 502 503 504 505
   /*
    * 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
506 507 508
    * determined either by the old-style packing of cubemap faces,
    * or the final row of 4x4, 2x2 and 1x1 faces below this.
    */
509
   if (nblocks > 32)
510
      tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4);
511
   else
512
      tex->stride = 14 * 8 * util_format_get_blocksize(pt->format);
513

514
   tex->total_nblocksy = nblocks * 4;
515 516 517 518

   /* Set all the levels to effectively occupy the whole rectangular region.
   */
   for (level = 0; level <= pt->last_level; level++) {
519 520 521
      i915_miptree_set_level_info(tex, level, 6, width, height, 1);
      width /= 2;
      height /= 2;
522
   }
Keith Whitwell's avatar
Keith Whitwell committed
523

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

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

      for (level = 0; level <= pt->last_level; level++) {
         i915_miptree_set_image_offset(tex, level, face, x, y);

         d >>= 1;

545
#if 0 /* Fix and enable this code for compressed formats */
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
         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:
574
#endif
575 576
               x += step_offsets[face][0] * d;
               y += step_offsets[face][1] * d;
577
#if 0
578 579
               break;
         }
580
#endif
581 582 583
      }
   }
}
Keith Whitwell's avatar
Keith Whitwell committed
584

585
static boolean
586
i945_miptree_layout(struct i915_texture * tex)
Keith Whitwell's avatar
Keith Whitwell committed
587
{
588
   struct pipe_texture *pt = &tex->base;
Keith Whitwell's avatar
Keith Whitwell committed
589

590
   switch (pt->target) {
591 592 593 594 595 596 597
   case PIPE_TEXTURE_1D:
   case PIPE_TEXTURE_2D:
      i945_miptree_layout_2d(tex);
      break;
   case PIPE_TEXTURE_3D:
      i945_miptree_layout_3d(tex);
      break;
598 599 600
   case PIPE_TEXTURE_CUBE:
      i945_miptree_layout_cube(tex);
      break;
Keith Whitwell's avatar
Keith Whitwell committed
601
   default:
602 603
      assert(0);
      return FALSE;
Keith Whitwell's avatar
Keith Whitwell committed
604 605
   }

606
   return TRUE;
Keith Whitwell's avatar
Keith Whitwell committed
607 608
}

609

610 611 612 613 614
/*
 * Screen texture functions
 */


615
static struct pipe_texture *
616 617
i915_texture_create(struct pipe_screen *screen,
                    const struct pipe_texture *templat)
618
{
619
   struct i915_screen *is = i915_screen(screen);
620
   struct i915_winsys *iws = is->iws;
621
   struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
622
   size_t tex_size;
623
   unsigned buf_usage = 0;
624

625
   if (!tex)
626
      return NULL;
627

628
   tex->base = *templat;
629
   pipe_reference_init(&tex->base.reference, 1);
630
   tex->base.screen = screen;
631

632
   if (is->is_i945) {
633
      if (!i945_miptree_layout(tex))
634
         goto fail;
635 636
   } else {
      if (!i915_miptree_layout(tex))
637
         goto fail;
638 639
   }

640 641
   tex_size = tex->stride * tex->total_nblocksy;

642

643

644
   /* for scanouts and cursors, cursors arn't scanouts */
645
   if (templat->tex_usage & PIPE_TEXTURE_USAGE_SCANOUT && templat->width0 != 64)
646
      buf_usage = I915_NEW_SCANOUT;
647
   else
648
      buf_usage = I915_NEW_TEXTURE;
649

650
   tex->buffer = iws->buffer_create(iws, tex_size, 64, buf_usage);
651 652
   if (!tex->buffer)
      goto fail;
653

654 655
   /* setup any hw fences */
   if (tex->hw_tiled) {
656
      assert(tex->sw_tiled == I915_TILE_NONE);
657 658 659 660
      iws->buffer_set_fence_reg(iws, tex->buffer, tex->stride, tex->hw_tiled);
   }

   
661
#if 0
Zack Rusin's avatar
Zack Rusin committed
662
   void *ptr = ws->buffer_map(ws, tex->buffer,
663 664
      PIPE_BUFFER_USAGE_CPU_WRITE);
   memset(ptr, 0x80, tex_size);
Zack Rusin's avatar
Zack Rusin committed
665
   ws->buffer_unmap(ws, tex->buffer);
666 667
#endif

668
   return &tex->base;
669

670
fail:
671 672
   FREE(tex);
   return NULL;
673 674
}

675 676 677 678 679 680 681
static struct pipe_texture *
i915_texture_from_handle(struct pipe_screen * screen,
                         const struct pipe_texture *templat,
                         struct winsys_handle *whandle)
{
   struct i915_screen *is = i915_screen(screen);
   struct i915_texture *tex;
682 683
   struct i915_winsys *iws = is->iws;
   struct i915_winsys_buffer *buffer;
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
   unsigned stride;

   assert(screen);

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

   /* Only supports one type */
   if (templat->target != PIPE_TEXTURE_2D ||
       templat->last_level != 0 ||
       templat->depth0 != 1) {
      return NULL;
   }

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

   tex->base = *templat;
   pipe_reference_init(&tex->base.reference, 1);
   tex->base.screen = screen;

   tex->stride = stride;

   i915_miptree_set_level_info(tex, 0, 1, templat->width0, templat->height0, 1);
   i915_miptree_set_image_offset(tex, 0, 0, 0, 0);

   tex->buffer = buffer;

   return &tex->base;
}

static boolean
i915_texture_get_handle(struct pipe_screen * screen,
                        struct pipe_texture *texture,
                        struct winsys_handle *whandle)
{
   struct i915_screen *is = i915_screen(screen);
   struct i915_texture *tex = (struct i915_texture *)texture;
722
   struct i915_winsys *iws = is->iws;
723 724 725 726

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

727

728
static void
729
i915_texture_destroy(struct pipe_texture *pt)
730
{
731
   struct i915_texture *tex = (struct i915_texture *)pt;
732
   struct i915_winsys *iws = i915_screen(pt->screen)->iws;
733
   uint i;
734 735

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

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

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

745
   FREE(tex);
746
}
747

748 749 750 751 752 753

/*
 * Screen surface functions
 */


754
static struct pipe_surface *
755 756 757 758
i915_get_tex_surface(struct pipe_screen *screen,
                     struct pipe_texture *pt,
                     unsigned face, unsigned level, unsigned zslice,
                     unsigned flags)
759 760 761 762 763 764
{
   struct i915_texture *tex = (struct i915_texture *)pt;
   struct pipe_surface *ps;
   unsigned offset;  /* in bytes */

   if (pt->target == PIPE_TEXTURE_CUBE) {
765
      offset = tex->image_offset[level][face];
766 767
   }
   else if (pt->target == PIPE_TEXTURE_3D) {
768
      offset = tex->image_offset[level][zslice];
769 770
   }
   else {
771
      offset = tex->image_offset[level][0];
772 773 774 775
      assert(face == 0);
      assert(zslice == 0);
   }

776
   ps = CALLOC_STRUCT(pipe_surface);
777
   if (ps) {
778
      pipe_reference_init(&ps->reference, 1);
779
      pipe_texture_reference(&ps->texture, pt);
780
      ps->format = pt->format;
781 782
      ps->width = u_minify(pt->width0, level);
      ps->height = u_minify(pt->height0, level);
783
      ps->offset = offset;
784
      ps->usage = flags;
785 786 787 788
   }
   return ps;
}

789
static void
790
i915_tex_surface_destroy(struct pipe_surface *surf)
791
{
792 793
   pipe_texture_reference(&surf->texture, NULL);
   FREE(surf);
794
}
795

796

797
/*
798
 * Texture transfer functions
799 800 801
 */


802 803
static struct pipe_transfer *
i915_get_tex_transfer(struct pipe_context *pipe,
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
                      struct pipe_texture *texture,
                      unsigned face, unsigned level, unsigned zslice,
                      enum pipe_transfer_usage usage, unsigned x, unsigned y,
                      unsigned w, unsigned h)
{
   struct i915_texture *tex = (struct i915_texture *)texture;
   struct i915_transfer *trans;
   unsigned offset;  /* in bytes */

   if (texture->target == PIPE_TEXTURE_CUBE) {
      offset = tex->image_offset[level][face];
   }
   else if (texture->target == PIPE_TEXTURE_3D) {
      offset = tex->image_offset[level][zslice];
   }
   else {
      offset = tex->image_offset[level][0];
      assert(face == 0);
      assert(zslice == 0);
   }

   trans = CALLOC_STRUCT(i915_transfer);
   if (trans) {
      pipe_texture_reference(&trans->base.texture, texture);
      trans->base.x = x;
      trans->base.y = y;
      trans->base.width = w;
      trans->base.height = h;
      trans->base.stride = tex->stride;
      trans->offset = offset;
      trans->base.usage = usage;
   }
   return &trans->base;
}

static void *
840
i915_transfer_map(struct pipe_context *pipe,
841 842 843
                  struct pipe_transfer *transfer)
{
   struct i915_texture *tex = (struct i915_texture *)transfer->texture;
844
   struct i915_winsys *iws = i915_screen(tex->base.screen)->iws;
845
   char *map;
846
   boolean write = FALSE;
847
   enum pipe_format format = tex->base.format;
848

849
   if (transfer->usage & PIPE_TRANSFER_WRITE)
850
      write = TRUE;
851

852
   map = iws->buffer_map(iws, tex->buffer, write);
853 854 855 856
   if (map == NULL)
      return NULL;

   return map + i915_transfer(transfer)->offset +
857 858
      transfer->y / util_format_get_blockheight(format) * transfer->stride +
      transfer->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
859 860 861
}

static void
862
i915_transfer_unmap(struct pipe_context *pipe,
863 864 865
                    struct pipe_transfer *transfer)
{
   struct i915_texture *tex = (struct i915_texture *)transfer->texture;
866
   struct i915_winsys *iws = i915_screen(tex->base.screen)->iws;
867
   iws->buffer_unmap(iws, tex->buffer);
868 869 870
}

static void
871 872
i915_tex_transfer_destroy(struct pipe_context *pipe,
                          struct pipe_transfer *trans)
873 874 875 876 877 878
{
   pipe_texture_reference(&trans->texture, NULL);
   FREE(trans);
}


879 880 881 882
/*
 * Other texture functions
 */

883 884 885 886 887 888 889 890
void
i915_init_texture_functions(struct i915_context *i915 )
{
   i915->base.get_tex_transfer = i915_get_tex_transfer;
   i915->base.transfer_map = i915_transfer_map;
   i915->base.transfer_unmap = i915_transfer_unmap;
   i915->base.tex_transfer_destroy = i915_tex_transfer_destroy;
}
891

892
void
893
i915_init_screen_texture_functions(struct i915_screen *is)
894
{
895
   is->base.texture_create = i915_texture_create;
896 897
   is->base.texture_from_handle = i915_texture_from_handle;
   is->base.texture_get_handle = i915_texture_get_handle;
898 899 900
   is->base.texture_destroy = i915_texture_destroy;
   is->base.get_tex_surface = i915_get_tex_surface;
   is->base.tex_surface_destroy = i915_tex_surface_destroy;
901
}