00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "pipe/p_state.h"
00034 #include "pipe/p_context.h"
00035 #include "pipe/p_defines.h"
00036 #include "pipe/p_inlines.h"
00037 #include "pipe/p_winsys.h"
00038 #include "util/u_math.h"
00039 #include "util/u_memory.h"
00040
00041 #include "i915_context.h"
00042 #include "i915_texture.h"
00043 #include "i915_debug.h"
00044 #include "i915_screen.h"
00045
00046
00047
00048
00049
00053 static const int initial_offsets[6][2] = {
00054 {0, 0},
00055 {0, 2},
00056 {1, 0},
00057 {1, 2},
00058 {1, 1},
00059 {1, 3}
00060 };
00061
00065 static const int step_offsets[6][2] = {
00066 {0, 2},
00067 {0, 2},
00068 {-1, 2},
00069 {-1, 2},
00070 {-1, 1},
00071 {-1, 1}
00072 };
00073
00074 static unsigned minify( unsigned d )
00075 {
00076 return MAX2(1, d>>1);
00077 }
00078
00079 static unsigned
00080 power_of_two(unsigned x)
00081 {
00082 unsigned value = 1;
00083 while (value < x)
00084 value = value << 1;
00085 return value;
00086 }
00087
00088 static unsigned
00089 round_up(unsigned n, unsigned multiple)
00090 {
00091 return (n + multiple - 1) & ~(multiple - 1);
00092 }
00093
00094
00095
00096
00097
00098
00099
00100 static void
00101 i915_miptree_set_level_info(struct i915_texture *tex,
00102 unsigned level,
00103 unsigned nr_images,
00104 unsigned w, unsigned h, unsigned d)
00105 {
00106 struct pipe_texture *pt = &tex->base;
00107
00108 assert(level < PIPE_MAX_TEXTURE_LEVELS);
00109
00110 pt->width[level] = w;
00111 pt->height[level] = h;
00112 pt->depth[level] = d;
00113
00114 pt->nblocksx[level] = pf_get_nblocksx(&pt->block, w);
00115 pt->nblocksy[level] = pf_get_nblocksy(&pt->block, h);
00116
00117 tex->nr_images[level] = nr_images;
00118
00119
00120
00121
00122
00123
00124
00125
00126 if (tex->image_offset[level]) {
00127 FREE(tex->image_offset[level]);
00128 tex->image_offset[level] = NULL;
00129 }
00130
00131 assert(nr_images);
00132 assert(!tex->image_offset[level]);
00133
00134 tex->image_offset[level] = (unsigned *) MALLOC(nr_images * sizeof(unsigned));
00135 tex->image_offset[level][0] = 0;
00136 }
00137
00138 static void
00139 i915_miptree_set_image_offset(struct i915_texture *tex,
00140 unsigned level, unsigned img, unsigned x, unsigned y)
00141 {
00142 if (img == 0 && level == 0)
00143 assert(x == 0 && y == 0);
00144
00145 assert(img < tex->nr_images[level]);
00146
00147 tex->image_offset[level][img] = y * tex->stride + x * tex->base.block.size;
00148
00149
00150
00151
00152
00153 }
00154
00155
00156
00157
00158
00159
00160
00164 static boolean
00165 i915_displaytarget_layout(struct i915_texture *tex)
00166 {
00167 struct pipe_texture *pt = &tex->base;
00168
00169 if (pt->last_level > 0 || pt->block.size != 4)
00170 return 0;
00171
00172 i915_miptree_set_level_info( tex, 0, 1,
00173 tex->base.width[0],
00174 tex->base.height[0],
00175 1 );
00176 i915_miptree_set_image_offset( tex, 0, 0, 0, 0 );
00177
00178 if (tex->base.width[0] >= 128) {
00179 tex->stride = power_of_two(tex->base.nblocksx[0] * pt->block.size);
00180 tex->total_nblocksy = round_up(tex->base.nblocksy[0], 8);
00181 tex->tiled = 1;
00182 } else {
00183 tex->stride = round_up(tex->base.nblocksx[0] * pt->block.size, 64);
00184 tex->total_nblocksy = tex->base.nblocksy[0];
00185 }
00186
00187
00188
00189
00190
00191
00192
00193 return 1;
00194 }
00195
00196 static void
00197 i945_miptree_layout_2d( struct i915_texture *tex )
00198 {
00199 struct pipe_texture *pt = &tex->base;
00200 const int align_x = 2, align_y = 4;
00201 unsigned level;
00202 unsigned x = 0;
00203 unsigned y = 0;
00204 unsigned width = pt->width[0];
00205 unsigned height = pt->height[0];
00206 unsigned nblocksx = pt->nblocksx[0];
00207 unsigned nblocksy = pt->nblocksy[0];
00208
00209 #if 0
00210 if (pt->last_level == 0 && pt->block.size == 4)
00211 if (i915_displaytarget_layout(tex))
00212 return;
00213 #endif
00214
00215 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
00216
00217
00218
00219
00220
00221
00222 if (pt->last_level > 0) {
00223 unsigned mip1_nblocksx
00224 = align(pf_get_nblocksx(&pt->block, minify(width)), align_x)
00225 + pf_get_nblocksx(&pt->block, minify(minify(width)));
00226
00227 if (mip1_nblocksx > nblocksx)
00228 tex->stride = mip1_nblocksx * pt->block.size;
00229 }
00230
00231
00232
00233 tex->stride = align(tex->stride, 64);
00234 tex->total_nblocksy = 0;
00235
00236 for (level = 0; level <= pt->last_level; level++) {
00237 i915_miptree_set_level_info(tex, level, 1, width, height, 1);
00238 i915_miptree_set_image_offset(tex, level, 0, x, y);
00239
00240 nblocksy = align(nblocksy, align_y);
00241
00242
00243
00244
00245 tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
00246
00247
00248
00249 if (level == 1) {
00250 x += align(nblocksx, align_x);
00251 }
00252 else {
00253 y += nblocksy;
00254 }
00255
00256 width = minify(width);
00257 height = minify(height);
00258 nblocksx = pf_get_nblocksx(&pt->block, width);
00259 nblocksy = pf_get_nblocksy(&pt->block, height);
00260 }
00261 }
00262
00263 static void
00264 i945_miptree_layout_cube(struct i915_texture *tex)
00265 {
00266 struct pipe_texture *pt = &tex->base;
00267 unsigned level;
00268
00269 const unsigned nblocks = pt->nblocksx[0];
00270 unsigned face;
00271 unsigned width = pt->width[0];
00272 unsigned height = pt->height[0];
00273
00274
00275
00276
00277
00278 assert(width == height);
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 if (nblocks > 32)
00289 tex->stride = round_up(nblocks * pt->block.size * 2, 4);
00290 else
00291 tex->stride = 14 * 8 * pt->block.size;
00292
00293 tex->total_nblocksy = nblocks * 4;
00294
00295
00296
00297 for (level = 0; level <= pt->last_level; level++) {
00298 i915_miptree_set_level_info(tex, level, 6, width, height, 1);
00299 width /= 2;
00300 height /= 2;
00301 }
00302
00303 for (face = 0; face < 6; face++) {
00304 unsigned x = initial_offsets[face][0] * nblocks;
00305 unsigned y = initial_offsets[face][1] * nblocks;
00306 unsigned d = nblocks;
00307
00308 #if 0
00309 if (nblocks == 4 && face >= 4) {
00310 y = tex->total_height - 4;
00311 x = (face - 4) * 8;
00312 }
00313 else if (nblocks < 4 && (face > 0)) {
00314 y = tex->total_height - 4;
00315 x = face * 8;
00316 }
00317 #endif
00318
00319 for (level = 0; level <= pt->last_level; level++) {
00320 i915_miptree_set_image_offset(tex, level, face, x, y);
00321
00322 d >>= 1;
00323
00324 #if 0
00325 switch (d) {
00326 case 4:
00327 switch (face) {
00328 case PIPE_TEX_FACE_POS_X:
00329 case PIPE_TEX_FACE_NEG_X:
00330 x += step_offsets[face][0] * d;
00331 y += step_offsets[face][1] * d;
00332 break;
00333 case PIPE_TEX_FACE_POS_Y:
00334 case PIPE_TEX_FACE_NEG_Y:
00335 y += 12;
00336 x -= 8;
00337 break;
00338 case PIPE_TEX_FACE_POS_Z:
00339 case PIPE_TEX_FACE_NEG_Z:
00340 y = tex->total_height - 4;
00341 x = (face - 4) * 8;
00342 break;
00343 }
00344 case 2:
00345 y = tex->total_height - 4;
00346 x = 16 + face * 8;
00347 break;
00348
00349 case 1:
00350 x += 48;
00351 break;
00352 default:
00353 #endif
00354 x += step_offsets[face][0] * d;
00355 y += step_offsets[face][1] * d;
00356 #if 0
00357 break;
00358 }
00359 #endif
00360 }
00361 }
00362 }
00363
00364 static boolean
00365 i915_miptree_layout(struct i915_texture * tex)
00366 {
00367 struct pipe_texture *pt = &tex->base;
00368 unsigned level;
00369
00370 switch (pt->target) {
00371 case PIPE_TEXTURE_CUBE: {
00372 const unsigned nblocks = pt->nblocksx[0];
00373 unsigned face;
00374 unsigned width = pt->width[0], height = pt->height[0];
00375
00376 assert(width == height);
00377
00378
00379 tex->stride = round_up(nblocks * pt->block.size * 2, 4);
00380 tex->total_nblocksy = nblocks * 4;
00381
00382 for (level = 0; level <= pt->last_level; level++) {
00383 i915_miptree_set_level_info(tex, level, 6,
00384 width, height,
00385 1);
00386 width /= 2;
00387 height /= 2;
00388 }
00389
00390 for (face = 0; face < 6; face++) {
00391 unsigned x = initial_offsets[face][0] * nblocks;
00392 unsigned y = initial_offsets[face][1] * nblocks;
00393 unsigned d = nblocks;
00394
00395 for (level = 0; level <= pt->last_level; level++) {
00396 i915_miptree_set_image_offset(tex, level, face, x, y);
00397 d >>= 1;
00398 x += step_offsets[face][0] * d;
00399 y += step_offsets[face][1] * d;
00400 }
00401 }
00402 break;
00403 }
00404 case PIPE_TEXTURE_3D:{
00405 unsigned width = pt->width[0];
00406 unsigned height = pt->height[0];
00407 unsigned depth = pt->depth[0];
00408 unsigned nblocksx = pt->nblocksx[0];
00409 unsigned nblocksy = pt->nblocksy[0];
00410 unsigned stack_nblocksy = 0;
00411
00412
00413
00414 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
00415
00416
00417
00418 for (level = 0; level <= MAX2(8, pt->last_level);
00419 level++) {
00420 i915_miptree_set_level_info(tex, level, depth,
00421 width, height, depth);
00422
00423
00424 stack_nblocksy += MAX2(2, nblocksy);
00425
00426 width = minify(width);
00427 height = minify(height);
00428 depth = minify(depth);
00429 nblocksx = pf_get_nblocksx(&pt->block, width);
00430 nblocksy = pf_get_nblocksy(&pt->block, height);
00431 }
00432
00433
00434
00435 depth = pt->depth[0];
00436 for (level = 0; level <= pt->last_level; level++) {
00437 unsigned i;
00438 for (i = 0; i < depth; i++)
00439 i915_miptree_set_image_offset(tex, level, i,
00440 0, i * stack_nblocksy);
00441
00442 depth = minify(depth);
00443 }
00444
00445
00446
00447
00448
00449
00450 tex->total_nblocksy = stack_nblocksy * pt->depth[0];
00451 break;
00452 }
00453
00454 default:{
00455 unsigned width = pt->width[0];
00456 unsigned height = pt->height[0];
00457 unsigned nblocksx = pt->nblocksx[0];
00458 unsigned nblocksy = pt->nblocksy[0];
00459
00460 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
00461 tex->total_nblocksy = 0;
00462
00463 for (level = 0; level <= pt->last_level; level++) {
00464 i915_miptree_set_level_info(tex, level, 1,
00465 width, height, 1);
00466 i915_miptree_set_image_offset(tex, level, 0,
00467 0, tex->total_nblocksy);
00468
00469 nblocksy = round_up(MAX2(2, nblocksy), 2);
00470
00471 tex->total_nblocksy += nblocksy;
00472
00473 width = minify(width);
00474 height = minify(height);
00475 nblocksx = pf_get_nblocksx(&pt->block, width);
00476 nblocksy = pf_get_nblocksy(&pt->block, height);
00477 }
00478 break;
00479 }
00480 }
00481
00482
00483
00484
00485
00486
00487 return TRUE;
00488 }
00489
00490
00491 static boolean
00492 i945_miptree_layout(struct i915_texture * tex)
00493 {
00494 struct pipe_texture *pt = &tex->base;
00495 unsigned level;
00496
00497 switch (pt->target) {
00498 case PIPE_TEXTURE_CUBE:
00499 i945_miptree_layout_cube(tex);
00500 break;
00501 case PIPE_TEXTURE_3D:{
00502 unsigned width = pt->width[0];
00503 unsigned height = pt->height[0];
00504 unsigned depth = pt->depth[0];
00505 unsigned nblocksx = pt->nblocksx[0];
00506 unsigned nblocksy = pt->nblocksy[0];
00507 unsigned pack_x_pitch, pack_x_nr;
00508 unsigned pack_y_pitch;
00509
00510 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
00511 tex->total_nblocksy = 0;
00512
00513 pack_y_pitch = MAX2(pt->nblocksy[0], 2);
00514 pack_x_pitch = tex->stride / pt->block.size;
00515 pack_x_nr = 1;
00516
00517 for (level = 0; level <= pt->last_level; level++) {
00518 unsigned nr_images = pt->target == PIPE_TEXTURE_3D ? depth : 6;
00519 int x = 0;
00520 int y = 0;
00521 unsigned q, j;
00522
00523 i915_miptree_set_level_info(tex, level, nr_images,
00524 width, height, depth);
00525
00526 for (q = 0; q < nr_images;) {
00527 for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) {
00528 i915_miptree_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
00529 x += pack_x_pitch;
00530 }
00531
00532 x = 0;
00533 y += pack_y_pitch;
00534 }
00535
00536
00537 tex->total_nblocksy += y;
00538
00539 if (pack_x_pitch > 4) {
00540 pack_x_pitch >>= 1;
00541 pack_x_nr <<= 1;
00542 assert(pack_x_pitch * pack_x_nr * pt->block.size <= tex->stride);
00543 }
00544
00545 if (pack_y_pitch > 2) {
00546 pack_y_pitch >>= 1;
00547 }
00548
00549 width = minify(width);
00550 height = minify(height);
00551 depth = minify(depth);
00552 nblocksx = pf_get_nblocksx(&pt->block, width);
00553 nblocksy = pf_get_nblocksy(&pt->block, height);
00554 }
00555 break;
00556 }
00557
00558 case PIPE_TEXTURE_1D:
00559 case PIPE_TEXTURE_2D:
00560
00561 i945_miptree_layout_2d(tex);
00562 break;
00563 default:
00564 assert(0);
00565 return FALSE;
00566 }
00567
00568
00569
00570
00571
00572
00573
00574 return TRUE;
00575 }
00576
00577
00578 static struct pipe_texture *
00579 i915_texture_create(struct pipe_screen *screen,
00580 const struct pipe_texture *templat)
00581 {
00582 struct i915_screen *i915screen = i915_screen(screen);
00583 struct pipe_winsys *ws = screen->winsys;
00584 struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
00585 size_t tex_size;
00586
00587 if (!tex)
00588 return NULL;
00589
00590 tex->base = *templat;
00591 tex->base.refcount = 1;
00592 tex->base.screen = screen;
00593
00594 tex->base.nblocksx[0] = pf_get_nblocksx(&tex->base.block, tex->base.width[0]);
00595 tex->base.nblocksy[0] = pf_get_nblocksy(&tex->base.block, tex->base.height[0]);
00596
00597 if (i915screen->is_i945) {
00598 if (!i945_miptree_layout(tex))
00599 goto fail;
00600 } else {
00601 if (!i915_miptree_layout(tex))
00602 goto fail;
00603 }
00604
00605 tex_size = tex->stride * tex->total_nblocksy;
00606
00607 tex->buffer = ws->buffer_create(ws, 64,
00608 PIPE_BUFFER_USAGE_PIXEL,
00609 tex_size);
00610
00611 if (!tex->buffer)
00612 goto fail;
00613
00614 #if 0
00615 void *ptr = ws->buffer_map(ws, tex->buffer,
00616 PIPE_BUFFER_USAGE_CPU_WRITE);
00617 memset(ptr, 0x80, tex_size);
00618 ws->buffer_unmap(ws, tex->buffer);
00619 #endif
00620
00621 return &tex->base;
00622
00623 fail:
00624 FREE(tex);
00625 return NULL;
00626 }
00627
00628
00629 static void
00630 i915_texture_release(struct pipe_screen *screen,
00631 struct pipe_texture **pt)
00632 {
00633 if (!*pt)
00634 return;
00635
00636
00637
00638
00639
00640 if (--(*pt)->refcount <= 0) {
00641 struct i915_texture *tex = (struct i915_texture *)*pt;
00642 uint i;
00643
00644
00645
00646
00647
00648 pipe_buffer_reference(screen, &tex->buffer, NULL);
00649
00650 for (i = 0; i < PIPE_MAX_TEXTURE_LEVELS; i++)
00651 if (tex->image_offset[i])
00652 FREE(tex->image_offset[i]);
00653
00654 FREE(tex);
00655 }
00656 *pt = NULL;
00657 }
00658
00659 static struct pipe_surface *
00660 i915_get_tex_surface(struct pipe_screen *screen,
00661 struct pipe_texture *pt,
00662 unsigned face, unsigned level, unsigned zslice,
00663 unsigned flags)
00664 {
00665 struct i915_texture *tex = (struct i915_texture *)pt;
00666 struct pipe_winsys *ws = screen->winsys;
00667 struct pipe_surface *ps;
00668 unsigned offset;
00669
00670 if (pt->target == PIPE_TEXTURE_CUBE) {
00671 offset = tex->image_offset[level][face];
00672 }
00673 else if (pt->target == PIPE_TEXTURE_3D) {
00674 offset = tex->image_offset[level][zslice];
00675 }
00676 else {
00677 offset = tex->image_offset[level][0];
00678 assert(face == 0);
00679 assert(zslice == 0);
00680 }
00681
00682 ps = CALLOC_STRUCT(pipe_surface);
00683 if (ps) {
00684 ps->refcount = 1;
00685 ps->winsys = ws;
00686 pipe_texture_reference(&ps->texture, pt);
00687 pipe_buffer_reference(screen, &ps->buffer, tex->buffer);
00688 ps->format = pt->format;
00689 ps->width = pt->width[level];
00690 ps->height = pt->height[level];
00691 ps->block = pt->block;
00692 ps->nblocksx = pt->nblocksx[level];
00693 ps->nblocksy = pt->nblocksy[level];
00694 ps->stride = tex->stride;
00695 ps->offset = offset;
00696 ps->usage = flags;
00697 ps->status = PIPE_SURFACE_STATUS_DEFINED;
00698 }
00699 return ps;
00700 }
00701
00702 static struct pipe_texture *
00703 i915_texture_blanket(struct pipe_screen * screen,
00704 const struct pipe_texture *base,
00705 const unsigned *stride,
00706 struct pipe_buffer *buffer)
00707 {
00708 struct i915_texture *tex;
00709 assert(screen);
00710
00711
00712 if (base->target != PIPE_TEXTURE_2D ||
00713 base->last_level != 0 ||
00714 base->depth[0] != 1) {
00715 return NULL;
00716 }
00717
00718 tex = CALLOC_STRUCT(i915_texture);
00719 if (!tex)
00720 return NULL;
00721
00722 tex->base = *base;
00723 tex->base.refcount = 1;
00724 tex->base.screen = screen;
00725
00726 tex->stride = stride[0];
00727
00728 i915_miptree_set_level_info(tex, 0, 1, base->width[0], base->height[0], 1);
00729 i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
00730
00731 pipe_buffer_reference(screen, &tex->buffer, buffer);
00732
00733 return &tex->base;
00734 }
00735
00736 void
00737 i915_init_texture_functions(struct i915_context *i915)
00738 {
00739
00740 }
00741
00742 static void
00743 i915_tex_surface_release(struct pipe_screen *screen,
00744 struct pipe_surface **surface)
00745 {
00746 struct pipe_surface *surf = *surface;
00747
00748 if (--surf->refcount == 0) {
00749
00750
00751
00752
00753 if (surf->status == PIPE_SURFACE_STATUS_CLEAR) {
00754 debug_printf("XXX destroying a surface with pending clears...\n");
00755 assert(0);
00756 }
00757
00758 pipe_texture_reference(&surf->texture, NULL);
00759 pipe_buffer_reference(screen, &surf->buffer, NULL);
00760 FREE(surf);
00761 }
00762
00763 *surface = NULL;
00764 }
00765
00766 void
00767 i915_init_screen_texture_functions(struct pipe_screen *screen)
00768 {
00769 screen->texture_create = i915_texture_create;
00770 screen->texture_release = i915_texture_release;
00771 screen->get_tex_surface = i915_get_tex_surface;
00772 screen->texture_blanket = i915_texture_blanket;
00773 screen->tex_surface_release = i915_tex_surface_release;
00774 }