df1fe7e69b4f16bd676823a63695d5560bfd7122
[mesa.git] / src / gallium / winsys / dri / nouveau / 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
9 #include "nouveau_context.h"
10 #include "nouveau_drm.h"
11 #include "nouveau_dri.h"
12 #include "nouveau_local.h"
13 #include "nouveau_screen.h"
14 #include "nouveau_swapbuffers.h"
15
16 #if NOUVEAU_DRM_HEADER_PATCHLEVEL != 11
17 #error nouveau_drm.h version does not match expected version
18 #endif
19
20 /* Extension stuff, enabling of extensions handled by Gallium's GL state
21 * tracker. But, we still need to define the entry points we want.
22 */
23 #define need_GL_ARB_fragment_program
24 #define need_GL_ARB_multisample
25 #define need_GL_ARB_occlusion_query
26 #define need_GL_ARB_point_parameters
27 #define need_GL_ARB_shader_objects
28 #define need_GL_ARB_texture_compression
29 #define need_GL_ARB_vertex_program
30 #define need_GL_ARB_vertex_shader
31 #define need_GL_ARB_vertex_buffer_object
32 #define need_GL_EXT_compiled_vertex_array
33 #define need_GL_EXT_fog_coord
34 #define need_GL_EXT_secondary_color
35 #define need_GL_EXT_framebuffer_object
36 #define need_GL_VERSION_2_0
37 #define need_GL_VERSION_2_1
38 #include "extension_helper.h"
39
40 const struct dri_extension card_extensions[] =
41 {
42 { "GL_ARB_multisample", GL_ARB_multisample_functions },
43 { "GL_ARB_occlusion_query", GL_ARB_occlusion_query_functions },
44 { "GL_ARB_point_parameters", GL_ARB_point_parameters_functions },
45 { "GL_ARB_shader_objects", GL_ARB_shader_objects_functions },
46 { "GL_ARB_shading_language_100", GL_VERSION_2_0_functions },
47 { "GL_ARB_shading_language_120", GL_VERSION_2_1_functions },
48 { "GL_ARB_texture_compression", GL_ARB_texture_compression_functions },
49 { "GL_ARB_vertex_program", GL_ARB_vertex_program_functions },
50 { "GL_ARB_vertex_shader", GL_ARB_vertex_shader_functions },
51 { "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions },
52 { "GL_EXT_compiled_vertex_array", GL_EXT_compiled_vertex_array_functions },
53 { "GL_EXT_fog_coord", GL_EXT_fog_coord_functions },
54 { "GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions },
55 { "GL_EXT_secondary_color", GL_EXT_secondary_color_functions },
56 { NULL, 0 }
57 };
58
59 PUBLIC const char __driConfigOptions[] =
60 DRI_CONF_BEGIN
61 DRI_CONF_END;
62 static const GLuint __driNConfigOptions = 0;
63
64 extern const struct dri_extension common_extensions[];
65 extern const struct dri_extension nv40_extensions[];
66
67 static GLboolean
68 nouveau_screen_create(__DRIscreenPrivate *driScrnPriv)
69 {
70 struct nouveau_dri *nv_dri = driScrnPriv->pDevPriv;
71 struct nouveau_screen *nv_screen;
72 int ret;
73
74 if (driScrnPriv->devPrivSize != sizeof(struct nouveau_dri)) {
75 NOUVEAU_ERR("DRI struct mismatch between DDX/DRI\n");
76 return GL_FALSE;
77 }
78
79 nv_screen = CALLOC_STRUCT(nouveau_screen);
80 if (!nv_screen)
81 return GL_FALSE;
82 nv_screen->driScrnPriv = driScrnPriv;
83 driScrnPriv->private = (void *)nv_screen;
84
85 driParseOptionInfo(&nv_screen->option_cache,
86 __driConfigOptions, __driNConfigOptions);
87
88 if ((ret = nouveau_device_open_existing(&nv_screen->device, 0,
89 driScrnPriv->fd, 0))) {
90 NOUVEAU_ERR("Failed opening nouveau device: %d\n", ret);
91 return GL_FALSE;
92 }
93
94 nv_screen->front_offset = nv_dri->front_offset;
95 nv_screen->front_pitch = nv_dri->front_pitch * (nv_dri->bpp / 8);
96 nv_screen->front_cpp = nv_dri->bpp / 8;
97 nv_screen->front_height = nv_dri->height;
98
99 return GL_TRUE;
100 }
101
102 static void
103 nouveau_screen_destroy(__DRIscreenPrivate *driScrnPriv)
104 {
105 struct nouveau_screen *nv_screen = driScrnPriv->private;
106
107 driScrnPriv->private = NULL;
108 FREE(nv_screen);
109 }
110
111 static GLboolean
112 nouveau_create_buffer(__DRIscreenPrivate * driScrnPriv,
113 __DRIdrawablePrivate * driDrawPriv,
114 const __GLcontextModes *glVis, GLboolean pixmapBuffer)
115 {
116 struct nouveau_framebuffer *nvfb;
117 enum pipe_format colour, depth, stencil;
118
119 if (pixmapBuffer)
120 return GL_FALSE;
121
122 nvfb = CALLOC_STRUCT(nouveau_framebuffer);
123 if (!nvfb)
124 return GL_FALSE;
125
126 if (glVis->redBits == 5)
127 colour = PIPE_FORMAT_R5G6B5_UNORM;
128 else
129 colour = PIPE_FORMAT_A8R8G8B8_UNORM;
130
131 if (glVis->depthBits == 16)
132 depth = PIPE_FORMAT_Z16_UNORM;
133 else if (glVis->depthBits == 24)
134 depth = PIPE_FORMAT_Z24S8_UNORM;
135 else
136 depth = PIPE_FORMAT_NONE;
137
138 if (glVis->stencilBits == 8)
139 stencil = PIPE_FORMAT_Z24S8_UNORM;
140 else
141 stencil = PIPE_FORMAT_NONE;
142
143 nvfb->stfb = st_create_framebuffer(glVis, colour, depth, stencil,
144 driDrawPriv->w, driDrawPriv->h,
145 (void*)nvfb);
146 if (!nvfb->stfb) {
147 free(nvfb);
148 return GL_FALSE;
149 }
150
151 driDrawPriv->driverPrivate = (void *)nvfb;
152 return GL_TRUE;
153 }
154
155 static void
156 nouveau_destroy_buffer(__DRIdrawablePrivate * driDrawPriv)
157 {
158 struct nouveau_framebuffer *nvfb;
159
160 nvfb = (struct nouveau_framebuffer *)driDrawPriv->driverPrivate;
161 st_unreference_framebuffer(&nvfb->stfb);
162 free(nvfb);
163 }
164
165 static struct __DriverAPIRec
166 nouveau_api = {
167 .InitDriver = nouveau_screen_create,
168 .DestroyScreen = nouveau_screen_destroy,
169 .CreateContext = nouveau_context_create,
170 .DestroyContext = nouveau_context_destroy,
171 .CreateBuffer = nouveau_create_buffer,
172 .DestroyBuffer = nouveau_destroy_buffer,
173 .SwapBuffers = nouveau_swap_buffers,
174 .MakeCurrent = nouveau_context_bind,
175 .UnbindContext = nouveau_context_unbind,
176 .GetSwapInfo = NULL,
177 .GetMSC = NULL,
178 .WaitForMSC = NULL,
179 .WaitForSBC = NULL,
180 .SwapBuffersMSC = NULL,
181 .CopySubBuffer = nouveau_copy_sub_buffer,
182 .setTexOffset = NULL
183 };
184
185 static __GLcontextModes *
186 nouveau_fill_in_modes(unsigned pixel_bits, unsigned depth_bits,
187 unsigned stencil_bits, GLboolean have_back_buffer)
188 {
189 __GLcontextModes * modes;
190 __GLcontextModes * m;
191 unsigned num_modes;
192 unsigned depth_buffer_factor;
193 unsigned back_buffer_factor;
194 int i;
195
196 static const struct {
197 GLenum format;
198 GLenum type;
199 } fb_format_array[] = {
200 { GL_RGB , GL_UNSIGNED_SHORT_5_6_5 },
201 { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
202 { GL_BGR , GL_UNSIGNED_INT_8_8_8_8_REV },
203 };
204
205 /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
206 * support pageflipping at all.
207 */
208 static const GLenum back_buffer_modes[] = {
209 GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML
210 };
211
212 uint8_t depth_bits_array[4] = { 0, 16, 24, 24 };
213 uint8_t stencil_bits_array[4] = { 0, 0, 0, 8 };
214 uint8_t msaa_samples_array[1] = { 0 };
215
216 depth_buffer_factor = 4;
217 back_buffer_factor = (have_back_buffer) ? 3 : 1;
218
219 num_modes = ((pixel_bits==16) ? 1 : 2) *
220 depth_buffer_factor * back_buffer_factor * 4;
221 modes = (*dri_interface->createContextModes)(num_modes,
222 sizeof(__GLcontextModes));
223 m = modes;
224
225 for (i=((pixel_bits==16)?0:1);i<((pixel_bits==16)?1:3);i++) {
226 if (!driFillInModes(&m, fb_format_array[i].format,
227 fb_format_array[i].type,
228 depth_bits_array,
229 stencil_bits_array,
230 depth_buffer_factor,
231 back_buffer_modes,
232 back_buffer_factor,
233 msaa_samples_array, 1,
234 GLX_TRUE_COLOR)) {
235 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
236 __func__, __LINE__ );
237 return NULL;
238 }
239
240 if (!driFillInModes(&m, fb_format_array[i].format,
241 fb_format_array[i].type,
242 depth_bits_array,
243 stencil_bits_array,
244 depth_buffer_factor,
245 back_buffer_modes,
246 back_buffer_factor,
247 msaa_samples_array, 1,
248 GLX_DIRECT_COLOR)) {
249 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
250 __func__, __LINE__ );
251 return NULL;
252 }
253 }
254
255 return modes;
256 }
257 PUBLIC void *
258 __driCreateNewScreen_20050727(__DRInativeDisplay *dpy, int scrn,
259 __DRIscreen *psc, const __GLcontextModes * modes,
260 const __DRIversion * ddx_version,
261 const __DRIversion * dri_version,
262 const __DRIversion * drm_version,
263 const __DRIframebuffer * frame_buffer,
264 void * pSAREA, int fd, int internal_api_version,
265 const __DRIinterfaceMethods * interface,
266 __GLcontextModes ** driver_modes)
267 {
268 __DRIscreenPrivate *psp;
269 static const __DRIversion ddx_expected =
270 { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
271 static const __DRIversion dri_expected = { 4, 0, 0 };
272 static const __DRIversion drm_expected =
273 { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
274 struct nouveau_dri *nv_dri = NULL;
275
276 dri_interface = interface;
277
278 if (!driCheckDriDdxDrmVersions2("nouveau",
279 dri_version, &dri_expected,
280 ddx_version, &ddx_expected,
281 drm_version, &drm_expected)) {
282 return NULL;
283 }
284
285 if (drm_expected.patch != drm_version->patch) {
286 fprintf(stderr, "Incompatible DRM patch level.\n"
287 "Expected: %d\n" "Current : %d\n",
288 drm_expected.patch, drm_version->patch);
289 return NULL;
290 }
291
292 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
293 ddx_version, dri_version, drm_version,
294 frame_buffer, pSAREA, fd,
295 internal_api_version,
296 &nouveau_api);
297 if (psp == NULL)
298 return NULL;
299 nv_dri = psp->pDevPriv;
300
301 *driver_modes = nouveau_fill_in_modes(nv_dri->bpp,
302 (nv_dri->bpp == 16) ? 16 : 24,
303 (nv_dri->bpp == 16) ? 0 : 8,
304 1);
305
306 driInitExtensions(NULL, card_extensions, GL_FALSE);
307
308 return (void *)psp;
309 }
310