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