Merge commit 'origin/master' into gallium-0.2
[mesa.git] / src / gallium / winsys / drm / nouveau / nv04_surface.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_format.h"
3
4 #include "nouveau_context.h"
5
6 static INLINE int log2i(int i)
7 {
8 int r = 0;
9
10 if (i & 0xffff0000) {
11 i >>= 16;
12 r += 16;
13 }
14 if (i & 0x0000ff00) {
15 i >>= 8;
16 r += 8;
17 }
18 if (i & 0x000000f0) {
19 i >>= 4;
20 r += 4;
21 }
22 if (i & 0x0000000c) {
23 i >>= 2;
24 r += 2;
25 }
26 if (i & 0x00000002) {
27 r += 1;
28 }
29 return r;
30 }
31
32 static INLINE int
33 nv04_surface_format(enum pipe_format format)
34 {
35 switch (format) {
36 case PIPE_FORMAT_A8_UNORM:
37 return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8;
38 case PIPE_FORMAT_R16_SNORM:
39 case PIPE_FORMAT_R5G6B5_UNORM:
40 return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5;
41 case PIPE_FORMAT_X8R8G8B8_UNORM:
42 case PIPE_FORMAT_A8R8G8B8_UNORM:
43 return NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8;
44 case PIPE_FORMAT_Z24S8_UNORM:
45 return NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
46 default:
47 return -1;
48 }
49 }
50
51 static INLINE int
52 nv04_rect_format(enum pipe_format format)
53 {
54 switch (format) {
55 case PIPE_FORMAT_A8_UNORM:
56 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
57 case PIPE_FORMAT_R5G6B5_UNORM:
58 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
59 case PIPE_FORMAT_A8R8G8B8_UNORM:
60 case PIPE_FORMAT_Z24S8_UNORM:
61 return NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
62 default:
63 return -1;
64 }
65 }
66
67 static INLINE int
68 nv04_scaled_image_format(enum pipe_format format)
69 {
70 switch (format) {
71 case PIPE_FORMAT_A1R5G5B5_UNORM:
72 return NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A1R5G5B5;
73 case PIPE_FORMAT_A8R8G8B8_UNORM:
74 return NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A8R8G8B8;
75 case PIPE_FORMAT_X8R8G8B8_UNORM:
76 return NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_X8R8G8B8;
77 case PIPE_FORMAT_R5G6B5_UNORM:
78 case PIPE_FORMAT_R16_SNORM:
79 return NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_R5G6B5;
80 default:
81 return -1;
82 }
83 }
84
85 static void
86 nv04_surface_copy_swizzle(struct nouveau_context *nv, unsigned dx, unsigned dy,
87 unsigned sx, unsigned sy, unsigned w, unsigned h)
88 {
89 struct nouveau_channel *chan = nv->nvc->channel;
90 struct pipe_surface *dst = nv->surf_dst;
91 struct pipe_surface *src = nv->surf_src;
92
93 /* POT or GTFO */
94 assert(!(w & (w - 1)) && !(h & (h - 1)));
95
96 BEGIN_RING(chan, nv->nvc->NvSwzSurf, NV04_SWIZZLED_SURFACE_DMA_IMAGE, 1);
97 OUT_RELOCo(chan, nouveau_buffer(dst->buffer)->bo,
98 NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
99
100 BEGIN_RING(chan, nv->nvc->NvSwzSurf, NV04_SWIZZLED_SURFACE_FORMAT, 2);
101 OUT_RING (chan, nv04_surface_format(dst->format) |
102 log2i(w) << NV04_SWIZZLED_SURFACE_FORMAT_BASE_SIZE_U_SHIFT |
103 log2i(h) << NV04_SWIZZLED_SURFACE_FORMAT_BASE_SIZE_V_SHIFT);
104 OUT_RELOCl(chan, nouveau_buffer(dst->buffer)->bo, dst->offset,
105 NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
106
107 BEGIN_RING(chan, nv->nvc->NvSIFM, NV04_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE, 1);
108 OUT_RELOCo(chan, nouveau_buffer(src->buffer)->bo,
109 NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
110 BEGIN_RING(chan, nv->nvc->NvSIFM, NV04_SCALED_IMAGE_FROM_MEMORY_SURFACE, 1);
111 OUT_RING (chan, nv->nvc->NvSwzSurf->handle);
112
113 BEGIN_RING(chan, nv->nvc->NvSIFM, NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION, 9);
114 OUT_RING (chan, NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION_TRUNCATE);
115 OUT_RING (chan, nv04_scaled_image_format(src->format));
116 OUT_RING (chan, NV04_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY);
117 OUT_RING (chan, 0);
118 OUT_RING (chan, h << 16 | w);
119 OUT_RING (chan, 0);
120 OUT_RING (chan, h << 16 | w);
121 OUT_RING (chan, 1 << 20);
122 OUT_RING (chan, 1 << 20);
123 BEGIN_RING(chan, nv->nvc->NvSIFM, NV04_SCALED_IMAGE_FROM_MEMORY_SIZE, 4);
124 OUT_RING (chan, h << 16 | w);
125 OUT_RING (chan, src->stride |
126 NV04_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER |
127 NV04_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_POINT_SAMPLE);
128 OUT_RELOCl(chan, nouveau_buffer(src->buffer)->bo, src->offset,
129 NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
130 OUT_RING (chan, 0);
131 }
132
133 static void
134 nv04_surface_copy_m2mf(struct nouveau_context *nv, unsigned dx, unsigned dy,
135 unsigned sx, unsigned sy, unsigned w, unsigned h)
136 {
137 struct nouveau_channel *chan = nv->nvc->channel;
138 struct pipe_surface *dst = nv->surf_dst;
139 struct pipe_surface *src = nv->surf_src;
140 unsigned dst_offset, src_offset;
141
142 dst_offset = dst->offset + (dy * dst->stride) + (dx * dst->block.size);
143 src_offset = src->offset + (sy * src->stride) + (sx * src->block.size);
144
145 while (h) {
146 int count = (h > 2047) ? 2047 : h;
147
148 BEGIN_RING(chan, nv->nvc->NvM2MF,
149 NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
150 OUT_RELOCl(chan, nouveau_buffer(src->buffer)->bo, src_offset,
151 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD);
152 OUT_RELOCl(chan, nouveau_buffer(dst->buffer)->bo, dst_offset,
153 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_WR);
154 OUT_RING (chan, src->stride);
155 OUT_RING (chan, dst->stride);
156 OUT_RING (chan, w * src->block.size);
157 OUT_RING (chan, count);
158 OUT_RING (chan, 0x0101);
159 OUT_RING (chan, 0);
160
161 h -= count;
162 src_offset += src->stride * count;
163 dst_offset += dst->stride * count;
164 }
165 }
166
167 static void
168 nv04_surface_copy_blit(struct nouveau_context *nv, unsigned dx, unsigned dy,
169 unsigned sx, unsigned sy, unsigned w, unsigned h)
170 {
171 struct nouveau_channel *chan = nv->nvc->channel;
172
173 BEGIN_RING(chan, nv->nvc->NvImageBlit, 0x0300, 3);
174 OUT_RING (chan, (sy << 16) | sx);
175 OUT_RING (chan, (dy << 16) | dx);
176 OUT_RING (chan, ( h << 16) | w);
177 }
178
179 static int
180 nv04_surface_copy_prep(struct nouveau_context *nv, struct pipe_surface *dst,
181 struct pipe_surface *src)
182 {
183 struct nouveau_channel *chan = nv->nvc->channel;
184 int format;
185
186 if (src->format != dst->format)
187 return 1;
188
189 /* Setup transfer to swizzle the texture to vram if needed */
190 /* FIXME/TODO: check proper limits of this operation */
191 if (src->texture && dst->texture) {
192 unsigned int src_linear = src->texture->tex_usage &
193 NOUVEAU_TEXTURE_USAGE_LINEAR;
194 unsigned int dst_linear = dst->texture->tex_usage &
195 NOUVEAU_TEXTURE_USAGE_LINEAR;
196 if (src_linear ^ dst_linear) {
197 nv->surface_copy = nv04_surface_copy_swizzle;
198 nv->surf_dst = dst;
199 nv->surf_src = src;
200 return 0;
201 }
202 }
203
204 /* NV_CONTEXT_SURFACES_2D has buffer alignment restrictions, fallback
205 * to NV_MEMORY_TO_MEMORY_FORMAT in this case.
206 */
207 if ((src->offset & 63) || (dst->offset & 63)) {
208 BEGIN_RING(nv->nvc->channel, nv->nvc->NvM2MF,
209 NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
210 OUT_RELOCo(chan, nouveau_buffer(src->buffer)->bo,
211 NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
212 OUT_RELOCo(chan, nouveau_buffer(dst->buffer)->bo,
213 NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
214
215 nv->surface_copy = nv04_surface_copy_m2mf;
216 nv->surf_dst = dst;
217 nv->surf_src = src;
218 return 0;
219
220 }
221
222 if ((format = nv04_surface_format(dst->format)) < 0) {
223 NOUVEAU_ERR("Bad surface format 0x%x\n", dst->format);
224 return 1;
225 }
226 nv->surface_copy = nv04_surface_copy_blit;
227
228 BEGIN_RING(chan, nv->nvc->NvCtxSurf2D,
229 NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
230 OUT_RELOCo(chan, nouveau_buffer(src->buffer)->bo,
231 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
232 OUT_RELOCo(chan, nouveau_buffer(dst->buffer)->bo,
233 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
234
235 BEGIN_RING(chan, nv->nvc->NvCtxSurf2D,
236 NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
237 OUT_RING (chan, format);
238 OUT_RING (chan, (dst->stride << 16) | src->stride);
239 OUT_RELOCl(chan, nouveau_buffer(src->buffer)->bo, src->offset,
240 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
241 OUT_RELOCl(chan, nouveau_buffer(dst->buffer)->bo, dst->offset,
242 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
243
244 return 0;
245 }
246
247 static void
248 nv04_surface_copy_done(struct nouveau_context *nv)
249 {
250 FIRE_RING(nv->nvc->channel);
251 }
252
253 static int
254 nv04_surface_fill(struct nouveau_context *nv, struct pipe_surface *dst,
255 unsigned dx, unsigned dy, unsigned w, unsigned h,
256 unsigned value)
257 {
258 struct nouveau_channel *chan = nv->nvc->channel;
259 struct nouveau_grobj *surf2d = nv->nvc->NvCtxSurf2D;
260 struct nouveau_grobj *rect = nv->nvc->NvGdiRect;
261 int cs2d_format, gdirect_format;
262
263 if ((cs2d_format = nv04_surface_format(dst->format)) < 0) {
264 NOUVEAU_ERR("Bad format = %d\n", dst->format);
265 return 1;
266 }
267
268 if ((gdirect_format = nv04_rect_format(dst->format)) < 0) {
269 NOUVEAU_ERR("Bad format = %d\n", dst->format);
270 return 1;
271 }
272
273 BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
274 OUT_RELOCo(chan, nouveau_buffer(dst->buffer)->bo,
275 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
276 OUT_RELOCo(chan, nouveau_buffer(dst->buffer)->bo,
277 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
278 BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
279 OUT_RING (chan, cs2d_format);
280 OUT_RING (chan, (dst->stride << 16) | dst->stride);
281 OUT_RELOCl(chan, nouveau_buffer(dst->buffer)->bo, dst->offset,
282 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
283 OUT_RELOCl(chan, nouveau_buffer(dst->buffer)->bo, dst->offset,
284 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
285
286 BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
287 OUT_RING (chan, gdirect_format);
288 BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
289 OUT_RING (chan, value);
290 BEGIN_RING(chan, rect,
291 NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
292 OUT_RING (chan, (dx << 16) | dy);
293 OUT_RING (chan, ( w << 16) | h);
294
295 FIRE_RING(chan);
296 return 0;
297 }
298
299 int
300 nouveau_surface_channel_create_nv04(struct nouveau_channel_context *nvc)
301 {
302 struct nouveau_channel *chan = nvc->channel;
303 unsigned chipset = nvc->channel->device->chipset, class;
304 int ret;
305
306 if ((ret = nouveau_grobj_alloc(chan, nvc->next_handle++, 0x39,
307 &nvc->NvM2MF))) {
308 NOUVEAU_ERR("Error creating m2mf object: %d\n", ret);
309 return 1;
310 }
311 BIND_RING (chan, nvc->NvM2MF, nvc->next_subchannel++);
312 BEGIN_RING(chan, nvc->NvM2MF,
313 NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
314 OUT_RING (chan, nvc->sync_notifier->handle);
315
316 class = chipset < 0x10 ? NV04_CONTEXT_SURFACES_2D :
317 NV10_CONTEXT_SURFACES_2D;
318 if ((ret = nouveau_grobj_alloc(chan, nvc->next_handle++, class,
319 &nvc->NvCtxSurf2D))) {
320 NOUVEAU_ERR("Error creating 2D surface object: %d\n", ret);
321 return 1;
322 }
323 BIND_RING (chan, nvc->NvCtxSurf2D, nvc->next_subchannel++);
324 BEGIN_RING(chan, nvc->NvCtxSurf2D,
325 NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
326 OUT_RING (chan, nvc->channel->vram->handle);
327 OUT_RING (chan, nvc->channel->vram->handle);
328
329 class = chipset < 0x10 ? NV04_IMAGE_BLIT : NV12_IMAGE_BLIT;
330 if ((ret = nouveau_grobj_alloc(chan, nvc->next_handle++, class,
331 &nvc->NvImageBlit))) {
332 NOUVEAU_ERR("Error creating blit object: %d\n", ret);
333 return 1;
334 }
335 BIND_RING (chan, nvc->NvImageBlit, nvc->next_subchannel++);
336 BEGIN_RING(chan, nvc->NvImageBlit, NV04_IMAGE_BLIT_DMA_NOTIFY, 1);
337 OUT_RING (chan, nvc->sync_notifier->handle);
338 BEGIN_RING(chan, nvc->NvImageBlit, NV04_IMAGE_BLIT_SURFACE, 1);
339 OUT_RING (chan, nvc->NvCtxSurf2D->handle);
340 BEGIN_RING(chan, nvc->NvImageBlit, NV04_IMAGE_BLIT_OPERATION, 1);
341 OUT_RING (chan, NV04_IMAGE_BLIT_OPERATION_SRCCOPY);
342
343 class = NV04_GDI_RECTANGLE_TEXT;
344 if ((ret = nouveau_grobj_alloc(chan, nvc->next_handle++, class,
345 &nvc->NvGdiRect))) {
346 NOUVEAU_ERR("Error creating rect object: %d\n", ret);
347 return 1;
348 }
349 BIND_RING (chan, nvc->NvGdiRect, nvc->next_subchannel++);
350 BEGIN_RING(chan, nvc->NvGdiRect, NV04_GDI_RECTANGLE_TEXT_DMA_NOTIFY, 1);
351 OUT_RING (chan, nvc->sync_notifier->handle);
352 BEGIN_RING(chan, nvc->NvGdiRect, NV04_GDI_RECTANGLE_TEXT_SURFACE, 1);
353 OUT_RING (chan, nvc->NvCtxSurf2D->handle);
354 BEGIN_RING(chan, nvc->NvGdiRect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
355 OUT_RING (chan, NV04_GDI_RECTANGLE_TEXT_OPERATION_SRCCOPY);
356 BEGIN_RING(chan, nvc->NvGdiRect,
357 NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT, 1);
358 OUT_RING (chan, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE);
359
360 switch (chipset & 0xf0) {
361 case 0x00:
362 case 0x10:
363 class = NV04_SWIZZLED_SURFACE;
364 break;
365 case 0x20:
366 class = NV20_SWIZZLED_SURFACE;
367 break;
368 case 0x30:
369 class = NV30_SWIZZLED_SURFACE;
370 break;
371 case 0x40:
372 case 0x60:
373 class = NV40_SWIZZLED_SURFACE;
374 break;
375 default:
376 /* Famous last words: this really can't happen.. */
377 assert(0);
378 break;
379 }
380
381 ret = nouveau_grobj_alloc(chan, nvc->next_handle++, class,
382 &nvc->NvSwzSurf);
383 if (ret) {
384 NOUVEAU_ERR("Error creating swizzled surface: %d\n", ret);
385 return 1;
386 }
387
388 BIND_RING (chan, nvc->NvSwzSurf, nvc->next_subchannel++);
389
390 if (chipset < 0x10) {
391 class = NV04_SCALED_IMAGE_FROM_MEMORY;
392 } else
393 if (chipset < 0x40) {
394 class = NV10_SCALED_IMAGE_FROM_MEMORY;
395 } else {
396 class = NV40_SCALED_IMAGE_FROM_MEMORY;
397 }
398
399 ret = nouveau_grobj_alloc(chan, nvc->next_handle++, class,
400 &nvc->NvSIFM);
401 if (ret) {
402 NOUVEAU_ERR("Error creating scaled image object: %d\n", ret);
403 return 1;
404 }
405
406 BIND_RING (chan, nvc->NvSIFM, nvc->next_subchannel++);
407
408 return 0;
409 }
410
411 int
412 nouveau_surface_init_nv04(struct nouveau_context *nv)
413 {
414 nv->surface_copy_prep = nv04_surface_copy_prep;
415 nv->surface_copy = nv04_surface_copy_blit;
416 nv->surface_copy_done = nv04_surface_copy_done;
417 nv->surface_fill = nv04_surface_fill;
418 return 0;
419 }
420