c8ab7f690f30ddd9538798ce27735de57794c16f
[mesa.git] / src / gallium / winsys / drm / nouveau / nv50_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
7 nv50_format(enum pipe_format format)
8 {
9 switch (format) {
10 case PIPE_FORMAT_A8R8G8B8_UNORM:
11 case PIPE_FORMAT_Z24S8_UNORM:
12 return NV50_2D_DST_FORMAT_32BPP;
13 case PIPE_FORMAT_X8R8G8B8_UNORM:
14 return NV50_2D_DST_FORMAT_24BPP;
15 case PIPE_FORMAT_R5G6B5_UNORM:
16 return NV50_2D_DST_FORMAT_16BPP;
17 case PIPE_FORMAT_A8_UNORM:
18 return NV50_2D_DST_FORMAT_8BPP;
19 default:
20 return -1;
21 }
22 }
23
24 static int
25 nv50_surface_set(struct nouveau_context *nv, struct pipe_surface *surf, int dst)
26 {
27 struct nouveau_channel *chan = nv->nvc->channel;
28 struct nouveau_grobj *eng2d = nv->nvc->Nv2D;
29 struct nouveau_bo *bo = nouveau_buffer(surf->buffer)->bo;
30 int surf_format, mthd = dst ? NV50_2D_DST_FORMAT : NV50_2D_SRC_FORMAT;
31 int flags = NOUVEAU_BO_VRAM | (dst ? NOUVEAU_BO_WR : NOUVEAU_BO_RD);
32
33 surf_format = nv50_format(surf->format);
34 if (surf_format < 0)
35 return 1;
36
37 if (!nouveau_bo(bo)->tiled) {
38 BEGIN_RING(chan, eng2d, mthd, 2);
39 OUT_RING (chan, surf_format);
40 OUT_RING (chan, 1);
41 BEGIN_RING(chan, eng2d, mthd + 0x14, 5);
42 OUT_RING (chan, surf->stride);
43 OUT_RING (chan, surf->width);
44 OUT_RING (chan, surf->height);
45 OUT_RELOCh(chan, bo, surf->offset, flags);
46 OUT_RELOCl(chan, bo, surf->offset, flags);
47 } else {
48 BEGIN_RING(chan, eng2d, mthd, 5);
49 OUT_RING (chan, surf_format);
50 OUT_RING (chan, 0);
51 OUT_RING (chan, 0);
52 OUT_RING (chan, 1);
53 OUT_RING (chan, 0);
54 BEGIN_RING(chan, eng2d, mthd + 0x18, 4);
55 OUT_RING (chan, surf->width);
56 OUT_RING (chan, surf->height);
57 OUT_RELOCh(chan, bo, surf->offset, flags);
58 OUT_RELOCl(chan, bo, surf->offset, flags);
59 }
60
61 #if 0
62 if (dst) {
63 BEGIN_RING(chan, eng2d, NV50_2D_CLIP_X, 4);
64 OUT_RING (chan, 0);
65 OUT_RING (chan, 0);
66 OUT_RING (chan, surf->width);
67 OUT_RING (chan, surf->height);
68 }
69 #endif
70
71 return 0;
72 }
73
74 static int
75 nv50_surface_copy_prep(struct nouveau_context *nv,
76 struct pipe_surface *dst, struct pipe_surface *src)
77 {
78 int ret;
79
80 assert(src->format == dst->format);
81
82 ret = nv50_surface_set(nv, dst, 1);
83 if (ret)
84 return ret;
85
86 ret = nv50_surface_set(nv, src, 0);
87 if (ret)
88 return ret;
89
90 return 0;
91 }
92
93 static void
94 nv50_surface_copy(struct nouveau_context *nv, unsigned dx, unsigned dy,
95 unsigned sx, unsigned sy, unsigned w, unsigned h)
96 {
97 struct nouveau_channel *chan = nv->nvc->channel;
98 struct nouveau_grobj *eng2d = nv->nvc->Nv2D;
99
100 BEGIN_RING(chan, eng2d, 0x088c, 1);
101 OUT_RING (chan, 0);
102 BEGIN_RING(chan, eng2d, NV50_2D_BLIT_DST_X, 4);
103 OUT_RING (chan, dx);
104 OUT_RING (chan, dy);
105 OUT_RING (chan, w);
106 OUT_RING (chan, h);
107 BEGIN_RING(chan, eng2d, 0x08c0, 4);
108 OUT_RING (chan, 0);
109 OUT_RING (chan, 1);
110 OUT_RING (chan, 0);
111 OUT_RING (chan, 1);
112 BEGIN_RING(chan, eng2d, 0x08d0, 4);
113 OUT_RING (chan, 0);
114 OUT_RING (chan, sx);
115 OUT_RING (chan, 0);
116 OUT_RING (chan, sy);
117 }
118
119 static void
120 nv50_surface_copy_done(struct nouveau_context *nv)
121 {
122 FIRE_RING(nv->nvc->channel);
123 }
124
125 static int
126 nv50_surface_fill(struct nouveau_context *nv, struct pipe_surface *dst,
127 unsigned dx, unsigned dy, unsigned w, unsigned h,
128 unsigned value)
129 {
130 struct nouveau_channel *chan = nv->nvc->channel;
131 struct nouveau_grobj *eng2d = nv->nvc->Nv2D;
132 int rect_format, ret;
133
134 rect_format = nv50_format(dst->format);
135 if (rect_format < 0)
136 return 1;
137
138 ret = nv50_surface_set(nv, dst, 1);
139 if (ret)
140 return ret;
141
142 BEGIN_RING(chan, eng2d, 0x0580, 3);
143 OUT_RING (chan, 4);
144 OUT_RING (chan, rect_format);
145 OUT_RING (chan, value);
146
147 BEGIN_RING(chan, eng2d, NV50_2D_RECT_X1, 4);
148 OUT_RING (chan, dx);
149 OUT_RING (chan, dy);
150 OUT_RING (chan, dx + w);
151 OUT_RING (chan, dy + h);
152
153 FIRE_RING(chan);
154 return 0;
155 }
156
157 int
158 nouveau_surface_channel_create_nv50(struct nouveau_channel_context *nvc)
159 {
160 struct nouveau_channel *chan = nvc->channel;
161 struct nouveau_grobj *eng2d = NULL;
162 int ret;
163
164 ret = nouveau_grobj_alloc(chan, nvc->next_handle++, NV50_2D, &eng2d);
165 if (ret)
166 return ret;
167 nvc->Nv2D = eng2d;
168
169 BIND_RING (chan, eng2d, nvc->next_subchannel++);
170 BEGIN_RING(chan, eng2d, NV50_2D_DMA_NOTIFY, 4);
171 OUT_RING (chan, nvc->sync_notifier->handle);
172 OUT_RING (chan, chan->vram->handle);
173 OUT_RING (chan, chan->vram->handle);
174 OUT_RING (chan, chan->vram->handle);
175 BEGIN_RING(chan, eng2d, NV50_2D_OPERATION, 1);
176 OUT_RING (chan, NV50_2D_OPERATION_SRCCOPY);
177 BEGIN_RING(chan, eng2d, 0x0290, 1);
178 OUT_RING (chan, 0);
179 BEGIN_RING(chan, eng2d, 0x0888, 1);
180 OUT_RING (chan, 1);
181
182 return 0;
183 }
184
185 int
186 nouveau_surface_init_nv50(struct nouveau_context *nv)
187 {
188 nv->surface_copy_prep = nv50_surface_copy_prep;
189 nv->surface_copy = nv50_surface_copy;
190 nv->surface_copy_done = nv50_surface_copy_done;
191 nv->surface_fill = nv50_surface_fill;
192 return 0;
193 }
194