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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  * Authors: Ben Skeggs
23  *
24  */
25 
26 #include "util/u_format.h"
27 #include "util/u_inlines.h"
28 #include "util/u_surface.h"
29 
30 #include "nouveau/nv_m2mf.xml.h"
31 #include "nv30_screen.h"
32 #include "nv30_context.h"
33 #include "nv30_resource.h"
34 #include "nv30_transfer.h"
35 
36 static INLINE unsigned
layer_offset(struct pipe_resource * pt,unsigned level,unsigned layer)37 layer_offset(struct pipe_resource *pt, unsigned level, unsigned layer)
38 {
39    struct nv30_miptree *mt = nv30_miptree(pt);
40    struct nv30_miptree_level *lvl = &mt->level[level];
41 
42    if (pt->target == PIPE_TEXTURE_CUBE)
43       return (layer * mt->layer_size) + lvl->offset;
44 
45    return lvl->offset + (layer * lvl->zslice_size);
46 }
47 
48 static boolean
nv30_miptree_get_handle(struct pipe_screen * pscreen,struct pipe_resource * pt,struct winsys_handle * handle)49 nv30_miptree_get_handle(struct pipe_screen *pscreen,
50                         struct pipe_resource *pt,
51                         struct winsys_handle *handle)
52 {
53    struct nv30_miptree *mt = nv30_miptree(pt);
54    unsigned stride;
55 
56    if (!mt || !mt->base.bo)
57       return FALSE;
58 
59    stride = mt->level[0].pitch;
60 
61    return nouveau_screen_bo_get_handle(pscreen, mt->base.bo, stride, handle);
62 }
63 
64 static void
nv30_miptree_destroy(struct pipe_screen * pscreen,struct pipe_resource * pt)65 nv30_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)
66 {
67    struct nv30_miptree *mt = nv30_miptree(pt);
68 
69    nouveau_bo_ref(NULL, &mt->base.bo);
70    FREE(mt);
71 }
72 
73 struct nv30_transfer {
74    struct pipe_transfer base;
75    struct nv30_rect img;
76    struct nv30_rect tmp;
77    unsigned nblocksx;
78    unsigned nblocksy;
79 };
80 
81 static INLINE struct nv30_transfer *
nv30_transfer(struct pipe_transfer * ptx)82 nv30_transfer(struct pipe_transfer *ptx)
83 {
84    return (struct nv30_transfer *)ptx;
85 }
86 
87 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)88 define_rect(struct pipe_resource *pt, unsigned level, unsigned z,
89             unsigned x, unsigned y, unsigned w, unsigned h,
90             struct nv30_rect *rect)
91 {
92    struct nv30_miptree *mt = nv30_miptree(pt);
93    struct nv30_miptree_level *lvl = &mt->level[level];
94 
95    rect->w = u_minify(pt->width0, level) << mt->ms_x;
96    rect->w = util_format_get_nblocksx(pt->format, rect->w);
97    rect->h = u_minify(pt->height0, level) << mt->ms_y;
98    rect->h = util_format_get_nblocksy(pt->format, rect->h);
99    rect->d = 1;
100    rect->z = 0;
101    if (mt->swizzled) {
102       if (pt->target == PIPE_TEXTURE_3D) {
103          rect->d = u_minify(pt->depth0, level);
104          rect->z = z; z = 0;
105       }
106       rect->pitch = 0;
107    } else {
108       rect->pitch = lvl->pitch;
109    }
110 
111    rect->bo     = mt->base.bo;
112    rect->domain = NOUVEAU_BO_VRAM;
113    rect->offset = layer_offset(pt, level, z);
114    rect->cpp    = util_format_get_blocksize(pt->format);
115 
116    rect->x0     = util_format_get_nblocksx(pt->format, x) << mt->ms_x;
117    rect->y0     = util_format_get_nblocksy(pt->format, y) << mt->ms_y;
118    rect->x1     = rect->x0 + (w << mt->ms_x);
119    rect->y1     = rect->y0 + (h << mt->ms_y);
120 }
121 
122 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)123 nv30_resource_copy_region(struct pipe_context *pipe,
124                           struct pipe_resource *dstres, unsigned dst_level,
125                           unsigned dstx, unsigned dsty, unsigned dstz,
126                           struct pipe_resource *srcres, unsigned src_level,
127                           const struct pipe_box *src_box)
128 {
129    struct nv30_context *nv30 = nv30_context(pipe);
130    struct nv30_rect src, dst;
131 
132    if (dstres->target == PIPE_BUFFER && srcres->target == PIPE_BUFFER) {
133       util_resource_copy_region(pipe, dstres, dst_level, dstx, dsty, dstz,
134                                       srcres, src_level, src_box);
135       return;
136    }
137 
138    define_rect(srcres, src_level, src_box->z, src_box->x, src_box->y,
139                        src_box->width, src_box->height, &src);
140    define_rect(dstres, dst_level, dstz, dstx, dsty,
141                        src_box->width, src_box->height, &dst);
142 
143    nv30_transfer_rect(nv30, NEAREST, &src, &dst);
144 }
145 
146 void
nv30_resource_resolve(struct pipe_context * pipe,const struct pipe_resolve_info * info)147 nv30_resource_resolve(struct pipe_context *pipe,
148                       const struct pipe_resolve_info *info)
149 {
150    struct nv30_context *nv30 = nv30_context(pipe);
151    struct nv30_rect src, dst;
152 
153    define_rect(info->src.res, 0, 0, info->src.x0, info->src.y0,
154                info->src.x1 - info->src.x0, info->src.y1 - info->src.y0, &src);
155    define_rect(info->dst.res, info->dst.level, 0, info->dst.x0, info->dst.y0,
156                info->dst.x1 - info->dst.x0, info->dst.y1 - info->dst.y0, &dst);
157 
158    nv30_transfer_rect(nv30, BILINEAR, &src, &dst);
159 }
160 
161 static struct pipe_transfer *
nv30_miptree_transfer_new(struct pipe_context * pipe,struct pipe_resource * pt,unsigned level,unsigned usage,const struct pipe_box * box)162 nv30_miptree_transfer_new(struct pipe_context *pipe, struct pipe_resource *pt,
163                           unsigned level, unsigned usage,
164                           const struct pipe_box *box)
165 {
166    struct nv30_context *nv30 = nv30_context(pipe);
167    struct nouveau_device *dev = nv30->screen->base.device;
168    struct nv30_transfer *tx;
169    int ret;
170 
171    tx = CALLOC_STRUCT(nv30_transfer);
172    if (!tx)
173       return NULL;
174    pipe_resource_reference(&tx->base.resource, pt);
175    tx->base.level = level;
176    tx->base.usage = usage;
177    tx->base.box = *box;
178    tx->base.stride = util_format_get_nblocksx(pt->format, box->width) *
179                      util_format_get_blocksize(pt->format);
180    tx->base.layer_stride = util_format_get_nblocksy(pt->format, box->height) *
181                            tx->base.stride;
182 
183    tx->nblocksx = util_format_get_nblocksx(pt->format, box->width);
184    tx->nblocksy = util_format_get_nblocksy(pt->format, box->height);
185 
186    define_rect(pt, level, box->z, box->x, box->y,
187                    tx->nblocksx, tx->nblocksy, &tx->img);
188 
189    ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
190                         tx->base.layer_stride, NULL, &tx->tmp.bo);
191    if (ret) {
192       pipe_resource_reference(&tx->base.resource, NULL);
193       FREE(tx);
194       return NULL;
195    }
196 
197    tx->tmp.domain = NOUVEAU_BO_GART;
198    tx->tmp.offset = 0;
199    tx->tmp.pitch  = tx->base.stride;
200    tx->tmp.cpp    = tx->img.cpp;
201    tx->tmp.w      = tx->nblocksx;
202    tx->tmp.h      = tx->nblocksy;
203    tx->tmp.d      = 1;
204    tx->tmp.x0     = 0;
205    tx->tmp.y0     = 0;
206    tx->tmp.x1     = tx->tmp.w;
207    tx->tmp.y1     = tx->tmp.h;
208    tx->tmp.z      = 0;
209 
210    if (usage & PIPE_TRANSFER_READ)
211       nv30_transfer_rect(nv30, NEAREST, &tx->img, &tx->tmp);
212 
213    return &tx->base;
214 }
215 
216 static void
nv30_miptree_transfer_del(struct pipe_context * pipe,struct pipe_transfer * ptx)217 nv30_miptree_transfer_del(struct pipe_context *pipe, struct pipe_transfer *ptx)
218 {
219    struct nv30_context *nv30 = nv30_context(pipe);
220    struct nv30_transfer *tx = nv30_transfer(ptx);
221 
222    if (ptx->usage & PIPE_TRANSFER_WRITE)
223       nv30_transfer_rect(nv30, NEAREST, &tx->tmp, &tx->img);
224 
225    nouveau_bo_ref(NULL, &tx->tmp.bo);
226    pipe_resource_reference(&ptx->resource, NULL);
227    FREE(tx);
228 }
229 
230 static void *
nv30_miptree_transfer_map(struct pipe_context * pipe,struct pipe_transfer * ptx)231 nv30_miptree_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx)
232 {
233    struct nv30_context *nv30 = nv30_context(pipe);
234    struct nv30_transfer *tx = nv30_transfer(ptx);
235    unsigned access = 0;
236    int ret;
237 
238    if (tx->tmp.bo->map)
239       return tx->tmp.bo->map;
240 
241    if (ptx->usage & PIPE_TRANSFER_READ)
242       access |= NOUVEAU_BO_RD;
243    if (ptx->usage & PIPE_TRANSFER_WRITE)
244       access |= NOUVEAU_BO_WR;
245 
246    ret = nouveau_bo_map(tx->tmp.bo, access, nv30->base.client);
247    if (ret)
248       return NULL;
249    return tx->tmp.bo->map;
250 }
251 
252 static void
nv30_miptree_transfer_unmap(struct pipe_context * pipe,struct pipe_transfer * ptx)253 nv30_miptree_transfer_unmap(struct pipe_context *pipe,
254                             struct pipe_transfer *ptx)
255 {
256 }
257 
258 const struct u_resource_vtbl nv30_miptree_vtbl = {
259    nv30_miptree_get_handle,
260    nv30_miptree_destroy,
261    nv30_miptree_transfer_new,
262    nv30_miptree_transfer_del,
263    nv30_miptree_transfer_map,
264    u_default_transfer_flush_region,
265    nv30_miptree_transfer_unmap,
266    u_default_transfer_inline_write
267 };
268 
269 struct pipe_resource *
nv30_miptree_create(struct pipe_screen * pscreen,const struct pipe_resource * tmpl)270 nv30_miptree_create(struct pipe_screen *pscreen,
271                     const struct pipe_resource *tmpl)
272 {
273    struct nouveau_device *dev = nouveau_screen(pscreen)->device;
274    struct nv30_miptree *mt = CALLOC_STRUCT(nv30_miptree);
275    struct pipe_resource *pt = &mt->base.base;
276    unsigned blocksz, size;
277    unsigned w, h, d, l;
278    int ret;
279 
280    switch (tmpl->nr_samples) {
281    case 4:
282       mt->ms_mode = 0x00004000;
283       mt->ms_x = 1;
284       mt->ms_y = 1;
285       break;
286    case 2:
287       mt->ms_mode = 0x00003000;
288       mt->ms_x = 1;
289       mt->ms_y = 0;
290       break;
291    default:
292       mt->ms_mode = 0x00000000;
293       mt->ms_x = 0;
294       mt->ms_y = 0;
295       break;
296    }
297 
298    mt->base.vtbl = &nv30_miptree_vtbl;
299    *pt = *tmpl;
300    pipe_reference_init(&pt->reference, 1);
301    pt->screen = pscreen;
302 
303    w = pt->width0 << mt->ms_x;
304    h = pt->height0 << mt->ms_y;
305    d = (pt->target == PIPE_TEXTURE_3D) ? pt->depth0 : 1;
306    blocksz = util_format_get_blocksize(pt->format);
307 
308    if ((pt->target == PIPE_TEXTURE_RECT) ||
309        !util_is_power_of_two(pt->width0) ||
310        !util_is_power_of_two(pt->height0) ||
311        !util_is_power_of_two(pt->depth0) ||
312        util_format_is_compressed(pt->format) ||
313        util_format_is_float(pt->format) || mt->ms_mode) {
314       mt->uniform_pitch = util_format_get_nblocksx(pt->format, w) * blocksz;
315       mt->uniform_pitch = align(mt->uniform_pitch, 64);
316    }
317 
318    if (!mt->uniform_pitch)
319       mt->swizzled = TRUE;
320 
321    size = 0;
322    for (l = 0; l <= pt->last_level; l++) {
323       struct nv30_miptree_level *lvl = &mt->level[l];
324       unsigned nbx = util_format_get_nblocksx(pt->format, w);
325       unsigned nby = util_format_get_nblocksx(pt->format, h);
326 
327       lvl->offset = size;
328       lvl->pitch  = mt->uniform_pitch;
329       if (!lvl->pitch)
330          lvl->pitch = nbx * blocksz;
331 
332       lvl->zslice_size = lvl->pitch * nby;
333       size += lvl->zslice_size * d;
334 
335       w = u_minify(w, 1);
336       h = u_minify(h, 1);
337       d = u_minify(d, 1);
338    }
339 
340    mt->layer_size = size;
341    if (pt->target == PIPE_TEXTURE_CUBE) {
342       if (!mt->uniform_pitch)
343          mt->layer_size = align(mt->layer_size, 128);
344       size = mt->layer_size * 6;
345    }
346 
347    ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 256, size, NULL, &mt->base.bo);
348    if (ret) {
349       FREE(mt);
350       return NULL;
351    }
352 
353    mt->base.domain = NOUVEAU_BO_VRAM;
354    return &mt->base.base;
355 }
356 
357 struct pipe_resource *
nv30_miptree_from_handle(struct pipe_screen * pscreen,const struct pipe_resource * tmpl,struct winsys_handle * handle)358 nv30_miptree_from_handle(struct pipe_screen *pscreen,
359                          const struct pipe_resource *tmpl,
360                          struct winsys_handle *handle)
361 {
362    struct nv30_miptree *mt;
363    unsigned stride;
364 
365    /* only supports 2D, non-mipmapped textures for the moment */
366    if ((tmpl->target != PIPE_TEXTURE_2D &&
367         tmpl->target != PIPE_TEXTURE_RECT) ||
368        tmpl->last_level != 0 ||
369        tmpl->depth0 != 1 ||
370        tmpl->array_size > 1)
371       return NULL;
372 
373    mt = CALLOC_STRUCT(nv30_miptree);
374    if (!mt)
375       return NULL;
376 
377    mt->base.bo = nouveau_screen_bo_from_handle(pscreen, handle, &stride);
378    if (mt->base.bo == NULL) {
379       FREE(mt);
380       return NULL;
381    }
382 
383    mt->base.base = *tmpl;
384    mt->base.vtbl = &nv30_miptree_vtbl;
385    pipe_reference_init(&mt->base.base.reference, 1);
386    mt->base.base.screen = pscreen;
387    mt->uniform_pitch = stride;
388    mt->level[0].pitch = mt->uniform_pitch;
389    mt->level[0].offset = 0;
390 
391    /* no need to adjust bo reference count */
392    return &mt->base.base;
393 }
394 
395 struct pipe_surface *
nv30_miptree_surface_new(struct pipe_context * pipe,struct pipe_resource * pt,const struct pipe_surface * tmpl)396 nv30_miptree_surface_new(struct pipe_context *pipe,
397                          struct pipe_resource *pt,
398                          const struct pipe_surface *tmpl)
399 {
400    struct nv30_miptree *mt = nv30_miptree(pt); /* guaranteed */
401    struct nv30_surface *ns;
402    struct pipe_surface *ps;
403    struct nv30_miptree_level *lvl = &mt->level[tmpl->u.tex.level];
404 
405    ns = CALLOC_STRUCT(nv30_surface);
406    if (!ns)
407       return NULL;
408    ps = &ns->base;
409 
410    pipe_reference_init(&ps->reference, 1);
411    pipe_resource_reference(&ps->texture, pt);
412    ps->context = pipe;
413    ps->format = tmpl->format;
414    ps->usage = tmpl->usage;
415    ps->u.tex.level = tmpl->u.tex.level;
416    ps->u.tex.first_layer = tmpl->u.tex.first_layer;
417    ps->u.tex.last_layer = tmpl->u.tex.last_layer;
418 
419    ns->width = u_minify(pt->width0, ps->u.tex.level);
420    ns->height = u_minify(pt->height0, ps->u.tex.level);
421    ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
422    ns->offset = layer_offset(pt, ps->u.tex.level, ps->u.tex.first_layer);
423    if (mt->swizzled)
424       ns->pitch = 4096; /* random, just something the hw won't reject.. */
425    else
426       ns->pitch = lvl->pitch;
427 
428    /* comment says there are going to be removed, but they're used by the st */
429    ps->width = ns->width;
430    ps->height = ns->height;
431    return ps;
432 }
433 
434 void
nv30_miptree_surface_del(struct pipe_context * pipe,struct pipe_surface * ps)435 nv30_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps)
436 {
437    struct nv30_surface *ns = nv30_surface(ps);
438 
439    pipe_resource_reference(&ps->texture, NULL);
440    FREE(ns);
441 }
442