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