nvfx: new 2D: use new 2D engine in Gallium
[mesa.git] / src / gallium / drivers / nvfx / nvfx_state_fb.c
1 #include "nvfx_context.h"
2 #include "nvfx_resource.h"
3 #include "nouveau/nouveau_util.h"
4
5 void
6 nvfx_state_framebuffer_validate(struct nvfx_context *nvfx)
7 {
8 struct pipe_framebuffer_state *fb = &nvfx->framebuffer;
9 struct nouveau_channel *chan = nvfx->screen->base.channel;
10 uint32_t rt_enable = 0, rt_format = 0;
11 int i, colour_format = 0, zeta_format = 0;
12 int depth_only = 0;
13 unsigned rt_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM;
14 unsigned w = fb->width;
15 unsigned h = fb->height;
16 int colour_bits = 32, zeta_bits = 32;
17
18 if(!nvfx->is_nv4x)
19 assert(fb->nr_cbufs <= 2);
20 else
21 assert(fb->nr_cbufs <= 4);
22
23 for (i = 0; i < fb->nr_cbufs; i++) {
24 if (colour_format)
25 assert(colour_format == fb->cbufs[i]->format);
26 else
27 colour_format = fb->cbufs[i]->format;
28
29 rt_enable |= (NV34TCL_RT_ENABLE_COLOR0 << i);
30 nvfx->hw_rt[i].bo = ((struct nvfx_miptree*)fb->cbufs[i]->texture)->base.bo;
31 nvfx->hw_rt[i].offset = fb->cbufs[i]->offset;
32 nvfx->hw_rt[i].pitch = ((struct nvfx_surface *)fb->cbufs[i])->pitch;
33 }
34 for(; i < 4; ++i)
35 nvfx->hw_rt[i].bo = 0;
36
37 if (rt_enable & (NV34TCL_RT_ENABLE_COLOR1 |
38 NV40TCL_RT_ENABLE_COLOR2 | NV40TCL_RT_ENABLE_COLOR3))
39 rt_enable |= NV34TCL_RT_ENABLE_MRT;
40
41 if (fb->zsbuf) {
42 zeta_format = fb->zsbuf->format;
43 nvfx->hw_zeta.bo = ((struct nvfx_miptree*)fb->zsbuf->texture)->base.bo;
44 nvfx->hw_zeta.offset = fb->zsbuf->offset;
45 nvfx->hw_zeta.pitch = ((struct nvfx_surface *)fb->zsbuf)->pitch;
46 }
47 else
48 nvfx->hw_zeta.bo = 0;
49
50 if (rt_enable & (NV34TCL_RT_ENABLE_COLOR0 | NV34TCL_RT_ENABLE_COLOR1 |
51 NV40TCL_RT_ENABLE_COLOR2 | NV40TCL_RT_ENABLE_COLOR3)) {
52 /* Render to at least a colour buffer */
53 if (!(fb->cbufs[0]->texture->flags & NVFX_RESOURCE_FLAG_LINEAR)) {
54 assert(!(fb->width & (fb->width - 1)) && !(fb->height & (fb->height - 1)));
55 for (i = 1; i < fb->nr_cbufs; i++)
56 assert(!(fb->cbufs[i]->texture->flags & NVFX_RESOURCE_FLAG_LINEAR));
57
58 rt_format = NV34TCL_RT_FORMAT_TYPE_SWIZZLED |
59 (log2i(fb->cbufs[0]->width) << NV34TCL_RT_FORMAT_LOG2_WIDTH_SHIFT) |
60 (log2i(fb->cbufs[0]->height) << NV34TCL_RT_FORMAT_LOG2_HEIGHT_SHIFT);
61 }
62 else
63 rt_format = NV34TCL_RT_FORMAT_TYPE_LINEAR;
64 } else if (fb->zsbuf) {
65 depth_only = 1;
66
67 /* Render to depth buffer only */
68 if (!(fb->zsbuf->texture->flags & NVFX_RESOURCE_FLAG_LINEAR)) {
69 assert(!(fb->width & (fb->width - 1)) && !(fb->height & (fb->height - 1)));
70
71 rt_format = NV34TCL_RT_FORMAT_TYPE_SWIZZLED |
72 (log2i(fb->zsbuf->width) << NV34TCL_RT_FORMAT_LOG2_WIDTH_SHIFT) |
73 (log2i(fb->zsbuf->height) << NV34TCL_RT_FORMAT_LOG2_HEIGHT_SHIFT);
74 }
75 else
76 rt_format = NV34TCL_RT_FORMAT_TYPE_LINEAR;
77 } else {
78 return;
79 }
80
81 switch (colour_format) {
82 case PIPE_FORMAT_B8G8R8X8_UNORM:
83 rt_format |= NV34TCL_RT_FORMAT_COLOR_X8R8G8B8;
84 break;
85 case PIPE_FORMAT_B8G8R8A8_UNORM:
86 case 0:
87 rt_format |= NV34TCL_RT_FORMAT_COLOR_A8R8G8B8;
88 break;
89 case PIPE_FORMAT_B5G6R5_UNORM:
90 rt_format |= NV34TCL_RT_FORMAT_COLOR_R5G6B5;
91 colour_bits = 16;
92 break;
93 default:
94 assert(0);
95 }
96
97 switch (zeta_format) {
98 case PIPE_FORMAT_Z16_UNORM:
99 rt_format |= NV34TCL_RT_FORMAT_ZETA_Z16;
100 zeta_bits = 16;
101 break;
102 case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
103 case PIPE_FORMAT_X8Z24_UNORM:
104 case 0:
105 rt_format |= NV34TCL_RT_FORMAT_ZETA_Z24S8;
106 break;
107 default:
108 assert(0);
109 }
110
111 if ((!nvfx->is_nv4x) && colour_bits > zeta_bits) {
112 /* TODO: does this limitation really exist?
113 TODO: can it be worked around somehow? */
114 assert(0);
115 }
116
117 if ((rt_enable & NV34TCL_RT_ENABLE_COLOR0)
118 || ((!nvfx->is_nv4x) && depth_only)) {
119 struct nvfx_render_target *rt0 = (depth_only ? &nvfx->hw_zeta : &nvfx->hw_rt[0]);
120 uint32_t pitch = rt0->pitch;
121
122 if(!nvfx->is_nv4x)
123 {
124 if (nvfx->hw_zeta.bo) {
125 pitch |= (nvfx->hw_zeta.pitch << 16);
126 } else {
127 pitch |= (pitch << 16);
128 }
129 }
130
131 OUT_RING(chan, RING_3D(NV34TCL_DMA_COLOR0, 1));
132 OUT_RELOC(chan, rt0->bo, 0,
133 rt_flags | NOUVEAU_BO_OR,
134 chan->vram->handle, chan->gart->handle);
135 OUT_RING(chan, RING_3D(NV34TCL_COLOR0_PITCH, 2));
136 OUT_RING(chan, pitch);
137 OUT_RELOC(chan, rt0->bo,
138 rt0->offset, rt_flags | NOUVEAU_BO_LOW,
139 0, 0);
140 }
141
142 if (rt_enable & NV34TCL_RT_ENABLE_COLOR1) {
143 OUT_RING(chan, RING_3D(NV34TCL_DMA_COLOR1, 1));
144 OUT_RELOC(chan, nvfx->hw_rt[1].bo, 0,
145 rt_flags | NOUVEAU_BO_OR,
146 chan->vram->handle, chan->gart->handle);
147 OUT_RING(chan, RING_3D(NV34TCL_COLOR1_OFFSET, 2));
148 OUT_RELOC(chan, nvfx->hw_rt[1].bo,
149 nvfx->hw_rt[1].offset, rt_flags | NOUVEAU_BO_LOW,
150 0, 0);
151 OUT_RING(chan, nvfx->hw_rt[1].pitch);
152 }
153
154 if(nvfx->is_nv4x)
155 {
156 if (rt_enable & NV40TCL_RT_ENABLE_COLOR2) {
157 OUT_RING(chan, RING_3D(NV40TCL_DMA_COLOR2, 1));
158 OUT_RELOC(chan, nvfx->hw_rt[2].bo, 0,
159 rt_flags | NOUVEAU_BO_OR,
160 chan->vram->handle, chan->gart->handle);
161 OUT_RING(chan, RING_3D(NV40TCL_COLOR2_OFFSET, 1));
162 OUT_RELOC(chan, nvfx->hw_rt[2].bo,
163 nvfx->hw_rt[2].offset, rt_flags | NOUVEAU_BO_LOW,
164 0, 0);
165 OUT_RING(chan, RING_3D(NV40TCL_COLOR2_PITCH, 1));
166 OUT_RING(chan, nvfx->hw_rt[2].pitch);
167 }
168
169 if (rt_enable & NV40TCL_RT_ENABLE_COLOR3) {
170 OUT_RING(chan, RING_3D(NV40TCL_DMA_COLOR3, 1));
171 OUT_RELOC(chan, nvfx->hw_rt[3].bo, 0,
172 rt_flags | NOUVEAU_BO_OR,
173 chan->vram->handle, chan->gart->handle);
174 OUT_RING(chan, RING_3D(NV40TCL_COLOR3_OFFSET, 1));
175 OUT_RELOC(chan, nvfx->hw_rt[3].bo,
176 nvfx->hw_rt[3].offset, rt_flags | NOUVEAU_BO_LOW,
177 0, 0);
178 OUT_RING(chan, RING_3D(NV40TCL_COLOR3_PITCH, 1));
179 OUT_RING(chan, nvfx->hw_rt[3].pitch);
180 }
181 }
182
183 if (zeta_format) {
184 OUT_RING(chan, RING_3D(NV34TCL_DMA_ZETA, 1));
185 OUT_RELOC(chan, nvfx->hw_zeta.bo, 0,
186 rt_flags | NOUVEAU_BO_OR,
187 chan->vram->handle, chan->gart->handle);
188 OUT_RING(chan, RING_3D(NV34TCL_ZETA_OFFSET, 1));
189 /* TODO: reverse engineer LMA */
190 OUT_RELOC(chan, nvfx->hw_zeta.bo,
191 nvfx->hw_zeta.offset, rt_flags | NOUVEAU_BO_LOW, 0, 0);
192 if(nvfx->is_nv4x) {
193 OUT_RING(chan, RING_3D(NV40TCL_ZETA_PITCH, 1));
194 OUT_RING(chan, nvfx->hw_zeta.pitch);
195 }
196 }
197
198 OUT_RING(chan, RING_3D(NV34TCL_RT_ENABLE, 1));
199 OUT_RING(chan, rt_enable);
200 OUT_RING(chan, RING_3D(NV34TCL_RT_HORIZ, 3));
201 OUT_RING(chan, (w << 16) | 0);
202 OUT_RING(chan, (h << 16) | 0);
203 OUT_RING(chan, rt_format);
204 OUT_RING(chan, RING_3D(NV34TCL_VIEWPORT_HORIZ, 2));
205 OUT_RING(chan, (w << 16) | 0);
206 OUT_RING(chan, (h << 16) | 0);
207 OUT_RING(chan, RING_3D(NV34TCL_VIEWPORT_CLIP_HORIZ(0), 2));
208 OUT_RING(chan, ((w - 1) << 16) | 0);
209 OUT_RING(chan, ((h - 1) << 16) | 0);
210 OUT_RING(chan, RING_3D(0x1d88, 1));
211 OUT_RING(chan, (1 << 12) | h);
212
213 if(!nvfx->is_nv4x) {
214 /* Wonder why this is needed, context should all be set to zero on init */
215 /* TODO: we can most likely remove this, after putting it in context init */
216 OUT_RING(chan, RING_3D(NV34TCL_VIEWPORT_TX_ORIGIN, 1));
217 OUT_RING(chan, 0);
218 }
219 }
220
221 void
222 nvfx_framebuffer_relocate(struct nvfx_context *nvfx)
223 {
224 struct nouveau_channel *chan = nvfx->screen->base.channel;
225 unsigned rt_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM;
226 rt_flags |= NOUVEAU_BO_DUMMY;
227 MARK_RING(chan, 20, 20);
228
229 #define DO_(var, pfx, name) \
230 if(var.bo) { \
231 OUT_RELOC(chan, var.bo, RING_3D(pfx##TCL_DMA_##name, 1), rt_flags, 0, 0); \
232 OUT_RELOC(chan, var.bo, 0, \
233 rt_flags | NOUVEAU_BO_OR, \
234 chan->vram->handle, chan->gart->handle); \
235 OUT_RELOC(chan, var.bo, RING_3D(pfx##TCL_##name##_OFFSET, 1), rt_flags, 0, 0); \
236 OUT_RELOC(chan, var.bo, \
237 var.offset, rt_flags | NOUVEAU_BO_LOW, \
238 0, 0); \
239 }
240
241 #define DO(pfx, num) DO_(nvfx->hw_rt[num], pfx, COLOR##num)
242 DO(NV34, 0);
243 DO(NV34, 1);
244 DO(NV40, 2);
245 DO(NV40, 3);
246
247 DO_(nvfx->hw_zeta, NV34, ZETA);
248 }