Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / drivers / nvc0 / nvc0_surface.c
1 /*
2  * Copyright 2008 Ben Skeggs
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
23 #include <stdint.h>
24
25 #include "pipe/p_defines.h"
26
27 #include "util/u_inlines.h"
28 #include "util/u_pack_color.h"
29 #include "util/u_format.h"
30 #include "util/u_surface.h"
31
32 #include "nvc0_context.h"
33 #include "nvc0_resource.h"
34 #include "nvc0_transfer.h"
35
36 #include "nv50/nv50_defs.xml.h"
37
38 #define NVC0_ENG2D_SUPPORTED_FORMATS 0xff9ccfe1cce3ccc9ULL
39
40 /* return TRUE for formats that can be converted among each other by NVC0_2D */
41 static INLINE boolean
42 nvc0_2d_format_faithful(enum pipe_format format)
43 {
44    uint8_t id = nvc0_format_table[format].rt;
45
46    return (id >= 0xc0) && (NVC0_ENG2D_SUPPORTED_FORMATS & (1ULL << (id - 0xc0)));
47 }
48
49 static INLINE uint8_t
50 nvc0_2d_format(enum pipe_format format)
51 {
52    uint8_t id = nvc0_format_table[format].rt;
53
54    /* Hardware values for color formats range from 0xc0 to 0xff,
55     * but the 2D engine doesn't support all of them.
56     */
57    if (nvc0_2d_format_faithful(format))
58       return id;
59
60    switch (util_format_get_blocksize(format)) {
61    case 1:
62       return NV50_SURFACE_FORMAT_R8_UNORM;
63    case 2:
64       return NV50_SURFACE_FORMAT_R16_UNORM;
65    case 4:
66       return NV50_SURFACE_FORMAT_A8R8G8B8_UNORM;
67    case 8:
68       return NV50_SURFACE_FORMAT_R16G16B16A16_UNORM;
69    case 16:
70       return NV50_SURFACE_FORMAT_R32G32B32A32_FLOAT;
71    default:
72       return 0;
73    }
74 }
75
76 static int
77 nvc0_2d_texture_set(struct nouveau_channel *chan, int dst,
78                     struct nvc0_miptree *mt, unsigned level, unsigned layer)
79 {
80    struct nouveau_bo *bo = mt->base.bo;
81    uint32_t width, height, depth;
82    uint32_t format;
83    uint32_t mthd = dst ? NVC0_2D_DST_FORMAT : NVC0_2D_SRC_FORMAT;
84    uint32_t flags = mt->base.domain | (dst ? NOUVEAU_BO_WR : NOUVEAU_BO_RD);
85    uint32_t offset = mt->level[level].offset;
86
87    format = nvc0_2d_format(mt->base.base.format);
88    if (!format) {
89       NOUVEAU_ERR("invalid/unsupported surface format: %s\n",
90                   util_format_name(mt->base.base.format));
91       return 1;
92    }
93
94    width = u_minify(mt->base.base.width0, level);
95    height = u_minify(mt->base.base.height0, level);
96    depth = u_minify(mt->base.base.depth0, level);
97
98    /* layer has to be < depth, and depth > tile depth / 2 */
99
100    if (!mt->layout_3d) {
101       offset += mt->layer_stride * layer;
102       layer = 0;
103       depth = 1;
104    } else
105    if (!dst) {
106       offset += nvc0_miptree_zslice_offset(mt, level, layer);
107       layer = 0;
108    }
109
110    if (!(bo->tile_flags & NOUVEAU_BO_TILE_LAYOUT_MASK)) {
111       BEGIN_RING(chan, RING_2D_(mthd), 2);
112       OUT_RING  (chan, format);
113       OUT_RING  (chan, 1);
114       BEGIN_RING(chan, RING_2D_(mthd + 0x14), 5);
115       OUT_RING  (chan, mt->level[level].pitch);
116       OUT_RING  (chan, width);
117       OUT_RING  (chan, height);
118       OUT_RELOCh(chan, bo, offset, flags);
119       OUT_RELOCl(chan, bo, offset, flags);
120    } else {
121       BEGIN_RING(chan, RING_2D_(mthd), 5);
122       OUT_RING  (chan, format);
123       OUT_RING  (chan, 0);
124       OUT_RING  (chan, mt->level[level].tile_mode);
125       OUT_RING  (chan, depth);
126       OUT_RING  (chan, layer);
127       BEGIN_RING(chan, RING_2D_(mthd + 0x18), 4);
128       OUT_RING  (chan, width);
129       OUT_RING  (chan, height);
130       OUT_RELOCh(chan, bo, offset, flags);
131       OUT_RELOCl(chan, bo, offset, flags);
132    }
133
134 #if 0
135    if (dst) {
136       BEGIN_RING(chan, RING_2D_(NVC0_2D_CLIP_X), 4);
137       OUT_RING  (chan, 0);
138       OUT_RING  (chan, 0);
139       OUT_RING  (chan, width);
140       OUT_RING  (chan, height);
141    }
142 #endif
143    return 0;
144 }
145
146 static int
147 nvc0_2d_texture_do_copy(struct nouveau_channel *chan,
148                         struct nvc0_miptree *dst, unsigned dst_level,
149                         unsigned dx, unsigned dy, unsigned dz,
150                         struct nvc0_miptree *src, unsigned src_level,
151                         unsigned sx, unsigned sy, unsigned sz,
152                         unsigned w, unsigned h)
153 {
154    int ret;
155
156    ret = MARK_RING(chan, 2 * 16 + 32, 4);
157    if (ret)
158       return ret;
159
160    ret = nvc0_2d_texture_set(chan, 1, dst, dst_level, dz);
161    if (ret)
162       return ret;
163
164    ret = nvc0_2d_texture_set(chan, 0, src, src_level, sz);
165    if (ret)
166       return ret;
167
168    /* 0/1 = CENTER/CORNER, 10/00 = POINT/BILINEAR */
169    BEGIN_RING(chan, RING_2D(BLIT_CONTROL), 1);
170    OUT_RING  (chan, 0);
171    BEGIN_RING(chan, RING_2D(BLIT_DST_X), 4);
172    OUT_RING  (chan, dx);
173    OUT_RING  (chan, dy);
174    OUT_RING  (chan, w);
175    OUT_RING  (chan, h);
176    BEGIN_RING(chan, RING_2D(BLIT_DU_DX_FRACT), 4);
177    OUT_RING  (chan, 0);
178    OUT_RING  (chan, 1);
179    OUT_RING  (chan, 0);
180    OUT_RING  (chan, 1);
181    BEGIN_RING(chan, RING_2D(BLIT_SRC_X_FRACT), 4);
182    OUT_RING  (chan, 0);
183    OUT_RING  (chan, sx);
184    OUT_RING  (chan, 0);
185    OUT_RING  (chan, sy);
186
187    return 0;
188 }
189
190 static void
191 nvc0_setup_m2mf_rect(struct nvc0_m2mf_rect *rect,
192                      struct pipe_resource *restrict res, unsigned l,
193                      unsigned x, unsigned y, unsigned z)
194 {
195    struct nvc0_miptree *mt = nvc0_miptree(res);
196    const unsigned w = u_minify(res->width0, l);
197    const unsigned h = u_minify(res->height0, l);
198
199    rect->bo = mt->base.bo;
200    rect->domain = mt->base.domain;
201    rect->base = mt->level[l].offset;
202    rect->pitch = mt->level[l].pitch;
203    if (util_format_is_plain(res->format)) {
204       rect->width = w;
205       rect->height = h;
206       rect->x = x;
207       rect->y = y;
208    } else {
209       rect->width = util_format_get_nblocksx(res->format, w);
210       rect->height = util_format_get_nblocksy(res->format, h);
211       rect->x = util_format_get_nblocksx(res->format, x);
212       rect->y = util_format_get_nblocksy(res->format, y);
213    }
214    rect->tile_mode = mt->level[l].tile_mode;
215    rect->cpp = util_format_get_blocksize(res->format);
216
217    if (mt->layout_3d) {
218       rect->z = z;
219       rect->depth = u_minify(res->depth0, l);
220    } else {
221       rect->base += z * mt->layer_stride;
222       rect->z = 0;
223       rect->depth = 1;
224    }
225 }
226
227 static void
228 nvc0_resource_copy_region(struct pipe_context *pipe,
229                           struct pipe_resource *dst, unsigned dst_level,
230                           unsigned dstx, unsigned dsty, unsigned dstz,
231                           struct pipe_resource *src, unsigned src_level,
232                           const struct pipe_box *src_box)
233 {
234    struct nvc0_screen *screen = nvc0_context(pipe)->screen;
235    int ret;
236    unsigned dst_layer = dstz, src_layer = src_box->z;
237
238    /* Fallback for buffers. */
239    if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
240       util_resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz,
241                                 src, src_level, src_box);
242       return;
243    }
244
245    nv04_resource(dst)->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
246
247    if (src->format == dst->format) {
248       struct nvc0_m2mf_rect drect, srect;
249       unsigned i;
250       unsigned nx = util_format_get_nblocksx(src->format, src_box->width);
251       unsigned ny = util_format_get_nblocksy(src->format, src_box->height);
252
253       nvc0_setup_m2mf_rect(&drect, dst, dst_level, dstx, dsty, dstz);
254       nvc0_setup_m2mf_rect(&srect, src, src_level,
255                            src_box->x, src_box->y, src_box->z);
256
257       for (i = 0; i < src_box->depth; ++i) {
258          nvc0_m2mf_transfer_rect(&screen->base.base, &drect, &srect, nx, ny);
259
260          if (nvc0_miptree(dst)->layout_3d)
261             drect.z++;
262          else
263             drect.base += nvc0_miptree(dst)->layer_stride;
264
265          if (nvc0_miptree(src)->layout_3d)
266             srect.z++;
267          else
268             srect.base += nvc0_miptree(src)->layer_stride;
269       }
270       return;
271    }
272
273    assert(nvc0_2d_format_faithful(src->format));
274    assert(nvc0_2d_format_faithful(dst->format));
275
276    for (; dst_layer < dstz + src_box->depth; ++dst_layer, ++src_layer) {
277       ret = nvc0_2d_texture_do_copy(screen->base.channel,
278                                     nvc0_miptree(dst), dst_level,
279                                     dstx, dsty, dst_layer,
280                                     nvc0_miptree(src), src_level,
281                                     src_box->x, src_box->y, src_layer,
282                                     src_box->width, src_box->height);
283       if (ret)
284          return;
285    }
286 }
287
288 static void
289 nvc0_clear_render_target(struct pipe_context *pipe,
290                          struct pipe_surface *dst,
291                          const float *rgba,
292                          unsigned dstx, unsigned dsty,
293                          unsigned width, unsigned height)
294 {
295         struct nvc0_context *nv50 = nvc0_context(pipe);
296         struct nvc0_screen *screen = nv50->screen;
297         struct nouveau_channel *chan = screen->base.channel;
298         struct nvc0_miptree *mt = nvc0_miptree(dst->texture);
299         struct nvc0_surface *sf = nvc0_surface(dst);
300         struct nouveau_bo *bo = mt->base.bo;
301
302         BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4);
303         OUT_RINGf (chan, rgba[0]);
304         OUT_RINGf (chan, rgba[1]);
305         OUT_RINGf (chan, rgba[2]);
306         OUT_RINGf (chan, rgba[3]);
307
308         if (MARK_RING(chan, 18, 2))
309                 return;
310
311         BEGIN_RING(chan, RING_3D(RT_CONTROL), 1);
312         OUT_RING  (chan, 1);
313         BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(0)), 9);
314         OUT_RELOCh(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
315         OUT_RELOCl(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
316         OUT_RING  (chan, sf->width);
317         OUT_RING  (chan, sf->height);
318         OUT_RING  (chan, nvc0_format_table[dst->format].rt);
319         OUT_RING  (chan, (mt->layout_3d << 16) |
320               mt->level[sf->base.u.tex.level].tile_mode);
321         OUT_RING  (chan, dst->u.tex.first_layer + sf->depth);
322         OUT_RING  (chan, mt->layer_stride >> 2);
323         OUT_RING  (chan, dst->u.tex.first_layer);
324
325         BEGIN_RING(chan, RING_3D(CLIP_RECT_HORIZ(0)), 2);
326         OUT_RING  (chan, ((dstx + width) << 16) | dstx);
327         OUT_RING  (chan, ((dsty + height) << 16) | dsty);
328         IMMED_RING(chan, RING_3D(CLIP_RECTS_EN), 1);
329
330         BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
331         OUT_RING  (chan, 0x3c);
332
333         IMMED_RING(chan, RING_3D(CLIP_RECTS_EN), 0);
334
335         nv50->dirty |= NVC0_NEW_FRAMEBUFFER;
336 }
337
338 static void
339 nvc0_clear_depth_stencil(struct pipe_context *pipe,
340                          struct pipe_surface *dst,
341                          unsigned clear_flags,
342                          double depth,
343                          unsigned stencil,
344                          unsigned dstx, unsigned dsty,
345                          unsigned width, unsigned height)
346 {
347         struct nvc0_context *nv50 = nvc0_context(pipe);
348         struct nvc0_screen *screen = nv50->screen;
349         struct nouveau_channel *chan = screen->base.channel;
350         struct nvc0_miptree *mt = nvc0_miptree(dst->texture);
351         struct nvc0_surface *sf = nvc0_surface(dst);
352         struct nouveau_bo *bo = mt->base.bo;
353         uint32_t mode = 0;
354         int unk = mt->base.base.target == PIPE_TEXTURE_2D;
355
356         if (clear_flags & PIPE_CLEAR_DEPTH) {
357                 BEGIN_RING(chan, RING_3D(CLEAR_DEPTH), 1);
358                 OUT_RINGf (chan, depth);
359                 mode |= NVC0_3D_CLEAR_BUFFERS_Z;
360         }
361
362         if (clear_flags & PIPE_CLEAR_STENCIL) {
363                 BEGIN_RING(chan, RING_3D(CLEAR_STENCIL), 1);
364                 OUT_RING  (chan, stencil & 0xff);
365                 mode |= NVC0_3D_CLEAR_BUFFERS_S;
366         }
367
368         if (MARK_RING(chan, 17, 2))
369                 return;
370
371         BEGIN_RING(chan, RING_3D(ZETA_ADDRESS_HIGH), 5);
372         OUT_RELOCh(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
373         OUT_RELOCl(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
374         OUT_RING  (chan, nvc0_format_table[dst->format].rt);
375         OUT_RING  (chan, mt->level[sf->base.u.tex.level].tile_mode);
376         OUT_RING  (chan, mt->layer_stride >> 2);
377         BEGIN_RING(chan, RING_3D(ZETA_ENABLE), 1);
378         OUT_RING  (chan, 1);
379         BEGIN_RING(chan, RING_3D(ZETA_HORIZ), 3);
380         OUT_RING  (chan, sf->width);
381         OUT_RING  (chan, sf->height);
382         OUT_RING  (chan, (unk << 16) | (dst->u.tex.first_layer + sf->depth));
383         BEGIN_RING(chan, RING_3D(ZETA_BASE_LAYER), 1);
384         OUT_RING  (chan, dst->u.tex.first_layer);
385
386         BEGIN_RING(chan, RING_3D(CLIP_RECT_HORIZ(0)), 2);
387         OUT_RING  (chan, ((dstx + width) << 16) | dstx);
388         OUT_RING  (chan, ((dsty + height) << 16) | dsty);
389         IMMED_RING(chan, RING_3D(CLIP_RECTS_EN), 1);
390
391         BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
392         OUT_RING  (chan, mode);
393
394         IMMED_RING(chan, RING_3D(CLIP_RECTS_EN), 0);
395
396         nv50->dirty |= NVC0_NEW_FRAMEBUFFER;
397 }
398
399 void
400 nvc0_clear(struct pipe_context *pipe, unsigned buffers,
401            const float *rgba, double depth, unsigned stencil)
402 {
403    struct nvc0_context *nvc0 = nvc0_context(pipe);
404    struct nouveau_channel *chan = nvc0->screen->base.channel;
405    struct pipe_framebuffer_state *fb = &nvc0->framebuffer;
406    unsigned i;
407    const unsigned dirty = nvc0->dirty;
408    uint32_t mode = 0;
409
410    /* don't need NEW_BLEND, COLOR_MASK doesn't affect CLEAR_BUFFERS */
411    nvc0->dirty &= NVC0_NEW_FRAMEBUFFER;
412    if (!nvc0_state_validate(nvc0))
413       return;
414
415    if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) {
416       BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4);
417       OUT_RINGf (chan, rgba[0]);
418       OUT_RINGf (chan, rgba[1]);
419       OUT_RINGf (chan, rgba[2]);
420       OUT_RINGf (chan, rgba[3]);
421       mode =
422          NVC0_3D_CLEAR_BUFFERS_R | NVC0_3D_CLEAR_BUFFERS_G |
423          NVC0_3D_CLEAR_BUFFERS_B | NVC0_3D_CLEAR_BUFFERS_A;
424    }
425
426    if (buffers & PIPE_CLEAR_DEPTH) {
427       BEGIN_RING(chan, RING_3D(CLEAR_DEPTH), 1);
428       OUT_RING  (chan, fui(depth));
429       mode |= NVC0_3D_CLEAR_BUFFERS_Z;
430    }
431
432    if (buffers & PIPE_CLEAR_STENCIL) {
433       BEGIN_RING(chan, RING_3D(CLEAR_STENCIL), 1);
434       OUT_RING  (chan, stencil & 0xff);
435       mode |= NVC0_3D_CLEAR_BUFFERS_S;
436    }
437
438    BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
439    OUT_RING  (chan, mode);
440
441    for (i = 1; i < fb->nr_cbufs; i++) {
442       BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
443       OUT_RING  (chan, (i << 6) | 0x3c);
444    }
445
446    nvc0->dirty = dirty & ~NVC0_NEW_FRAMEBUFFER;
447 }
448
449 void
450 nvc0_init_surface_functions(struct nvc0_context *nvc0)
451 {
452    struct pipe_context *pipe = &nvc0->base.pipe;
453
454    pipe->resource_copy_region = nvc0_resource_copy_region;
455    pipe->clear_render_target = nvc0_clear_render_target;
456    pipe->clear_depth_stencil = nvc0_clear_depth_stencil;
457 }
458
459