c6d0c53588777aff89a1231aa71e34d01f1cc43c
[mesa.git] / src / gallium / winsys / drm / 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_create_buffer(__DRIscreenPrivate * driScrnPriv,
69 __DRIdrawablePrivate * driDrawPriv,
70 const __GLcontextModes *glVis, GLboolean pixmapBuffer)
71 {
72 struct nouveau_framebuffer *nvfb;
73 enum pipe_format colour, depth, stencil;
74
75 if (pixmapBuffer)
76 return GL_FALSE;
77
78 nvfb = CALLOC_STRUCT(nouveau_framebuffer);
79 if (!nvfb)
80 return GL_FALSE;
81
82 if (glVis->redBits == 5)
83 colour = PIPE_FORMAT_R5G6B5_UNORM;
84 else
85 colour = PIPE_FORMAT_A8R8G8B8_UNORM;
86
87 if (glVis->depthBits == 16)
88 depth = PIPE_FORMAT_Z16_UNORM;
89 else if (glVis->depthBits == 24)
90 depth = PIPE_FORMAT_Z24S8_UNORM;
91 else
92 depth = PIPE_FORMAT_NONE;
93
94 if (glVis->stencilBits == 8)
95 stencil = PIPE_FORMAT_Z24S8_UNORM;
96 else
97 stencil = PIPE_FORMAT_NONE;
98
99 nvfb->stfb = st_create_framebuffer(glVis, colour, depth, stencil,
100 driDrawPriv->w, driDrawPriv->h,
101 (void*)nvfb);
102 if (!nvfb->stfb) {
103 free(nvfb);
104 return GL_FALSE;
105 }
106
107 driDrawPriv->driverPrivate = (void *)nvfb;
108 return GL_TRUE;
109 }
110
111 static void
112 nouveau_destroy_buffer(__DRIdrawablePrivate * driDrawPriv)
113 {
114 struct nouveau_framebuffer *nvfb;
115
116 nvfb = (struct nouveau_framebuffer *)driDrawPriv->driverPrivate;
117 st_unreference_framebuffer(nvfb->stfb);
118 free(nvfb);
119 }
120
121 static __DRIconfig **
122 nouveau_fill_in_modes(__DRIscreenPrivate *psp,
123 unsigned pixel_bits, unsigned depth_bits,
124 unsigned stencil_bits, GLboolean have_back_buffer)
125 {
126 __DRIconfig **configs;
127 unsigned depth_buffer_factor;
128 unsigned back_buffer_factor;
129 GLenum fb_format;
130 GLenum fb_type;
131
132 static const GLenum back_buffer_modes[] = {
133 GLX_NONE, GLX_SWAP_UNDEFINED_OML,
134 };
135
136 uint8_t depth_bits_array[3];
137 uint8_t stencil_bits_array[3];
138 uint8_t msaa_samples_array[1];
139
140 depth_bits_array[0] = 0;
141 depth_bits_array[1] = depth_bits;
142 depth_bits_array[2] = depth_bits;
143
144 /* Just like with the accumulation buffer, always provide some modes
145 * with a stencil buffer. It will be a sw fallback, but some apps won't
146 * care about that.
147 */
148 stencil_bits_array[0] = 0;
149 stencil_bits_array[1] = 0;
150 if (depth_bits == 24)
151 stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
152 stencil_bits_array[2] = (stencil_bits == 0) ? 8 : stencil_bits;
153
154 msaa_samples_array[0] = 0;
155
156 depth_buffer_factor =
157 ((depth_bits != 0) || (stencil_bits != 0)) ? 3 : 1;
158 back_buffer_factor = (have_back_buffer) ? 3 : 1;
159
160 if (pixel_bits == 16) {
161 fb_format = GL_RGB;
162 fb_type = GL_UNSIGNED_SHORT_5_6_5;
163 }
164 else {
165 fb_format = GL_BGRA;
166 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
167 }
168
169 configs = driCreateConfigs(fb_format, fb_type,
170 depth_bits_array, stencil_bits_array,
171 depth_buffer_factor, back_buffer_modes,
172 back_buffer_factor, msaa_samples_array, 1);
173 if (configs == NULL) {
174 fprintf(stderr, "[%s:%u] Error creating FBConfig!\n",
175 __func__, __LINE__);
176 return NULL;
177 }
178
179 return configs;
180 }
181
182 static const __DRIconfig **
183 nouveau_screen_create(__DRIscreenPrivate *psp)
184 {
185 struct nouveau_dri *nv_dri = psp->pDevPriv;
186 struct nouveau_screen *nv_screen;
187 static const __DRIversion ddx_expected =
188 { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
189 static const __DRIversion dri_expected = { 4, 0, 0 };
190 static const __DRIversion drm_expected =
191 { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
192 int ret;
193
194 if (!driCheckDriDdxDrmVersions2("nouveau",
195 &psp->dri_version, &dri_expected,
196 &psp->ddx_version, &ddx_expected,
197 &psp->drm_version, &drm_expected)) {
198 return NULL;
199 }
200
201 if (drm_expected.patch != psp->drm_version.patch) {
202 fprintf(stderr, "Incompatible DRM patch level.\n"
203 "Expected: %d\n" "Current : %d\n",
204 drm_expected.patch, psp->drm_version.patch);
205 return NULL;
206 }
207
208 driInitExtensions(NULL, card_extensions, GL_FALSE);
209
210 if (psp->devPrivSize != sizeof(struct nouveau_dri)) {
211 NOUVEAU_ERR("DRI struct mismatch between DDX/DRI\n");
212 return GL_FALSE;
213 }
214
215 nv_screen = CALLOC_STRUCT(nouveau_screen);
216 if (!nv_screen)
217 return GL_FALSE;
218 nv_screen->driScrnPriv = psp;
219 psp->private = (void *)nv_screen;
220
221 driParseOptionInfo(&nv_screen->option_cache,
222 __driConfigOptions, __driNConfigOptions);
223
224 if ((ret = nouveau_device_open_existing(&nv_screen->device, 0,
225 psp->fd, 0))) {
226 NOUVEAU_ERR("Failed opening nouveau device: %d\n", ret);
227 return GL_FALSE;
228 }
229
230 nv_screen->front_offset = nv_dri->front_offset;
231 nv_screen->front_pitch = nv_dri->front_pitch * (nv_dri->bpp / 8);
232 nv_screen->front_cpp = nv_dri->bpp / 8;
233 nv_screen->front_height = nv_dri->height;
234
235 return (const __DRIconfig **)
236 nouveau_fill_in_modes(psp, nv_dri->bpp,
237 (nv_dri->bpp == 16) ? 16 : 24,
238 (nv_dri->bpp == 16) ? 0 : 8, 1);
239 }
240
241 static void
242 nouveau_screen_destroy(__DRIscreenPrivate *driScrnPriv)
243 {
244 struct nouveau_screen *nv_screen = driScrnPriv->private;
245
246 driScrnPriv->private = NULL;
247 FREE(nv_screen);
248 }
249
250 const struct __DriverAPIRec
251 driDriverAPI = {
252 .InitScreen = nouveau_screen_create,
253 .DestroyScreen = nouveau_screen_destroy,
254 .CreateContext = nouveau_context_create,
255 .DestroyContext = nouveau_context_destroy,
256 .CreateBuffer = nouveau_create_buffer,
257 .DestroyBuffer = nouveau_destroy_buffer,
258 .SwapBuffers = nouveau_swap_buffers,
259 .MakeCurrent = nouveau_context_bind,
260 .UnbindContext = nouveau_context_unbind,
261 .CopySubBuffer = nouveau_copy_sub_buffer,
262
263 .InitScreen2 = NULL, /* one day, I promise! */
264 };
265