1 /*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 *
24 */
25
26 #include "util/format/u_format.h"
27 #include "util/u_inlines.h"
28 #include "util/u_surface.h"
29
30 #include "nv_m2mf.xml.h"
31 #include "nv_object.xml.h"
32 #include "nv30/nv30_screen.h"
33 #include "nv30/nv30_context.h"
34 #include "nv30/nv30_resource.h"
35 #include "nv30/nv30_transfer.h"
36
37 static inline unsigned
layer_offset(struct pipe_resource * pt,unsigned level,unsigned layer)38 layer_offset(struct pipe_resource *pt, unsigned level, unsigned layer)
39 {
40 struct nv30_miptree *mt = nv30_miptree(pt);
41 struct nv30_miptree_level *lvl = &mt->level[level];
42
43 if (pt->target == PIPE_TEXTURE_CUBE)
44 return (layer * mt->layer_size) + lvl->offset;
45
46 return lvl->offset + (layer * lvl->zslice_size);
47 }
48
49 bool
nv30_miptree_get_handle(struct pipe_screen * pscreen,struct pipe_context * context,struct pipe_resource * pt,struct winsys_handle * handle,unsigned usage)50 nv30_miptree_get_handle(struct pipe_screen *pscreen,
51 struct pipe_context *context,
52 struct pipe_resource *pt,
53 struct winsys_handle *handle,
54 unsigned usage)
55 {
56 if (pt->target == PIPE_BUFFER)
57 return false;
58
59 struct nv30_miptree *mt = nv30_miptree(pt);
60 unsigned stride;
61
62 if (!mt || !mt->base.bo)
63 return false;
64
65 stride = mt->level[0].pitch;
66
67 return nouveau_screen_bo_get_handle(pscreen, mt->base.bo, stride, handle);
68 }
69
70 void
nv30_miptree_destroy(struct pipe_screen * pscreen,struct pipe_resource * pt)71 nv30_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)
72 {
73 struct nv30_miptree *mt = nv30_miptree(pt);
74
75 nouveau_bo_ref(NULL, &mt->base.bo);
76 FREE(mt);
77 }
78
79 struct nv30_transfer {
80 struct pipe_transfer base;
81 struct nv30_rect img;
82 struct nv30_rect tmp;
83 unsigned nblocksx;
84 unsigned nblocksy;
85 };
86
87 static inline struct nv30_transfer *
nv30_transfer(struct pipe_transfer * ptx)88 nv30_transfer(struct pipe_transfer *ptx)
89 {
90 return (struct nv30_transfer *)ptx;
91 }
92
93 static inline void
define_rect(struct pipe_resource * pt,unsigned level,unsigned z,unsigned x,unsigned y,unsigned w,unsigned h,struct nv30_rect * rect)94 define_rect(struct pipe_resource *pt, unsigned level, unsigned z,
95 unsigned x, unsigned y, unsigned w, unsigned h,
96 struct nv30_rect *rect)
97 {
98 struct nv30_miptree *mt = nv30_miptree(pt);
99 struct nv30_miptree_level *lvl = &mt->level[level];
100
101 rect->w = u_minify(pt->width0, level) << mt->ms_x;
102 rect->w = util_format_get_nblocksx(pt->format, rect->w);
103 rect->h = u_minify(pt->height0, level) << mt->ms_y;
104 rect->h = util_format_get_nblocksy(pt->format, rect->h);
105 rect->d = 1;
106 rect->z = 0;
107 if (mt->swizzled) {
108 if (pt->target == PIPE_TEXTURE_3D) {
109 rect->d = u_minify(pt->depth0, level);
110 rect->z = z; z = 0;
111 }
112 rect->pitch = 0;
113 } else {
114 rect->pitch = lvl->pitch;
115 }
116
117 rect->bo = mt->base.bo;
118 rect->domain = NOUVEAU_BO_VRAM;
119 rect->offset = layer_offset(pt, level, z);
120 rect->cpp = util_format_get_blocksize(pt->format);
121
122 rect->x0 = util_format_get_nblocksx(pt->format, x) << mt->ms_x;
123 rect->y0 = util_format_get_nblocksy(pt->format, y) << mt->ms_y;
124 rect->x1 = rect->x0 + (util_format_get_nblocksx(pt->format, w) << mt->ms_x);
125 rect->y1 = rect->y0 + (util_format_get_nblocksy(pt->format, h) << mt->ms_y);
126
127 /* XXX There's some indication that swizzled formats > 4 bytes are treated
128 * differently. However that only applies to RGBA16_FLOAT, RGBA32_FLOAT,
129 * and the DXT* formats. The former aren't properly supported yet, and the
130 * latter avoid swizzled layouts.
131
132 if (mt->swizzled && rect->cpp > 4) {
133 unsigned scale = rect->cpp / 4;
134 rect->w *= scale;
135 rect->x0 *= scale;
136 rect->x1 *= scale;
137 rect->cpp = 4;
138 }
139 */
140 }
141
142 void
nv30_resource_copy_region(struct pipe_context * pipe,struct pipe_resource * dstres,unsigned dst_level,unsigned dstx,unsigned dsty,unsigned dstz,struct pipe_resource * srcres,unsigned src_level,const struct pipe_box * src_box)143 nv30_resource_copy_region(struct pipe_context *pipe,
144 struct pipe_resource *dstres, unsigned dst_level,
145 unsigned dstx, unsigned dsty, unsigned dstz,
146 struct pipe_resource *srcres, unsigned src_level,
147 const struct pipe_box *src_box)
148 {
149 struct nv30_context *nv30 = nv30_context(pipe);
150 struct nv30_rect src, dst;
151
152 if (dstres->target == PIPE_BUFFER && srcres->target == PIPE_BUFFER) {
153 nouveau_copy_buffer(&nv30->base,
154 nv04_resource(dstres), dstx,
155 nv04_resource(srcres), src_box->x, src_box->width);
156 return;
157 }
158
159 define_rect(srcres, src_level, src_box->z, src_box->x, src_box->y,
160 src_box->width, src_box->height, &src);
161 define_rect(dstres, dst_level, dstz, dstx, dsty,
162 src_box->width, src_box->height, &dst);
163
164 nv30_transfer_rect(nv30, NEAREST, &src, &dst);
165 }
166
167 static void
nv30_resource_resolve(struct nv30_context * nv30,const struct pipe_blit_info * info)168 nv30_resource_resolve(struct nv30_context *nv30,
169 const struct pipe_blit_info *info)
170 {
171 struct nv30_miptree *src_mt = nv30_miptree(info->src.resource);
172 struct nv30_rect src, dst;
173 unsigned x, x0, x1, y, y1, w, h;
174
175 define_rect(info->src.resource, 0, info->src.box.z, info->src.box.x,
176 info->src.box.y, info->src.box.width, info->src.box.height, &src);
177 define_rect(info->dst.resource, 0, info->dst.box.z, info->dst.box.x,
178 info->dst.box.y, info->dst.box.width, info->dst.box.height, &dst);
179
180 x0 = src.x0;
181 x1 = src.x1;
182 y1 = src.y1;
183
184 /* On nv3x we must use sifm which is restricted to 1024x1024 tiles */
185 for (y = src.y0; y < y1; y += h) {
186 h = y1 - y;
187 if (h > 1024)
188 h = 1024;
189
190 src.y0 = 0;
191 src.y1 = h;
192 src.h = h;
193
194 dst.y1 = dst.y0 + (h >> src_mt->ms_y);
195 dst.h = h >> src_mt->ms_y;
196
197 for (x = x0; x < x1; x += w) {
198 w = x1 - x;
199 if (w > 1024)
200 w = 1024;
201
202 src.offset = y * src.pitch + x * src.cpp;
203 src.x0 = 0;
204 src.x1 = w;
205 src.w = w;
206
207 dst.offset = (y >> src_mt->ms_y) * dst.pitch +
208 (x >> src_mt->ms_x) * dst.cpp;
209 dst.x1 = dst.x0 + (w >> src_mt->ms_x);
210 dst.w = w >> src_mt->ms_x;
211
212 nv30_transfer_rect(nv30, BILINEAR, &src, &dst);
213 }
214 }
215 }
216
217 void
nv30_blit(struct pipe_context * pipe,const struct pipe_blit_info * blit_info)218 nv30_blit(struct pipe_context *pipe,
219 const struct pipe_blit_info *blit_info)
220 {
221 struct nv30_context *nv30 = nv30_context(pipe);
222 struct pipe_blit_info info = *blit_info;
223
224 if (info.src.resource->nr_samples > 1 &&
225 info.dst.resource->nr_samples <= 1 &&
226 !util_format_is_depth_or_stencil(info.src.resource->format) &&
227 !util_format_is_pure_integer(info.src.resource->format)) {
228 nv30_resource_resolve(nv30, blit_info);
229 return;
230 }
231
232 if (util_try_blit_via_copy_region(pipe, &info)) {
233 return; /* done */
234 }
235
236 if (info.mask & PIPE_MASK_S) {
237 debug_printf("nv30: cannot blit stencil, skipping\n");
238 info.mask &= ~PIPE_MASK_S;
239 }
240
241 if (!util_blitter_is_blit_supported(nv30->blitter, &info)) {
242 debug_printf("nv30: blit unsupported %s -> %s\n",
243 util_format_short_name(info.src.resource->format),
244 util_format_short_name(info.dst.resource->format));
245 return;
246 }
247
248 /* XXX turn off occlusion queries */
249
250 util_blitter_save_vertex_buffer_slot(nv30->blitter, nv30->vtxbuf);
251 util_blitter_save_vertex_elements(nv30->blitter, nv30->vertex);
252 util_blitter_save_vertex_shader(nv30->blitter, nv30->vertprog.program);
253 util_blitter_save_rasterizer(nv30->blitter, nv30->rast);
254 util_blitter_save_viewport(nv30->blitter, &nv30->viewport);
255 util_blitter_save_scissor(nv30->blitter, &nv30->scissor);
256 util_blitter_save_fragment_shader(nv30->blitter, nv30->fragprog.program);
257 util_blitter_save_blend(nv30->blitter, nv30->blend);
258 util_blitter_save_depth_stencil_alpha(nv30->blitter,
259 nv30->zsa);
260 util_blitter_save_stencil_ref(nv30->blitter, &nv30->stencil_ref);
261 util_blitter_save_sample_mask(nv30->blitter, nv30->sample_mask);
262 util_blitter_save_framebuffer(nv30->blitter, &nv30->framebuffer);
263 util_blitter_save_fragment_sampler_states(nv30->blitter,
264 nv30->fragprog.num_samplers,
265 (void**)nv30->fragprog.samplers);
266 util_blitter_save_fragment_sampler_views(nv30->blitter,
267 nv30->fragprog.num_textures, nv30->fragprog.textures);
268 util_blitter_save_render_condition(nv30->blitter, nv30->render_cond_query,
269 nv30->render_cond_cond, nv30->render_cond_mode);
270 util_blitter_blit(nv30->blitter, &info);
271 }
272
273 void
nv30_flush_resource(struct pipe_context * pipe,struct pipe_resource * resource)274 nv30_flush_resource(struct pipe_context *pipe,
275 struct pipe_resource *resource)
276 {
277 }
278
279 void *
nv30_miptree_transfer_map(struct pipe_context * pipe,struct pipe_resource * pt,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** ptransfer)280 nv30_miptree_transfer_map(struct pipe_context *pipe, struct pipe_resource *pt,
281 unsigned level, unsigned usage,
282 const struct pipe_box *box,
283 struct pipe_transfer **ptransfer)
284 {
285 struct nv30_context *nv30 = nv30_context(pipe);
286 struct nouveau_device *dev = nv30->screen->base.device;
287 struct nv30_miptree *mt = nv30_miptree(pt);
288 struct nv30_transfer *tx;
289 unsigned access = 0;
290 int ret;
291
292 tx = CALLOC_STRUCT(nv30_transfer);
293 if (!tx)
294 return NULL;
295 pipe_resource_reference(&tx->base.resource, pt);
296 tx->base.level = level;
297 tx->base.usage = usage;
298 tx->base.box = *box;
299 tx->base.stride = align(util_format_get_nblocksx(pt->format, box->width) *
300 util_format_get_blocksize(pt->format), 64);
301 tx->base.layer_stride = util_format_get_nblocksy(pt->format, box->height) *
302 tx->base.stride;
303
304 tx->nblocksx = util_format_get_nblocksx(pt->format, box->width);
305 tx->nblocksy = util_format_get_nblocksy(pt->format, box->height);
306
307 define_rect(pt, level, box->z, box->x, box->y,
308 box->width, box->height, &tx->img);
309
310 ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
311 tx->base.layer_stride * tx->base.box.depth, NULL,
312 &tx->tmp.bo);
313 if (ret) {
314 pipe_resource_reference(&tx->base.resource, NULL);
315 FREE(tx);
316 return NULL;
317 }
318
319 tx->tmp.domain = NOUVEAU_BO_GART;
320 tx->tmp.offset = 0;
321 tx->tmp.pitch = tx->base.stride;
322 tx->tmp.cpp = tx->img.cpp;
323 tx->tmp.w = tx->nblocksx;
324 tx->tmp.h = tx->nblocksy;
325 tx->tmp.d = 1;
326 tx->tmp.x0 = 0;
327 tx->tmp.y0 = 0;
328 tx->tmp.x1 = tx->tmp.w;
329 tx->tmp.y1 = tx->tmp.h;
330 tx->tmp.z = 0;
331
332 if (usage & PIPE_MAP_READ) {
333 bool is_3d = mt->base.base.target == PIPE_TEXTURE_3D;
334 unsigned offset = tx->img.offset;
335 unsigned z = tx->img.z;
336 unsigned i;
337 for (i = 0; i < box->depth; ++i) {
338 nv30_transfer_rect(nv30, NEAREST, &tx->img, &tx->tmp);
339 if (is_3d && mt->swizzled)
340 tx->img.z++;
341 else if (is_3d)
342 tx->img.offset += mt->level[level].zslice_size;
343 else
344 tx->img.offset += mt->layer_size;
345 tx->tmp.offset += tx->base.layer_stride;
346 }
347 tx->img.z = z;
348 tx->img.offset = offset;
349 tx->tmp.offset = 0;
350 }
351
352 if (tx->tmp.bo->map) {
353 *ptransfer = &tx->base;
354 return tx->tmp.bo->map;
355 }
356
357 if (usage & PIPE_MAP_READ)
358 access |= NOUVEAU_BO_RD;
359 if (usage & PIPE_MAP_WRITE)
360 access |= NOUVEAU_BO_WR;
361
362 ret = nouveau_bo_map(tx->tmp.bo, access, nv30->base.client);
363 if (ret) {
364 pipe_resource_reference(&tx->base.resource, NULL);
365 FREE(tx);
366 return NULL;
367 }
368
369 *ptransfer = &tx->base;
370 return tx->tmp.bo->map;
371 }
372
373 void
nv30_miptree_transfer_unmap(struct pipe_context * pipe,struct pipe_transfer * ptx)374 nv30_miptree_transfer_unmap(struct pipe_context *pipe,
375 struct pipe_transfer *ptx)
376 {
377 struct nv30_context *nv30 = nv30_context(pipe);
378 struct nv30_transfer *tx = nv30_transfer(ptx);
379 struct nv30_miptree *mt = nv30_miptree(tx->base.resource);
380 unsigned i;
381
382 if (ptx->usage & PIPE_MAP_WRITE) {
383 bool is_3d = mt->base.base.target == PIPE_TEXTURE_3D;
384 for (i = 0; i < tx->base.box.depth; ++i) {
385 nv30_transfer_rect(nv30, NEAREST, &tx->tmp, &tx->img);
386 if (is_3d && mt->swizzled)
387 tx->img.z++;
388 else if (is_3d)
389 tx->img.offset += mt->level[tx->base.level].zslice_size;
390 else
391 tx->img.offset += mt->layer_size;
392 tx->tmp.offset += tx->base.layer_stride;
393 }
394
395 /* Allow the copies above to finish executing before freeing the source */
396 nouveau_fence_work(nv30->screen->base.fence.current,
397 nouveau_fence_unref_bo, tx->tmp.bo);
398 } else {
399 nouveau_bo_ref(NULL, &tx->tmp.bo);
400 }
401 pipe_resource_reference(&ptx->resource, NULL);
402 FREE(tx);
403 }
404
405 struct pipe_resource *
nv30_miptree_create(struct pipe_screen * pscreen,const struct pipe_resource * tmpl)406 nv30_miptree_create(struct pipe_screen *pscreen,
407 const struct pipe_resource *tmpl)
408 {
409 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
410 struct nv30_miptree *mt = CALLOC_STRUCT(nv30_miptree);
411 struct pipe_resource *pt = &mt->base.base;
412 unsigned blocksz, size;
413 unsigned w, h, d, l;
414 int ret;
415
416 switch (tmpl->nr_samples) {
417 case 4:
418 mt->ms_mode = 0x00004000;
419 mt->ms_x = 1;
420 mt->ms_y = 1;
421 break;
422 case 2:
423 mt->ms_mode = 0x00003000;
424 mt->ms_x = 1;
425 mt->ms_y = 0;
426 break;
427 default:
428 mt->ms_mode = 0x00000000;
429 mt->ms_x = 0;
430 mt->ms_y = 0;
431 break;
432 }
433
434 *pt = *tmpl;
435 pipe_reference_init(&pt->reference, 1);
436 pt->screen = pscreen;
437
438 w = pt->width0 << mt->ms_x;
439 h = pt->height0 << mt->ms_y;
440 d = (pt->target == PIPE_TEXTURE_3D) ? pt->depth0 : 1;
441 blocksz = util_format_get_blocksize(pt->format);
442
443 if ((pt->target == PIPE_TEXTURE_RECT) ||
444 (pt->bind & PIPE_BIND_SCANOUT) ||
445 !util_is_power_of_two_or_zero(pt->width0) ||
446 !util_is_power_of_two_or_zero(pt->height0) ||
447 !util_is_power_of_two_or_zero(pt->depth0) ||
448 mt->ms_mode) {
449 mt->uniform_pitch = util_format_get_nblocksx(pt->format, w) * blocksz;
450 mt->uniform_pitch = align(mt->uniform_pitch, 64);
451 if (pt->bind & PIPE_BIND_SCANOUT) {
452 struct nv30_screen *screen = nv30_screen(pscreen);
453 int pitch_align = MAX2(
454 screen->eng3d->oclass >= NV40_3D_CLASS ? 1024 : 256,
455 /* round_down_pow2(mt->uniform_pitch / 4) */
456 1 << (util_last_bit(mt->uniform_pitch / 4) - 1));
457 mt->uniform_pitch = align(mt->uniform_pitch, pitch_align);
458 }
459 }
460
461 if (util_format_is_compressed(pt->format)) {
462 // Compressed (DXT) formats are packed tightly. We don't mark them as
463 // swizzled, since their layout is largely linear. However we do end up
464 // omitting the LINEAR flag when texturing them, as the levels are not
465 // uniformly sized (for POT sizes).
466 } else if (!mt->uniform_pitch) {
467 mt->swizzled = true;
468 }
469
470 size = 0;
471 for (l = 0; l <= pt->last_level; l++) {
472 struct nv30_miptree_level *lvl = &mt->level[l];
473 unsigned nbx = util_format_get_nblocksx(pt->format, w);
474 unsigned nby = util_format_get_nblocksy(pt->format, h);
475
476 lvl->offset = size;
477 lvl->pitch = mt->uniform_pitch;
478 if (!lvl->pitch)
479 lvl->pitch = nbx * blocksz;
480
481 lvl->zslice_size = lvl->pitch * nby;
482 size += lvl->zslice_size * d;
483
484 w = u_minify(w, 1);
485 h = u_minify(h, 1);
486 d = u_minify(d, 1);
487 }
488
489 mt->layer_size = size;
490 if (pt->target == PIPE_TEXTURE_CUBE) {
491 if (!mt->uniform_pitch)
492 mt->layer_size = align(mt->layer_size, 128);
493 size = mt->layer_size * 6;
494 }
495
496 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 256, size, NULL, &mt->base.bo);
497 if (ret) {
498 FREE(mt);
499 return NULL;
500 }
501
502 mt->base.domain = NOUVEAU_BO_VRAM;
503 return &mt->base.base;
504 }
505
506 struct pipe_resource *
nv30_miptree_from_handle(struct pipe_screen * pscreen,const struct pipe_resource * tmpl,struct winsys_handle * handle)507 nv30_miptree_from_handle(struct pipe_screen *pscreen,
508 const struct pipe_resource *tmpl,
509 struct winsys_handle *handle)
510 {
511 struct nv30_miptree *mt;
512 unsigned stride;
513
514 /* only supports 2D, non-mipmapped textures for the moment */
515 if ((tmpl->target != PIPE_TEXTURE_2D &&
516 tmpl->target != PIPE_TEXTURE_RECT) ||
517 tmpl->last_level != 0 ||
518 tmpl->depth0 != 1 ||
519 tmpl->array_size > 1)
520 return NULL;
521
522 mt = CALLOC_STRUCT(nv30_miptree);
523 if (!mt)
524 return NULL;
525
526 mt->base.bo = nouveau_screen_bo_from_handle(pscreen, handle, &stride);
527 if (mt->base.bo == NULL) {
528 FREE(mt);
529 return NULL;
530 }
531
532 mt->base.base = *tmpl;
533 pipe_reference_init(&mt->base.base.reference, 1);
534 mt->base.base.screen = pscreen;
535 mt->uniform_pitch = stride;
536 mt->level[0].pitch = mt->uniform_pitch;
537 mt->level[0].offset = 0;
538
539 /* no need to adjust bo reference count */
540 return &mt->base.base;
541 }
542
543 struct pipe_surface *
nv30_miptree_surface_new(struct pipe_context * pipe,struct pipe_resource * pt,const struct pipe_surface * tmpl)544 nv30_miptree_surface_new(struct pipe_context *pipe,
545 struct pipe_resource *pt,
546 const struct pipe_surface *tmpl)
547 {
548 struct nv30_miptree *mt = nv30_miptree(pt); /* guaranteed */
549 struct nv30_surface *ns;
550 struct pipe_surface *ps;
551 struct nv30_miptree_level *lvl = &mt->level[tmpl->u.tex.level];
552
553 ns = CALLOC_STRUCT(nv30_surface);
554 if (!ns)
555 return NULL;
556 ps = &ns->base;
557
558 pipe_reference_init(&ps->reference, 1);
559 pipe_resource_reference(&ps->texture, pt);
560 ps->context = pipe;
561 ps->format = tmpl->format;
562 ps->u.tex.level = tmpl->u.tex.level;
563 ps->u.tex.first_layer = tmpl->u.tex.first_layer;
564 ps->u.tex.last_layer = tmpl->u.tex.last_layer;
565
566 ns->width = u_minify(pt->width0, ps->u.tex.level);
567 ns->height = u_minify(pt->height0, ps->u.tex.level);
568 ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
569 ns->offset = layer_offset(pt, ps->u.tex.level, ps->u.tex.first_layer);
570 if (mt->swizzled)
571 ns->pitch = 4096; /* random, just something the hw won't reject.. */
572 else
573 ns->pitch = lvl->pitch;
574
575 /* comment says there are going to be removed, but they're used by the st */
576 ps->width = ns->width;
577 ps->height = ns->height;
578 return ps;
579 }
580
581 void
nv30_miptree_surface_del(struct pipe_context * pipe,struct pipe_surface * ps)582 nv30_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps)
583 {
584 struct nv30_surface *ns = nv30_surface(ps);
585
586 pipe_resource_reference(&ps->texture, NULL);
587 FREE(ns);
588 }
589