nouveau: Factor out common winsys bits into libnouveaudrm.a
[mesa.git] / src / gallium / winsys / drm / nouveau / dri / nouveau_screen_dri.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 <nouveau_drm.h>
9 #include "../common/nouveau_dri.h"
10 #include "../common/nouveau_local.h"
11 #include "nouveau_context_dri.h"
12 #include "nouveau_screen_dri.h"
13 #include "nouveau_swapbuffers.h"
14
15 #if NOUVEAU_DRM_HEADER_PATCHLEVEL != 11
16 #error nouveau_drm.h version does not match expected version
17 #endif
18
19 /* Extension stuff, enabling of extensions handled by Gallium's GL state
20 * tracker. But, we still need to define the entry points we want.
21 */
22 #define need_GL_ARB_fragment_program
23 #define need_GL_ARB_multisample
24 #define need_GL_ARB_occlusion_query
25 #define need_GL_ARB_point_parameters
26 #define need_GL_ARB_shader_objects
27 #define need_GL_ARB_texture_compression
28 #define need_GL_ARB_vertex_program
29 #define need_GL_ARB_vertex_shader
30 #define need_GL_ARB_vertex_buffer_object
31 #define need_GL_EXT_compiled_vertex_array
32 #define need_GL_EXT_fog_coord
33 #define need_GL_EXT_secondary_color
34 #define need_GL_EXT_framebuffer_object
35 #define need_GL_VERSION_2_0
36 #define need_GL_VERSION_2_1
37 #include "extension_helper.h"
38
39 const struct dri_extension card_extensions[] =
40 {
41 { "GL_ARB_multisample", GL_ARB_multisample_functions },
42 { "GL_ARB_occlusion_query", GL_ARB_occlusion_query_functions },
43 { "GL_ARB_point_parameters", GL_ARB_point_parameters_functions },
44 { "GL_ARB_shader_objects", GL_ARB_shader_objects_functions },
45 { "GL_ARB_shading_language_100", GL_VERSION_2_0_functions },
46 { "GL_ARB_shading_language_120", GL_VERSION_2_1_functions },
47 { "GL_ARB_texture_compression", GL_ARB_texture_compression_functions },
48 { "GL_ARB_vertex_program", GL_ARB_vertex_program_functions },
49 { "GL_ARB_vertex_shader", GL_ARB_vertex_shader_functions },
50 { "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions },
51 { "GL_EXT_compiled_vertex_array", GL_EXT_compiled_vertex_array_functions },
52 { "GL_EXT_fog_coord", GL_EXT_fog_coord_functions },
53 { "GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions },
54 { "GL_EXT_secondary_color", GL_EXT_secondary_color_functions },
55 { NULL, 0 }
56 };
57
58 PUBLIC const char __driConfigOptions[] =
59 DRI_CONF_BEGIN
60 DRI_CONF_END;
61 static const GLuint __driNConfigOptions = 0;
62
63 extern const struct dri_extension common_extensions[];
64 extern const struct dri_extension nv40_extensions[];
65
66 static GLboolean
67 nouveau_create_buffer(__DRIscreenPrivate * driScrnPriv,
68 __DRIdrawablePrivate * driDrawPriv,
69 const __GLcontextModes *glVis, GLboolean pixmapBuffer)
70 {
71 struct nouveau_framebuffer *nvfb;
72 enum pipe_format colour, depth, stencil;
73
74 if (pixmapBuffer)
75 return GL_FALSE;
76
77 nvfb = CALLOC_STRUCT(nouveau_framebuffer);
78 if (!nvfb)
79 return GL_FALSE;
80
81 if (glVis->redBits == 5)
82 colour = PIPE_FORMAT_R5G6B5_UNORM;
83 else
84 colour = PIPE_FORMAT_A8R8G8B8_UNORM;
85
86 if (glVis->depthBits == 16)
87 depth = PIPE_FORMAT_Z16_UNORM;
88 else if (glVis->depthBits == 24)
89 depth = PIPE_FORMAT_Z24S8_UNORM;
90 else
91 depth = PIPE_FORMAT_NONE;
92
93 if (glVis->stencilBits == 8)
94 stencil = PIPE_FORMAT_Z24S8_UNORM;
95 else
96 stencil = PIPE_FORMAT_NONE;
97
98 nvfb->stfb = st_create_framebuffer(glVis, colour, depth, stencil,
99 driDrawPriv->w, driDrawPriv->h,
100 (void*)nvfb);
101 if (!nvfb->stfb) {
102 free(nvfb);
103 return GL_FALSE;
104 }
105
106 driDrawPriv->driverPrivate = (void *)nvfb;
107 return GL_TRUE;
108 }
109
110 static void
111 nouveau_destroy_buffer(__DRIdrawablePrivate * driDrawPriv)
112 {
113 struct nouveau_framebuffer *nvfb;
114
115 nvfb = (struct nouveau_framebuffer *)driDrawPriv->driverPrivate;
116 st_unreference_framebuffer(nvfb->stfb);
117 free(nvfb);
118 }
119
120 static __DRIconfig **
121 nouveau_fill_in_modes(__DRIscreenPrivate *psp,
122 unsigned pixel_bits, unsigned depth_bits,
123 unsigned stencil_bits, GLboolean have_back_buffer)
124 {
125 __DRIconfig **configs;
126 unsigned depth_buffer_factor;
127 unsigned back_buffer_factor;
128 GLenum fb_format;
129 GLenum fb_type;
130
131 static const GLenum back_buffer_modes[] = {
132 GLX_NONE, GLX_SWAP_UNDEFINED_OML,
133 };
134
135 uint8_t depth_bits_array[3];
136 uint8_t stencil_bits_array[3];
137 uint8_t msaa_samples_array[1];
138
139 depth_bits_array[0] = 0;
140 depth_bits_array[1] = depth_bits;
141 depth_bits_array[2] = depth_bits;
142
143 /* Just like with the accumulation buffer, always provide some modes
144 * with a stencil buffer. It will be a sw fallback, but some apps won't
145 * care about that.
146 */
147 stencil_bits_array[0] = 0;
148 stencil_bits_array[1] = 0;
149 if (depth_bits == 24)
150 stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
151 stencil_bits_array[2] = (stencil_bits == 0) ? 8 : stencil_bits;
152
153 msaa_samples_array[0] = 0;
154
155 depth_buffer_factor =
156 ((depth_bits != 0) || (stencil_bits != 0)) ? 3 : 1;
157 back_buffer_factor = (have_back_buffer) ? 3 : 1;
158
159 if (pixel_bits == 16) {
160 fb_format = GL_RGB;
161 fb_type = GL_UNSIGNED_SHORT_5_6_5;
162 }
163 else {
164 fb_format = GL_BGRA;
165 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
166 }
167
168 configs = driCreateConfigs(fb_format, fb_type,
169 depth_bits_array, stencil_bits_array,
170 depth_buffer_factor, back_buffer_modes,
171 back_buffer_factor, msaa_samples_array, 1);
172 if (configs == NULL) {
173 fprintf(stderr, "[%s:%u] Error creating FBConfig!\n",
174 __func__, __LINE__);
175 return NULL;
176 }
177
178 return configs;
179 }
180
181 static const __DRIconfig **
182 nouveau_screen_create(__DRIscreenPrivate *psp)
183 {
184 struct nouveau_dri *nv_dri = psp->pDevPriv;
185 struct nouveau_screen_dri *nv_screen;
186 static const __DRIversion ddx_expected =
187 { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
188 static const __DRIversion dri_expected = { 4, 0, 0 };
189 static const __DRIversion drm_expected =
190 { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
191
192 if (!driCheckDriDdxDrmVersions2("nouveau",
193 &psp->dri_version, &dri_expected,
194 &psp->ddx_version, &ddx_expected,
195 &psp->drm_version, &drm_expected)) {
196 return NULL;
197 }
198
199 if (drm_expected.patch != psp->drm_version.patch) {
200 fprintf(stderr, "Incompatible DRM patch level.\n"
201 "Expected: %d\n" "Current : %d\n",
202 drm_expected.patch, psp->drm_version.patch);
203 return NULL;
204 }
205
206 driInitExtensions(NULL, card_extensions, GL_FALSE);
207
208 if (psp->devPrivSize != sizeof(struct nouveau_dri)) {
209 NOUVEAU_ERR("DRI struct mismatch between DDX/DRI\n");
210 return NULL;
211 }
212
213 nv_screen = CALLOC_STRUCT(nouveau_screen_dri);
214 if (!nv_screen)
215 return NULL;
216
217 driParseOptionInfo(&nv_screen->option_cache,
218 __driConfigOptions, __driNConfigOptions);
219
220 if (nouveau_screen_init(nv_dri, psp->fd, &nv_screen->base)) {
221 FREE(nv_screen);
222 return NULL;
223 }
224
225 nv_screen->driScrnPriv = psp;
226 psp->private = (void *)nv_screen;
227
228 return (const __DRIconfig **)
229 nouveau_fill_in_modes(psp, nv_dri->bpp,
230 (nv_dri->bpp == 16) ? 16 : 24,
231 (nv_dri->bpp == 16) ? 0 : 8, 1);
232 }
233
234 static void
235 nouveau_screen_destroy(__DRIscreenPrivate *driScrnPriv)
236 {
237 struct nouveau_screen_dri *nv_screen = driScrnPriv->private;
238
239 driScrnPriv->private = NULL;
240 nouveau_screen_cleanup(&nv_screen->base);
241 FREE(nv_screen);
242 }
243
244 const struct __DriverAPIRec
245 driDriverAPI = {
246 .InitScreen = nouveau_screen_create,
247 .DestroyScreen = nouveau_screen_destroy,
248 .CreateContext = nouveau_context_create,
249 .DestroyContext = nouveau_context_destroy,
250 .CreateBuffer = nouveau_create_buffer,
251 .DestroyBuffer = nouveau_destroy_buffer,
252 .SwapBuffers = nouveau_swap_buffers,
253 .MakeCurrent = nouveau_context_bind,
254 .UnbindContext = nouveau_context_unbind,
255 .CopySubBuffer = nouveau_copy_sub_buffer,
256
257 .InitScreen2 = NULL, /* one day, I promise! */
258 };
259