nouveau: rework and simplify nv04/nv05 driver a bit
[mesa.git] / src / gallium / drivers / nvfx / nvfx_state_fb.c
1 #include "nvfx_context.h"
2 #include "nvfx_resource.h"
3 #include "util/u_format.h"
4
5 static inline boolean
6 nvfx_surface_linear_target(struct pipe_surface* surf)
7 {
8 return !!((struct nvfx_miptree*)surf->texture)->linear_pitch;
9 }
10
11 static void
12 nvfx_surface_get_render_target(struct pipe_surface* surf,
13 struct nvfx_render_target* target)
14 {
15 struct nvfx_surface* ns = (struct nvfx_surface*)surf;
16
17 target->bo = ((struct nvfx_miptree*)surf->texture)->base.bo;
18 target->offset = ns->offset;
19 target->pitch = align(ns->pitch, 64);
20 assert(target->pitch);
21 }
22
23 void
24 nvfx_framebuffer_validate(struct nvfx_context *nvfx)
25 {
26 struct pipe_framebuffer_state *fb = &nvfx->framebuffer;
27 struct nouveau_channel *chan = nvfx->screen->base.channel;
28 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
29 uint32_t rt_enable, rt_format;
30 int i;
31 unsigned rt_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM;
32 unsigned w = fb->width;
33 unsigned h = fb->height;
34 int all_swizzled =1 , cb_format = 0;
35
36 /* do some sanity checks on the render target state and check if the targets
37 * are swizzled
38 */
39 nvfx->is_nv4x ? assert(fb->nr_cbufs <= 4) : assert(fb->nr_cbufs <= 1);
40 if(fb->nr_cbufs && fb->zsbuf)
41 assert(util_format_get_blocksize(fb->cbufs[0]->format) ==
42 util_format_get_blocksize(fb->zsbuf->format));
43
44 for(i = 0; i < fb->nr_cbufs; i++) {
45 if(cb_format)
46 assert(cb_format == fb->cbufs[i]->format);
47 else
48 cb_format = fb->cbufs[i]->format;
49
50 if(nvfx_surface_linear_target(fb->cbufs[i]))
51 all_swizzled = 0;
52 }
53
54 if(fb->zsbuf && nvfx_surface_linear_target(fb->zsbuf))
55 all_swizzled = 0;
56
57 rt_enable = (NV30_3D_RT_ENABLE_COLOR0 << fb->nr_cbufs) - 1;
58 if(rt_enable & (NV30_3D_RT_ENABLE_COLOR1 |
59 NV40_3D_RT_ENABLE_COLOR2 | NV40_3D_RT_ENABLE_COLOR3))
60 rt_enable |= NV30_3D_RT_ENABLE_MRT;
61
62 for(i = 0; i < fb->nr_cbufs; i++)
63 nvfx_surface_get_render_target(fb->cbufs[i], &nvfx->hw_rt[i]);
64
65 for(; i < 4; ++i)
66 nvfx->hw_rt[i].bo = NULL;
67
68 nvfx->hw_zeta.bo = NULL;
69
70 if(fb->zsbuf) {
71 nvfx_surface_get_render_target(fb->zsbuf, &nvfx->hw_zeta);
72 assert(util_format_get_stride(fb->zsbuf->format, fb->width) <=
73 nvfx->hw_zeta.pitch);
74 }
75
76 if(all_swizzled) {
77 /* hardware rounds down render target offset to 64 bytes,
78 * but surfaces with a size of 2x2 pixel (16bpp) or 1x1 pixel (32bpp)
79 * have an unaligned start address, for those two important square
80 * formats we can hack around this limitation by adjusting the viewport
81 */
82 if(nvfx->hw_rt[0].offset & 63) {
83 int delta = nvfx->hw_rt[0].offset & 63;
84 h = 2;
85 w = 16;
86 nvfx->viewport.translate[0] += delta /
87 (util_format_get_blocksize(fb->cbufs[0]->format) * 2);
88 nvfx->dirty |= NVFX_NEW_VIEWPORT;
89 }
90
91 rt_format = NV30_3D_RT_FORMAT_TYPE_SWIZZLED |
92 (util_logbase2(w) << NV30_3D_RT_FORMAT_LOG2_WIDTH__SHIFT) |
93 (util_logbase2(h) << NV30_3D_RT_FORMAT_LOG2_HEIGHT__SHIFT);
94 } else {
95 rt_format = NV30_3D_RT_FORMAT_TYPE_LINEAR;
96 }
97
98 if(fb->nr_cbufs > 0) {
99 switch (fb->cbufs[0]->format) {
100 case PIPE_FORMAT_B8G8R8X8_UNORM:
101 rt_format |= NV30_3D_RT_FORMAT_COLOR_X8R8G8B8;
102 break;
103 case PIPE_FORMAT_B8G8R8A8_UNORM:
104 case 0:
105 rt_format |= NV30_3D_RT_FORMAT_COLOR_A8R8G8B8;
106 break;
107 case PIPE_FORMAT_R8G8B8X8_UNORM:
108 rt_format |= NV30_3D_RT_FORMAT_COLOR_X8B8G8R8;
109 break;
110 case PIPE_FORMAT_R8G8B8A8_UNORM:
111 rt_format |= NV30_3D_RT_FORMAT_COLOR_A8B8G8R8;
112 break;
113 case PIPE_FORMAT_B5G6R5_UNORM:
114 rt_format |= NV30_3D_RT_FORMAT_COLOR_R5G6B5;
115 break;
116 case PIPE_FORMAT_R32G32B32A32_FLOAT:
117 rt_format |= NV30_3D_RT_FORMAT_COLOR_A32B32G32R32_FLOAT;
118 break;
119 case PIPE_FORMAT_R16G16B16A16_FLOAT:
120 rt_format |= NV30_3D_RT_FORMAT_COLOR_A16B16G16R16_FLOAT;
121 break;
122 default:
123 assert(0);
124 }
125 } else if(fb->zsbuf && util_format_get_blocksize(fb->zsbuf->format) == 2)
126 rt_format |= NV30_3D_RT_FORMAT_COLOR_R5G6B5;
127 else
128 rt_format |= NV30_3D_RT_FORMAT_COLOR_A8R8G8B8;
129
130 if(fb->zsbuf) {
131 switch (fb->zsbuf->format) {
132 case PIPE_FORMAT_Z16_UNORM:
133 rt_format |= NV30_3D_RT_FORMAT_ZETA_Z16;
134 break;
135 case PIPE_FORMAT_S8_UINT_Z24_UNORM:
136 case PIPE_FORMAT_X8Z24_UNORM:
137 case 0:
138 rt_format |= NV30_3D_RT_FORMAT_ZETA_Z24S8;
139 break;
140 default:
141 assert(0);
142 }
143 } else if(fb->nr_cbufs && util_format_get_blocksize(fb->cbufs[0]->format) == 2)
144 rt_format |= NV30_3D_RT_FORMAT_ZETA_Z16;
145 else
146 rt_format |= NV30_3D_RT_FORMAT_ZETA_Z24S8;
147
148 MARK_RING(chan, 42, 10);
149
150 if ((rt_enable & NV30_3D_RT_ENABLE_COLOR0) || fb->zsbuf) {
151 struct nvfx_render_target *rt0 = &nvfx->hw_rt[0];
152 uint32_t pitch;
153
154 if(!(rt_enable & NV30_3D_RT_ENABLE_COLOR0))
155 rt0 = &nvfx->hw_zeta;
156
157 pitch = rt0->pitch;
158
159 if(!nvfx->is_nv4x)
160 {
161 if (nvfx->hw_zeta.bo)
162 pitch |= (nvfx->hw_zeta.pitch << 16);
163 else
164 pitch |= (pitch << 16);
165 }
166
167 //printf("rendering to bo %p [%i] at offset %i with pitch %i\n", rt0->bo, rt0->bo->handle, rt0->offset, pitch);
168
169 BEGIN_RING(chan, eng3d, NV30_3D_DMA_COLOR0, 1);
170 OUT_RELOC(chan, rt0->bo, 0,
171 rt_flags | NOUVEAU_BO_OR,
172 chan->vram->handle, chan->gart->handle);
173 BEGIN_RING(chan, eng3d, NV30_3D_COLOR0_PITCH, 2);
174 OUT_RING(chan, pitch);
175 OUT_RELOC(chan, rt0->bo,
176 rt0->offset, rt_flags | NOUVEAU_BO_LOW,
177 0, 0);
178 }
179
180 if (rt_enable & NV30_3D_RT_ENABLE_COLOR1) {
181 BEGIN_RING(chan, eng3d, NV30_3D_DMA_COLOR1, 1);
182 OUT_RELOC(chan, nvfx->hw_rt[1].bo, 0,
183 rt_flags | NOUVEAU_BO_OR,
184 chan->vram->handle, chan->gart->handle);
185 BEGIN_RING(chan, eng3d, NV30_3D_COLOR1_OFFSET, 2);
186 OUT_RELOC(chan, nvfx->hw_rt[1].bo,
187 nvfx->hw_rt[1].offset, rt_flags | NOUVEAU_BO_LOW,
188 0, 0);
189 OUT_RING(chan, nvfx->hw_rt[1].pitch);
190 }
191
192 if(nvfx->is_nv4x)
193 {
194 if (rt_enable & NV40_3D_RT_ENABLE_COLOR2) {
195 BEGIN_RING(chan, eng3d, NV40_3D_DMA_COLOR2, 1);
196 OUT_RELOC(chan, nvfx->hw_rt[2].bo, 0,
197 rt_flags | NOUVEAU_BO_OR,
198 chan->vram->handle, chan->gart->handle);
199 BEGIN_RING(chan, eng3d, NV40_3D_COLOR2_OFFSET, 1);
200 OUT_RELOC(chan, nvfx->hw_rt[2].bo,
201 nvfx->hw_rt[2].offset, rt_flags | NOUVEAU_BO_LOW,
202 0, 0);
203 BEGIN_RING(chan, eng3d, NV40_3D_COLOR2_PITCH, 1);
204 OUT_RING(chan, nvfx->hw_rt[2].pitch);
205 }
206
207 if (rt_enable & NV40_3D_RT_ENABLE_COLOR3) {
208 BEGIN_RING(chan, eng3d, NV40_3D_DMA_COLOR3, 1);
209 OUT_RELOC(chan, nvfx->hw_rt[3].bo, 0,
210 rt_flags | NOUVEAU_BO_OR,
211 chan->vram->handle, chan->gart->handle);
212 BEGIN_RING(chan, eng3d, NV40_3D_COLOR3_OFFSET, 1);
213 OUT_RELOC(chan, nvfx->hw_rt[3].bo,
214 nvfx->hw_rt[3].offset, rt_flags | NOUVEAU_BO_LOW,
215 0, 0);
216 BEGIN_RING(chan, eng3d, NV40_3D_COLOR3_PITCH, 1);
217 OUT_RING(chan, nvfx->hw_rt[3].pitch);
218 }
219 }
220
221 if (fb->zsbuf) {
222 BEGIN_RING(chan, eng3d, NV30_3D_DMA_ZETA, 1);
223 OUT_RELOC(chan, nvfx->hw_zeta.bo, 0,
224 rt_flags | NOUVEAU_BO_OR,
225 chan->vram->handle, chan->gart->handle);
226 BEGIN_RING(chan, eng3d, NV30_3D_ZETA_OFFSET, 1);
227 /* TODO: reverse engineer LMA */
228 OUT_RELOC(chan, nvfx->hw_zeta.bo,
229 nvfx->hw_zeta.offset, rt_flags | NOUVEAU_BO_LOW, 0, 0);
230 if(nvfx->is_nv4x) {
231 BEGIN_RING(chan, eng3d, NV40_3D_ZETA_PITCH, 1);
232 OUT_RING(chan, nvfx->hw_zeta.pitch);
233 }
234 }
235 else if(nvfx->is_nv4x) {
236 BEGIN_RING(chan, eng3d, NV40_3D_ZETA_PITCH, 1);
237 OUT_RING(chan, 64);
238 }
239
240 BEGIN_RING(chan, eng3d, NV30_3D_RT_ENABLE, 1);
241 OUT_RING(chan, rt_enable);
242 BEGIN_RING(chan, eng3d, NV30_3D_RT_HORIZ, 3);
243 OUT_RING(chan, (w << 16) | 0);
244 OUT_RING(chan, (h << 16) | 0);
245 OUT_RING(chan, rt_format);
246 BEGIN_RING(chan, eng3d, NV30_3D_VIEWPORT_HORIZ, 2);
247 OUT_RING(chan, (w << 16) | 0);
248 OUT_RING(chan, (h << 16) | 0);
249 BEGIN_RING(chan, eng3d, NV30_3D_VIEWPORT_CLIP_HORIZ(0), 2);
250 OUT_RING(chan, ((w - 1) << 16) | 0);
251 OUT_RING(chan, ((h - 1) << 16) | 0);
252
253 if(!nvfx->is_nv4x) {
254 /* Wonder why this is needed, context should all be set to zero on init */
255 /* TODO: we can most likely remove this, after putting it in context init */
256 BEGIN_RING(chan, eng3d, NV30_3D_VIEWPORT_TX_ORIGIN, 1);
257 OUT_RING(chan, 0);
258 }
259 nvfx->relocs_needed &=~ NVFX_RELOCATE_FRAMEBUFFER;
260 }
261
262 void
263 nvfx_framebuffer_relocate(struct nvfx_context *nvfx)
264 {
265 struct nouveau_channel *chan = nvfx->screen->base.channel;
266 unsigned rt_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM;
267 rt_flags |= NOUVEAU_BO_DUMMY;
268 MARK_RING(chan, 20, 20);
269
270 #define DO_(var, pfx, name) \
271 if(var.bo) { \
272 OUT_RELOC(chan, var.bo, RING_3D(pfx##_3D_DMA_##name, 1), rt_flags, 0, 0); \
273 OUT_RELOC(chan, var.bo, 0, \
274 rt_flags | NOUVEAU_BO_OR, \
275 chan->vram->handle, chan->gart->handle); \
276 OUT_RELOC(chan, var.bo, RING_3D(pfx##_3D_##name##_OFFSET, 1), rt_flags, 0, 0); \
277 OUT_RELOC(chan, var.bo, \
278 var.offset, rt_flags | NOUVEAU_BO_LOW, \
279 0, 0); \
280 }
281
282 #define DO(pfx, num) DO_(nvfx->hw_rt[num], pfx, COLOR##num)
283 DO(NV30, 0);
284 DO(NV30, 1);
285 DO(NV40, 2);
286 DO(NV40, 3);
287
288 DO_(nvfx->hw_zeta, NV30, ZETA);
289 nvfx->relocs_needed &=~ NVFX_RELOCATE_FRAMEBUFFER;
290 }