faa51769313adedf11d5465ccefec5f91312bd48
[mesa.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
31 #include "nvc0_context.h"
32 #include "nvc0_resource.h"
33
34 #include "nv50_defs.xml.h"
35
36 #define NVC0_ENG2D_SUPPORTED_FORMATS 0xff9ccfe1cce3ccc9ULL
37
38 /* return TRUE for formats that can be converted among each other by NVC0_2D */
39 static INLINE boolean
40 nvc0_2d_format_faithful(enum pipe_format format)
41 {
42 uint8_t id = nvc0_format_table[format].rt;
43
44 return (id >= 0xc0) && (NVC0_ENG2D_SUPPORTED_FORMATS & (1ULL << (id - 0xc0)));
45 }
46
47 static INLINE uint8_t
48 nvc0_2d_format(enum pipe_format format)
49 {
50 uint8_t id = nvc0_format_table[format].rt;
51
52 /* Hardware values for color formats range from 0xc0 to 0xff,
53 * but the 2D engine doesn't support all of them.
54 */
55 if (nvc0_2d_format_faithful(format))
56 return id;
57
58 switch (util_format_get_blocksize(format)) {
59 case 1:
60 return NV50_SURFACE_FORMAT_R8_UNORM;
61 case 2:
62 return NV50_SURFACE_FORMAT_R16_UNORM;
63 case 4:
64 return NV50_SURFACE_FORMAT_A8R8G8B8_UNORM;
65 case 8:
66 return NV50_SURFACE_FORMAT_R16G16B16A16_UNORM;
67 case 16:
68 return NV50_SURFACE_FORMAT_R32G32B32A32_FLOAT;
69 default:
70 return 0;
71 }
72 }
73
74 static int
75 nvc0_2d_texture_set(struct nouveau_channel *chan, int dst,
76 struct nvc0_miptree *mt, unsigned level, unsigned layer)
77 {
78 struct nouveau_bo *bo = mt->base.bo;
79 uint32_t width, height, depth;
80 uint32_t format;
81 uint32_t mthd = dst ? NVC0_2D_DST_FORMAT : NVC0_2D_SRC_FORMAT;
82 uint32_t flags = mt->base.domain | (dst ? NOUVEAU_BO_WR : NOUVEAU_BO_RD);
83 uint32_t offset = mt->level[level].offset;
84
85 format = nvc0_2d_format(mt->base.base.format);
86 if (!format) {
87 NOUVEAU_ERR("invalid/unsupported surface format: %s\n",
88 util_format_name(mt->base.base.format));
89 return 1;
90 }
91
92 width = u_minify(mt->base.base.width0, level);
93 height = u_minify(mt->base.base.height0, level);
94
95 offset = mt->level[level].offset;
96 if (!mt->layout_3d) {
97 offset += mt->layer_stride * layer;
98 depth = 1;
99 layer = 0;
100 } else {
101 depth = u_minify(mt->base.base.depth0, level);
102 }
103
104 if (!(bo->tile_flags & NOUVEAU_BO_TILE_LAYOUT_MASK)) {
105 BEGIN_RING(chan, RING_2D_(mthd), 2);
106 OUT_RING (chan, format);
107 OUT_RING (chan, 1);
108 BEGIN_RING(chan, RING_2D_(mthd + 0x14), 5);
109 OUT_RING (chan, mt->level[level].pitch);
110 OUT_RING (chan, width);
111 OUT_RING (chan, height);
112 OUT_RELOCh(chan, bo, offset, flags);
113 OUT_RELOCl(chan, bo, offset, flags);
114 } else {
115 BEGIN_RING(chan, RING_2D_(mthd), 5);
116 OUT_RING (chan, format);
117 OUT_RING (chan, 0);
118 OUT_RING (chan, mt->level[level].tile_mode);
119 OUT_RING (chan, depth);
120 OUT_RING (chan, layer);
121 BEGIN_RING(chan, RING_2D_(mthd + 0x18), 4);
122 OUT_RING (chan, width);
123 OUT_RING (chan, height);
124 OUT_RELOCh(chan, bo, offset, flags);
125 OUT_RELOCl(chan, bo, offset, flags);
126 }
127
128 #if 0
129 if (dst) {
130 BEGIN_RING(chan, RING_2D_(NVC0_2D_CLIP_X), 4);
131 OUT_RING (chan, 0);
132 OUT_RING (chan, 0);
133 OUT_RING (chan, width);
134 OUT_RING (chan, height);
135 }
136 #endif
137 return 0;
138 }
139
140 static int
141 nvc0_2d_texture_do_copy(struct nouveau_channel *chan,
142 struct nvc0_miptree *dst, unsigned dst_level,
143 unsigned dx, unsigned dy, unsigned dz,
144 struct nvc0_miptree *src, unsigned src_level,
145 unsigned sx, unsigned sy, unsigned sz,
146 unsigned w, unsigned h)
147 {
148 int ret;
149
150 ret = MARK_RING(chan, 2 * 16 + 32, 4);
151 if (ret)
152 return ret;
153
154 ret = nvc0_2d_texture_set(chan, 1, dst, dst_level, dz);
155 if (ret)
156 return ret;
157
158 ret = nvc0_2d_texture_set(chan, 0, src, src_level, sz);
159 if (ret)
160 return ret;
161
162 /* 0/1 = CENTER/CORNER, 10/00 = POINT/BILINEAR */
163 BEGIN_RING(chan, RING_2D(BLIT_CONTROL), 1);
164 OUT_RING (chan, 0);
165 BEGIN_RING(chan, RING_2D(BLIT_DST_X), 4);
166 OUT_RING (chan, dx);
167 OUT_RING (chan, dy);
168 OUT_RING (chan, w);
169 OUT_RING (chan, h);
170 BEGIN_RING(chan, RING_2D(BLIT_DU_DX_FRACT), 4);
171 OUT_RING (chan, 0);
172 OUT_RING (chan, 1);
173 OUT_RING (chan, 0);
174 OUT_RING (chan, 1);
175 BEGIN_RING(chan, RING_2D(BLIT_SRC_X_FRACT), 4);
176 OUT_RING (chan, 0);
177 OUT_RING (chan, sx);
178 OUT_RING (chan, 0);
179 OUT_RING (chan, sy);
180
181 return 0;
182 }
183
184 static void
185 nvc0_resource_copy_region(struct pipe_context *pipe,
186 struct pipe_resource *dst, unsigned dst_level,
187 unsigned dstx, unsigned dsty, unsigned dstz,
188 struct pipe_resource *src, unsigned src_level,
189 const struct pipe_box *src_box)
190 {
191 struct nvc0_screen *screen = nvc0_context(pipe)->screen;
192 int ret;
193 unsigned dst_layer = dstz, src_layer = src_box->z;
194
195 assert((src->format == dst->format) ||
196 (nvc0_2d_format_faithful(src->format) &&
197 nvc0_2d_format_faithful(dst->format)));
198
199 for (; dst_layer < dstz + src_box->depth; ++dst_layer, ++src_layer) {
200 ret = nvc0_2d_texture_do_copy(screen->base.channel,
201 nvc0_miptree(dst), dst_level,
202 dstx, dsty, dst_layer,
203 nvc0_miptree(src), src_level,
204 src_box->x, src_box->y, src_layer,
205 src_box->width, src_box->height);
206 if (ret)
207 return;
208 }
209 }
210
211 static void
212 nvc0_clear_render_target(struct pipe_context *pipe,
213 struct pipe_surface *dst,
214 const float *rgba,
215 unsigned dstx, unsigned dsty,
216 unsigned width, unsigned height)
217 {
218 struct nvc0_context *nv50 = nvc0_context(pipe);
219 struct nvc0_screen *screen = nv50->screen;
220 struct nouveau_channel *chan = screen->base.channel;
221 struct nvc0_miptree *mt = nvc0_miptree(dst->texture);
222 struct nvc0_surface *sf = nvc0_surface(dst);
223 struct nouveau_bo *bo = mt->base.bo;
224
225 BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4);
226 OUT_RINGf (chan, rgba[0]);
227 OUT_RINGf (chan, rgba[1]);
228 OUT_RINGf (chan, rgba[2]);
229 OUT_RINGf (chan, rgba[3]);
230
231 if (MARK_RING(chan, 18, 2))
232 return;
233
234 BEGIN_RING(chan, RING_3D(RT_CONTROL), 1);
235 OUT_RING (chan, 1);
236 BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(0)), 8);
237 OUT_RELOCh(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
238 OUT_RELOCl(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
239 OUT_RING (chan, sf->width);
240 OUT_RING (chan, sf->height);
241 OUT_RING (chan, nvc0_format_table[dst->format].rt);
242 OUT_RING (chan, mt->level[sf->base.u.tex.level].tile_mode);
243 OUT_RING (chan, 1);
244 OUT_RING (chan, 0);
245
246 /* NOTE: only works with D3D clear flag (5097/0x143c bit 4) */
247
248 BEGIN_RING(chan, RING_3D(VIEWPORT_HORIZ(0)), 2);
249 OUT_RING (chan, (width << 16) | dstx);
250 OUT_RING (chan, (height << 16) | dsty);
251
252 BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
253 OUT_RING (chan, 0x3c);
254
255 nv50->dirty |= NVC0_NEW_FRAMEBUFFER;
256 }
257
258 static void
259 nvc0_clear_depth_stencil(struct pipe_context *pipe,
260 struct pipe_surface *dst,
261 unsigned clear_flags,
262 double depth,
263 unsigned stencil,
264 unsigned dstx, unsigned dsty,
265 unsigned width, unsigned height)
266 {
267 struct nvc0_context *nv50 = nvc0_context(pipe);
268 struct nvc0_screen *screen = nv50->screen;
269 struct nouveau_channel *chan = screen->base.channel;
270 struct nvc0_miptree *mt = nvc0_miptree(dst->texture);
271 struct nvc0_surface *sf = nvc0_surface(dst);
272 struct nouveau_bo *bo = mt->base.bo;
273 uint32_t mode = 0;
274
275 if (clear_flags & PIPE_CLEAR_DEPTH) {
276 BEGIN_RING(chan, RING_3D(CLEAR_DEPTH), 1);
277 OUT_RINGf (chan, depth);
278 mode |= NVC0_3D_CLEAR_BUFFERS_Z;
279 }
280
281 if (clear_flags & PIPE_CLEAR_STENCIL) {
282 BEGIN_RING(chan, RING_3D(CLEAR_STENCIL), 1);
283 OUT_RING (chan, stencil & 0xff);
284 mode |= NVC0_3D_CLEAR_BUFFERS_S;
285 }
286
287 if (MARK_RING(chan, 17, 2))
288 return;
289
290 BEGIN_RING(chan, RING_3D(ZETA_ADDRESS_HIGH), 5);
291 OUT_RELOCh(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
292 OUT_RELOCl(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
293 OUT_RING (chan, nvc0_format_table[dst->format].rt);
294 OUT_RING (chan, mt->level[sf->base.u.tex.level].tile_mode);
295 OUT_RING (chan, 0);
296 BEGIN_RING(chan, RING_3D(ZETA_ENABLE), 1);
297 OUT_RING (chan, 1);
298 BEGIN_RING(chan, RING_3D(ZETA_HORIZ), 3);
299 OUT_RING (chan, sf->width);
300 OUT_RING (chan, sf->height);
301 OUT_RING (chan, (1 << 16) | 1);
302
303 BEGIN_RING(chan, RING_3D(VIEWPORT_HORIZ(0)), 2);
304 OUT_RING (chan, (width << 16) | dstx);
305 OUT_RING (chan, (height << 16) | dsty);
306
307 BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
308 OUT_RING (chan, mode);
309
310 nv50->dirty |= NVC0_NEW_FRAMEBUFFER;
311 }
312
313 void
314 nvc0_clear(struct pipe_context *pipe, unsigned buffers,
315 const float *rgba, double depth, unsigned stencil)
316 {
317 struct nvc0_context *nvc0 = nvc0_context(pipe);
318 struct nouveau_channel *chan = nvc0->screen->base.channel;
319 struct pipe_framebuffer_state *fb = &nvc0->framebuffer;
320 unsigned i;
321 const unsigned dirty = nvc0->dirty;
322 uint32_t mode = 0;
323
324 /* don't need NEW_BLEND, COLOR_MASK doesn't affect CLEAR_BUFFERS */
325 nvc0->dirty &= NVC0_NEW_FRAMEBUFFER;
326 if (!nvc0_state_validate(nvc0))
327 return;
328
329 if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) {
330 BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4);
331 OUT_RINGf (chan, rgba[0]);
332 OUT_RINGf (chan, rgba[1]);
333 OUT_RINGf (chan, rgba[2]);
334 OUT_RINGf (chan, rgba[3]);
335 mode =
336 NVC0_3D_CLEAR_BUFFERS_R | NVC0_3D_CLEAR_BUFFERS_G |
337 NVC0_3D_CLEAR_BUFFERS_B | NVC0_3D_CLEAR_BUFFERS_A;
338 }
339
340 if (buffers & PIPE_CLEAR_DEPTH) {
341 BEGIN_RING(chan, RING_3D(CLEAR_DEPTH), 1);
342 OUT_RING (chan, fui(depth));
343 mode |= NVC0_3D_CLEAR_BUFFERS_Z;
344 }
345
346 if (buffers & PIPE_CLEAR_STENCIL) {
347 BEGIN_RING(chan, RING_3D(CLEAR_STENCIL), 1);
348 OUT_RING (chan, stencil & 0xff);
349 mode |= NVC0_3D_CLEAR_BUFFERS_S;
350 }
351
352 BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
353 OUT_RING (chan, mode);
354
355 for (i = 1; i < fb->nr_cbufs; i++) {
356 BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1);
357 OUT_RING (chan, (i << 6) | 0x3c);
358 }
359
360 nvc0->dirty = dirty & ~NVC0_NEW_FRAMEBUFFER;
361 }
362
363 void
364 nvc0_init_surface_functions(struct nvc0_context *nvc0)
365 {
366 nvc0->pipe.resource_copy_region = nvc0_resource_copy_region;
367 nvc0->pipe.clear_render_target = nvc0_clear_render_target;
368 nvc0->pipe.clear_depth_stencil = nvc0_clear_depth_stencil;
369 }
370
371