nouveau: use dri state tracker for dri1
[mesa.git] / src / gallium / winsys / drm / nouveau / dri / nouveau_screen.c
1 #include <utils.h>
2 #include <vblank.h>
3 #include <xmlpool.h>
4
5 #include <pipe/p_context.h>
6 #include <state_tracker/st_public.h>
7 #include <state_tracker/st_cb_fbo.h>
8 #include <state_tracker/drm_api.h>
9
10 #include "nouveau_context.h"
11 #include "nouveau_screen.h"
12 #include "nouveau_swapbuffers.h"
13 #include "nouveau_dri.h"
14
15 #include "nouveau_drm.h"
16 #include "nouveau_drmif.h"
17
18 #if NOUVEAU_DRM_HEADER_PATCHLEVEL != 12
19 #error nouveau_drm.h version does not match expected version
20 #endif
21
22 /* Extension stuff, enabling of extensions handled by Gallium's GL state
23 * tracker. But, we still need to define the entry points we want.
24 */
25 #define need_GL_ARB_fragment_program
26 #define need_GL_ARB_multisample
27 #define need_GL_ARB_occlusion_query
28 #define need_GL_ARB_point_parameters
29 #define need_GL_ARB_shader_objects
30 #define need_GL_ARB_texture_compression
31 #define need_GL_ARB_vertex_program
32 #define need_GL_ARB_vertex_shader
33 #define need_GL_ARB_vertex_buffer_object
34 #define need_GL_EXT_compiled_vertex_array
35 #define need_GL_EXT_fog_coord
36 #define need_GL_EXT_secondary_color
37 #define need_GL_EXT_framebuffer_object
38 #define need_GL_VERSION_2_0
39 #define need_GL_VERSION_2_1
40 #include "extension_helper.h"
41
42 const struct dri_extension card_extensions[] =
43 {
44 { "GL_ARB_multisample", GL_ARB_multisample_functions },
45 { "GL_ARB_occlusion_query", GL_ARB_occlusion_query_functions },
46 { "GL_ARB_point_parameters", GL_ARB_point_parameters_functions },
47 { "GL_ARB_shader_objects", GL_ARB_shader_objects_functions },
48 { "GL_ARB_shading_language_100", GL_VERSION_2_0_functions },
49 { "GL_ARB_shading_language_120", GL_VERSION_2_1_functions },
50 { "GL_ARB_texture_compression", GL_ARB_texture_compression_functions },
51 { "GL_ARB_vertex_program", GL_ARB_vertex_program_functions },
52 { "GL_ARB_vertex_shader", GL_ARB_vertex_shader_functions },
53 { "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions },
54 { "GL_EXT_compiled_vertex_array", GL_EXT_compiled_vertex_array_functions },
55 { "GL_EXT_fog_coord", GL_EXT_fog_coord_functions },
56 { "GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions },
57 { "GL_EXT_secondary_color", GL_EXT_secondary_color_functions },
58 { NULL, 0 }
59 };
60
61 PUBLIC const char __driConfigOptions[] =
62 DRI_CONF_BEGIN
63 DRI_CONF_END;
64 static const GLuint __driNConfigOptions = 0;
65
66 extern const struct dri_extension common_extensions[];
67 extern const struct dri_extension nv40_extensions[];
68
69 static GLboolean
70 nouveau_create_buffer(__DRIscreenPrivate * driScrnPriv,
71 __DRIdrawablePrivate * driDrawPriv,
72 const __GLcontextModes *glVis, GLboolean pixmapBuffer)
73 {
74 struct nouveau_framebuffer *nvfb;
75 enum pipe_format colour, depth, stencil;
76
77 if (pixmapBuffer)
78 return GL_FALSE;
79
80 nvfb = CALLOC_STRUCT(nouveau_framebuffer);
81 if (!nvfb)
82 return GL_FALSE;
83
84 if (glVis->redBits == 5)
85 colour = PIPE_FORMAT_R5G6B5_UNORM;
86 else
87 colour = PIPE_FORMAT_A8R8G8B8_UNORM;
88
89 if (glVis->depthBits == 16)
90 depth = PIPE_FORMAT_Z16_UNORM;
91 else if (glVis->depthBits == 24)
92 depth = PIPE_FORMAT_Z24S8_UNORM;
93 else
94 depth = PIPE_FORMAT_NONE;
95
96 if (glVis->stencilBits == 8)
97 stencil = PIPE_FORMAT_Z24S8_UNORM;
98 else
99 stencil = PIPE_FORMAT_NONE;
100
101 nvfb->stfb = st_create_framebuffer(glVis, colour, depth, stencil,
102 driDrawPriv->w, driDrawPriv->h,
103 (void*)nvfb);
104 if (!nvfb->stfb) {
105 free(nvfb);
106 return GL_FALSE;
107 }
108
109 driDrawPriv->driverPrivate = (void *)nvfb;
110 return GL_TRUE;
111 }
112
113 static void
114 nouveau_destroy_buffer(__DRIdrawablePrivate * driDrawPriv)
115 {
116 struct nouveau_framebuffer *nvfb;
117
118 nvfb = (struct nouveau_framebuffer *)driDrawPriv->driverPrivate;
119 st_unreference_framebuffer(nvfb->stfb);
120 free(nvfb);
121 }
122
123 static __DRIconfig **
124 nouveau_fill_in_modes(__DRIscreenPrivate *psp,
125 unsigned pixel_bits, unsigned depth_bits,
126 unsigned stencil_bits, GLboolean have_back_buffer)
127 {
128 __DRIconfig **configs;
129 unsigned depth_buffer_factor;
130 unsigned back_buffer_factor;
131 GLenum fb_format;
132 GLenum fb_type;
133
134 static const GLenum back_buffer_modes[] = {
135 GLX_NONE, GLX_SWAP_UNDEFINED_OML,
136 };
137
138 uint8_t depth_bits_array[3];
139 uint8_t stencil_bits_array[3];
140 uint8_t msaa_samples_array[1];
141
142 depth_bits_array[0] = 0;
143 depth_bits_array[1] = depth_bits;
144 depth_bits_array[2] = depth_bits;
145
146 /* Just like with the accumulation buffer, always provide some modes
147 * with a stencil buffer. It will be a sw fallback, but some apps won't
148 * care about that.
149 */
150 stencil_bits_array[0] = 0;
151 stencil_bits_array[1] = 0;
152 if (depth_bits == 24)
153 stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
154 stencil_bits_array[2] = (stencil_bits == 0) ? 8 : stencil_bits;
155
156 msaa_samples_array[0] = 0;
157
158 depth_buffer_factor =
159 ((depth_bits != 0) || (stencil_bits != 0)) ? 3 : 1;
160 back_buffer_factor = (have_back_buffer) ? 3 : 1;
161
162 if (pixel_bits == 16) {
163 fb_format = GL_RGB;
164 fb_type = GL_UNSIGNED_SHORT_5_6_5;
165 }
166 else {
167 fb_format = GL_BGRA;
168 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
169 }
170
171 configs = driCreateConfigs(fb_format, fb_type,
172 depth_bits_array, stencil_bits_array,
173 depth_buffer_factor, back_buffer_modes,
174 back_buffer_factor, msaa_samples_array, 1);
175 if (configs == NULL) {
176 fprintf(stderr, "[%s:%u] Error creating FBConfig!\n",
177 __func__, __LINE__);
178 return NULL;
179 }
180
181 return configs;
182 }
183
184 static struct pipe_surface *
185 dri_surface_from_handle(struct pipe_screen *screen,
186 unsigned handle,
187 enum pipe_format format,
188 unsigned width,
189 unsigned height,
190 unsigned pitch)
191 {
192 struct pipe_surface *surface = NULL;
193 struct pipe_texture *texture = NULL;
194 struct pipe_texture templat;
195 struct pipe_buffer *buf = NULL;
196
197 buf = drm_api_hooks.buffer_from_handle(screen, "front buffer", handle);
198 if (!buf)
199 return NULL;
200
201 memset(&templat, 0, sizeof(templat));
202 templat.tex_usage = PIPE_TEXTURE_USAGE_PRIMARY |
203 NOUVEAU_TEXTURE_USAGE_LINEAR;
204 templat.target = PIPE_TEXTURE_2D;
205 templat.last_level = 0;
206 templat.depth[0] = 1;
207 templat.format = format;
208 templat.width[0] = width;
209 templat.height[0] = height;
210 pf_get_block(templat.format, &templat.block);
211
212 texture = screen->texture_blanket(screen,
213 &templat,
214 &pitch,
215 buf);
216
217 /* we don't need the buffer from this point on */
218 pipe_buffer_reference(&buf, NULL);
219
220 if (!texture)
221 return NULL;
222
223 surface = screen->get_tex_surface(screen, texture, 0, 0, 0,
224 PIPE_BUFFER_USAGE_GPU_READ |
225 PIPE_BUFFER_USAGE_GPU_WRITE);
226
227 /* we don't need the texture from this point on */
228 pipe_texture_reference(&texture, NULL);
229 return surface;
230 }
231
232 static const __DRIconfig **
233 nouveau_screen_create(__DRIscreenPrivate *psp)
234 {
235 struct nouveau_dri *nv_dri = psp->pDevPriv;
236 struct nouveau_screen *nv_screen;
237 static const __DRIversion ddx_expected =
238 { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
239 static const __DRIversion dri_expected = { 4, 0, 0 };
240 static const __DRIversion drm_expected =
241 { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
242
243 if (!driCheckDriDdxDrmVersions2("nouveau",
244 &psp->dri_version, &dri_expected,
245 &psp->ddx_version, &ddx_expected,
246 &psp->drm_version, &drm_expected)) {
247 return NULL;
248 }
249
250 if (drm_expected.patch != psp->drm_version.patch) {
251 fprintf(stderr, "Incompatible DRM patch level.\n"
252 "Expected: %d\n" "Current : %d\n",
253 drm_expected.patch, psp->drm_version.patch);
254 return NULL;
255 }
256
257 driInitExtensions(NULL, card_extensions, GL_FALSE);
258
259 if (psp->devPrivSize != sizeof(struct nouveau_dri)) {
260 NOUVEAU_ERR("DRI struct mismatch between DDX/DRI\n");
261 return NULL;
262 }
263
264 nv_screen = CALLOC_STRUCT(nouveau_screen);
265 if (!nv_screen)
266 return NULL;
267
268 nouveau_device_open_existing(&nv_screen->device, 0, psp->fd, 0);
269
270 nv_screen->pscreen = drm_api_hooks.create_screen(psp->fd, NULL);
271 if (!nv_screen->pscreen) {
272 FREE(nv_screen);
273 return NULL;
274 }
275 nv_screen->pscreen->flush_frontbuffer = nouveau_flush_frontbuffer;
276
277 {
278 enum pipe_format format;
279
280 if (nv_dri->bpp == 16)
281 format = PIPE_FORMAT_R5G6B5_UNORM;
282 else
283 format = PIPE_FORMAT_A8R8G8B8_UNORM;
284
285 nv_screen->fb = dri_surface_from_handle(nv_screen->pscreen,
286 nv_dri->front_offset,
287 format,
288 nv_dri->width,
289 nv_dri->height,
290 nv_dri->front_pitch *
291 nv_dri->bpp / 8);
292 }
293
294 driParseOptionInfo(&nv_screen->option_cache,
295 __driConfigOptions, __driNConfigOptions);
296
297 nv_screen->driScrnPriv = psp;
298 psp->private = (void *)nv_screen;
299
300 return (const __DRIconfig **)
301 nouveau_fill_in_modes(psp, nv_dri->bpp,
302 (nv_dri->bpp == 16) ? 16 : 24,
303 (nv_dri->bpp == 16) ? 0 : 8, 1);
304 }
305
306 static void
307 nouveau_screen_destroy(__DRIscreenPrivate *driScrnPriv)
308 {
309 struct nouveau_screen *nv_screen = driScrnPriv->private;
310
311 driScrnPriv->private = NULL;
312 FREE(nv_screen);
313 }
314
315 const struct __DriverAPIRec
316 driDriverAPI = {
317 .InitScreen = nouveau_screen_create,
318 .DestroyScreen = nouveau_screen_destroy,
319 .CreateContext = nouveau_context_create,
320 .DestroyContext = nouveau_context_destroy,
321 .CreateBuffer = nouveau_create_buffer,
322 .DestroyBuffer = nouveau_destroy_buffer,
323 .SwapBuffers = nouveau_swap_buffers,
324 .MakeCurrent = nouveau_context_bind,
325 .UnbindContext = nouveau_context_unbind,
326 .CopySubBuffer = nouveau_copy_sub_buffer,
327
328 .InitScreen2 = NULL, /* one day, I promise! */
329 };
330