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 "pipe/p_defines.h"
27 #include "util/u_pack_color.h"
28 
29 #include "nouveau/nouveau_gldefs.h"
30 #include "nouveau/nv_object.xml.h"
31 #include "nv30-40_3d.xml.h"
32 #include "nv30_context.h"
33 #include "nv30_format.h"
34 
35 static INLINE uint32_t
pack_rgba(enum pipe_format format,const float * rgba)36 pack_rgba(enum pipe_format format, const float *rgba)
37 {
38    union util_color uc;
39    util_pack_color(rgba, format, &uc);
40    return uc.ui;
41 }
42 
43 static INLINE uint32_t
pack_zeta(enum pipe_format format,double depth,unsigned stencil)44 pack_zeta(enum pipe_format format, double depth, unsigned stencil)
45 {
46    uint32_t zuint = (uint32_t)(depth * 4294967295.0);
47    if (format != PIPE_FORMAT_Z16_UNORM)
48       return (zuint & 0xffffff00) | (stencil & 0xff);
49    return zuint >> 16;
50 }
51 
52 static void
nv30_clear(struct pipe_context * pipe,unsigned buffers,const union pipe_color_union * color,double depth,unsigned stencil)53 nv30_clear(struct pipe_context *pipe, unsigned buffers,
54            const union pipe_color_union *color, double depth, unsigned stencil)
55 {
56    struct nv30_context *nv30 = nv30_context(pipe);
57    struct nouveau_pushbuf *push = nv30->base.pushbuf;
58    struct pipe_framebuffer_state *fb = &nv30->framebuffer;
59    uint32_t colr = 0, zeta = 0, mode = 0;
60 
61    if (!nv30_state_validate(nv30, TRUE))
62       return;
63 
64    if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) {
65       colr  = pack_rgba(fb->cbufs[0]->format, color->f);
66       mode |= NV30_3D_CLEAR_BUFFERS_COLOR_R |
67               NV30_3D_CLEAR_BUFFERS_COLOR_G |
68               NV30_3D_CLEAR_BUFFERS_COLOR_B |
69               NV30_3D_CLEAR_BUFFERS_COLOR_A;
70    }
71 
72    if (fb->zsbuf) {
73       zeta = pack_zeta(fb->zsbuf->format, depth, stencil);
74       if (buffers & PIPE_CLEAR_DEPTH)
75          mode |= NV30_3D_CLEAR_BUFFERS_DEPTH;
76       if (buffers & PIPE_CLEAR_STENCIL)
77          mode |= NV30_3D_CLEAR_BUFFERS_STENCIL;
78    }
79 
80    /*XXX: wtf? fixes clears sometimes not clearing on nv3x... */
81    if (nv30->screen->eng3d->oclass < NV40_3D_CLASS) {
82       BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3);
83       PUSH_DATA (push, zeta);
84       PUSH_DATA (push, colr);
85       PUSH_DATA (push, mode);
86    }
87 
88    BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3);
89    PUSH_DATA (push, zeta);
90    PUSH_DATA (push, colr);
91    PUSH_DATA (push, mode);
92 
93    nv30_state_release(nv30);
94 }
95 
96 static void
nv30_clear_render_target(struct pipe_context * pipe,struct pipe_surface * ps,const union pipe_color_union * color,unsigned x,unsigned y,unsigned w,unsigned h)97 nv30_clear_render_target(struct pipe_context *pipe, struct pipe_surface *ps,
98                          const union pipe_color_union *color,
99                          unsigned x, unsigned y, unsigned w, unsigned h)
100 {
101    struct nv30_context *nv30 = nv30_context(pipe);
102    struct nv30_surface *sf = nv30_surface(ps);
103    struct nv30_miptree *mt = nv30_miptree(ps->texture);
104    struct nouveau_pushbuf *push = nv30->base.pushbuf;
105    struct nouveau_object *eng3d = nv30->screen->eng3d;
106    struct nouveau_pushbuf_refn refn;
107    uint32_t rt_format;
108 
109    rt_format = nv30_format(pipe->screen, ps->format)->hw;
110    if (util_format_get_blocksize(ps->format) == 4)
111       rt_format |= NV30_3D_RT_FORMAT_ZETA_Z24S8;
112    else
113       rt_format |= NV30_3D_RT_FORMAT_ZETA_Z16;
114 
115    if (nv30_miptree(ps->texture)->swizzled) {
116       rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
117       rt_format |= util_logbase2(sf->width) << 16;
118       rt_format |= util_logbase2(sf->height) << 24;
119    } else {
120       rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
121    }
122 
123    refn.bo = mt->base.bo;
124    refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
125    if (nouveau_pushbuf_space(push, 16, 1, 0) ||
126        nouveau_pushbuf_refn (push, &refn, 1))
127       return;
128 
129    BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
130    PUSH_DATA (push, NV30_3D_RT_ENABLE_COLOR0);
131    BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
132    PUSH_DATA (push, sf->width << 16);
133    PUSH_DATA (push, sf->height << 16);
134    PUSH_DATA (push, rt_format);
135    BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 2);
136    if (eng3d->oclass < NV40_3D_CLASS)
137       PUSH_DATA (push, (sf->pitch << 16) | sf->pitch);
138    else
139       PUSH_DATA (push, sf->pitch);
140    PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0);
141    BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
142    PUSH_DATA (push, (w << 16) | x);
143    PUSH_DATA (push, (h << 16) | y);
144 
145    BEGIN_NV04(push, NV30_3D(CLEAR_COLOR_VALUE), 2);
146    PUSH_DATA (push, pack_rgba(ps->format, color->f));
147    PUSH_DATA (push, NV30_3D_CLEAR_BUFFERS_COLOR_R |
148                     NV30_3D_CLEAR_BUFFERS_COLOR_G |
149                     NV30_3D_CLEAR_BUFFERS_COLOR_B |
150                     NV30_3D_CLEAR_BUFFERS_COLOR_A);
151 
152    nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
153 }
154 
155 static void
nv30_clear_depth_stencil(struct pipe_context * pipe,struct pipe_surface * ps,unsigned buffers,double depth,unsigned stencil,unsigned x,unsigned y,unsigned w,unsigned h)156 nv30_clear_depth_stencil(struct pipe_context *pipe, struct pipe_surface *ps,
157                          unsigned buffers, double depth, unsigned stencil,
158                          unsigned x, unsigned y, unsigned w, unsigned h)
159 {
160    struct nv30_context *nv30 = nv30_context(pipe);
161    struct nv30_surface *sf = nv30_surface(ps);
162    struct nv30_miptree *mt = nv30_miptree(ps->texture);
163    struct nouveau_pushbuf *push = nv30->base.pushbuf;
164    struct nouveau_object *eng3d = nv30->screen->eng3d;
165    struct nouveau_pushbuf_refn refn;
166    uint32_t rt_format, mode = 0;
167 
168    rt_format = nv30_format(pipe->screen, ps->format)->hw;
169    if (util_format_get_blocksize(ps->format) == 4)
170       rt_format |= NV30_3D_RT_FORMAT_COLOR_A8R8G8B8;
171    else
172       rt_format |= NV30_3D_RT_FORMAT_COLOR_R5G6B5;
173 
174    if (nv30_miptree(ps->texture)->swizzled) {
175       rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED;
176       rt_format |= util_logbase2(sf->width) << 16;
177       rt_format |= util_logbase2(sf->height) << 24;
178    } else {
179       rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR;
180    }
181 
182    if (buffers & PIPE_CLEAR_DEPTH)
183       mode |= NV30_3D_CLEAR_BUFFERS_DEPTH;
184    if (buffers & PIPE_CLEAR_STENCIL)
185       mode |= NV30_3D_CLEAR_BUFFERS_STENCIL;
186 
187    refn.bo = mt->base.bo;
188    refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR;
189    if (nouveau_pushbuf_space(push, 32, 1, 0) ||
190        nouveau_pushbuf_refn (push, &refn, 1))
191       return;
192 
193    BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1);
194    PUSH_DATA (push, 0);
195    BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3);
196    PUSH_DATA (push, sf->width << 16);
197    PUSH_DATA (push, sf->height << 16);
198    PUSH_DATA (push, rt_format);
199    if (eng3d->oclass < NV40_3D_CLASS) {
200       BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 1);
201       PUSH_DATA (push, (sf->pitch << 16) | sf->pitch);
202    } else {
203       BEGIN_NV04(push, NV40_3D(ZETA_PITCH), 1);
204       PUSH_DATA (push, sf->pitch);
205    }
206    BEGIN_NV04(push, NV30_3D(ZETA_OFFSET), 1);
207    PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0);
208    BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
209    PUSH_DATA (push, (w << 16) | x);
210    PUSH_DATA (push, (h << 16) | y);
211 
212    BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 1);
213    PUSH_DATA (push, pack_zeta(ps->format, depth, stencil));
214    BEGIN_NV04(push, NV30_3D(CLEAR_BUFFERS), 1);
215    PUSH_DATA (push, mode);
216 
217    nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR;
218 }
219 
220 void
nv30_clear_init(struct pipe_context * pipe)221 nv30_clear_init(struct pipe_context *pipe)
222 {
223    pipe->clear = nv30_clear;
224    pipe->clear_render_target = nv30_clear_render_target;
225    pipe->clear_depth_stencil = nv30_clear_depth_stencil;
226 }
227