eef428232b01c9a9dfb894cb9edcea4023205e21
[profile/ivi/mesa.git] / src / gallium / state_trackers / xorg / xorg_crtc.c
1 /*
2  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sub license, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portions
15  * of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  *
26  * Author: Alan Hourihane <alanh@tungstengraphics.com>
27  * Author: Jakob Bornecrantz <wallbraker@gmail.com>
28  *
29  */
30
31 #include <unistd.h>
32 #include <string.h>
33 #include <assert.h>
34 #include <stdlib.h>
35 #include <math.h>
36 #include <stdint.h>
37
38 #include "xorg-server.h"
39 #include <xf86.h>
40 #include <xf86i2c.h>
41 #include <xf86Crtc.h>
42 #include <cursorstr.h>
43 #include "xorg_tracker.h"
44 #include "xf86Modes.h"
45
46 #ifdef HAVE_XEXTPROTO_71
47 #include <X11/extensions/dpmsconst.h>
48 #else
49 #define DPMS_SERVER
50 #include <X11/extensions/dpms.h>
51 #endif
52
53 #include "util/u_inlines.h"
54 #include "util/u_rect.h"
55
56 #ifdef HAVE_LIBKMS
57 #include "libkms.h"
58 #endif
59
60 struct crtc_private
61 {
62     drmModeCrtcPtr drm_crtc;
63
64     /* hwcursor */
65     struct pipe_texture *cursor_tex;
66     struct kms_bo *cursor_bo;
67
68     unsigned cursor_handle;
69 };
70
71 static void
72 crtc_dpms(xf86CrtcPtr crtc, int mode)
73 {
74     /* ScrnInfoPtr pScrn = crtc->scrn; */
75
76     switch (mode) {
77     case DPMSModeOn:
78     case DPMSModeStandby:
79     case DPMSModeSuspend:
80         break;
81     case DPMSModeOff:
82         break;
83     }
84 }
85
86 static Bool
87 crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
88                     Rotation rotation, int x, int y)
89 {
90     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
91     modesettingPtr ms = modesettingPTR(crtc->scrn);
92     xf86OutputPtr output = NULL;
93     drmModeConnectorPtr drm_connector;
94     struct crtc_private *crtcp = crtc->driver_private;
95     drmModeCrtcPtr drm_crtc = crtcp->drm_crtc;
96     drmModeModeInfo drm_mode;
97     int i, ret;
98
99     for (i = 0; i < config->num_output; output = NULL, i++) {
100         output = config->output[i];
101
102         if (output->crtc == crtc)
103             break;
104     }
105
106     if (!output)
107         return FALSE;
108
109     drm_connector = output->driver_private;
110
111     drm_mode.clock = mode->Clock;
112     drm_mode.hdisplay = mode->HDisplay;
113     drm_mode.hsync_start = mode->HSyncStart;
114     drm_mode.hsync_end = mode->HSyncEnd;
115     drm_mode.htotal = mode->HTotal;
116     drm_mode.vdisplay = mode->VDisplay;
117     drm_mode.vsync_start = mode->VSyncStart;
118     drm_mode.vsync_end = mode->VSyncEnd;
119     drm_mode.vtotal = mode->VTotal;
120     drm_mode.flags = mode->Flags;
121     drm_mode.hskew = mode->HSkew;
122     drm_mode.vscan = mode->VScan;
123     drm_mode.vrefresh = mode->VRefresh;
124     if (!mode->name)
125         xf86SetModeDefaultName(mode);
126     strncpy(drm_mode.name, mode->name, DRM_DISPLAY_MODE_LEN - 1);
127     drm_mode.name[DRM_DISPLAY_MODE_LEN - 1] = '\0';
128
129     ret = drmModeSetCrtc(ms->fd, drm_crtc->crtc_id, ms->fb_id, x, y,
130                          &drm_connector->connector_id, 1, &drm_mode);
131
132     if (ret)
133         return FALSE;
134
135     crtc->x = x;
136     crtc->y = y;
137     crtc->mode = *mode;
138     crtc->rotation = rotation;
139
140     return TRUE;
141 }
142
143 static void
144 crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green, CARD16 * blue,
145                int size)
146 {
147     /* XXX: hockup */
148 }
149
150 static void *
151 crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
152 {
153     /* ScrnInfoPtr pScrn = crtc->scrn; */
154
155     return NULL;
156 }
157
158 static PixmapPtr
159 crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
160 {
161     /* ScrnInfoPtr pScrn = crtc->scrn; */
162
163     return NULL;
164 }
165
166 static void
167 crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
168 {
169     /* ScrnInfoPtr pScrn = crtc->scrn; */
170 }
171
172 /*
173  * Cursor functions
174  */
175
176 static void
177 crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
178 {
179     /* XXX: See if this one is needed, as we only support ARGB cursors */
180 }
181
182 static void
183 crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
184 {
185     modesettingPtr ms = modesettingPTR(crtc->scrn);
186     struct crtc_private *crtcp = crtc->driver_private;
187
188     drmModeMoveCursor(ms->fd, crtcp->drm_crtc->crtc_id, x, y);
189 }
190
191 static void
192 crtc_load_cursor_argb_ga3d(xf86CrtcPtr crtc, CARD32 * image)
193 {
194     unsigned char *ptr;
195     modesettingPtr ms = modesettingPTR(crtc->scrn);
196     struct crtc_private *crtcp = crtc->driver_private;
197     struct pipe_transfer *transfer;
198
199     if (!crtcp->cursor_tex) {
200         struct pipe_texture templat;
201         struct winsys_handle whandle;
202
203         memset(&templat, 0, sizeof(templat));
204         templat.tex_usage |= PIPE_TEXTURE_USAGE_RENDER_TARGET;
205         templat.tex_usage |= PIPE_TEXTURE_USAGE_SCANOUT;
206         templat.target = PIPE_TEXTURE_2D;
207         templat.last_level = 0;
208         templat.depth0 = 1;
209         templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
210         templat.width0 = 64;
211         templat.height0 = 64;
212
213         memset(&whandle, 0, sizeof(whandle));
214         whandle.type = DRM_API_HANDLE_TYPE_KMS;
215
216         crtcp->cursor_tex = ms->screen->texture_create(ms->screen,
217                                                        &templat);
218         ms->screen->texture_get_handle(ms->screen, crtcp->cursor_tex, &whandle);
219
220         crtcp->cursor_handle = whandle.handle;
221     }
222
223     transfer = ms->ctx->get_tex_transfer(ms->ctx, crtcp->cursor_tex,
224                                          0, 0, 0,
225                                          PIPE_TRANSFER_WRITE,
226                                          0, 0, 64, 64);
227     ptr = ms->ctx->transfer_map(ms->ctx, transfer);
228     util_copy_rect(ptr, crtcp->cursor_tex->format,
229                    transfer->stride, 0, 0,
230                    64, 64, (void*)image, 64 * 4, 0, 0);
231     ms->ctx->transfer_unmap(ms->ctx, transfer);
232     ms->ctx->tex_transfer_destroy(ms->ctx, transfer);
233 }
234
235 #if HAVE_LIBKMS
236 static void
237 crtc_load_cursor_argb_kms(xf86CrtcPtr crtc, CARD32 * image)
238 {
239     modesettingPtr ms = modesettingPTR(crtc->scrn);
240     struct crtc_private *crtcp = crtc->driver_private;
241     unsigned char *ptr;
242
243     if (!crtcp->cursor_bo) {
244         unsigned attr[8];
245
246         attr[0] = KMS_BO_TYPE;
247 #ifdef KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8
248         attr[1] = KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8;
249 #else
250         attr[1] = KMS_BO_TYPE_CURSOR;
251 #endif
252         attr[2] = KMS_WIDTH;
253         attr[3] = 64;
254         attr[4] = KMS_HEIGHT;
255         attr[5] = 64;
256         attr[6] = 0;
257
258         if (kms_bo_create(ms->kms, attr, &crtcp->cursor_bo))
259            return;
260
261         if (kms_bo_get_prop(crtcp->cursor_bo, KMS_HANDLE,
262                             &crtcp->cursor_handle))
263             goto err_bo_destroy;
264     }
265
266     kms_bo_map(crtcp->cursor_bo, (void**)&ptr);
267     memcpy(ptr, image, 64*64*4);
268     kms_bo_unmap(crtcp->cursor_bo);
269
270     return;
271
272 err_bo_destroy:
273     kms_bo_destroy(&crtcp->cursor_bo);
274 }
275 #endif
276
277 static void
278 crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image)
279 {
280     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
281     modesettingPtr ms = modesettingPTR(crtc->scrn);
282
283     /* Older X servers have cursor reference counting bugs leading to use of
284      * freed memory and consequently random crashes. Should be fixed as of
285      * xserver 1.8, but this workaround shouldn't hurt anyway.
286      */
287     if (config->cursor)
288        config->cursor->refcnt++;
289
290     if (ms->cursor)
291        FreeCursor(ms->cursor, None);
292
293     ms->cursor = config->cursor;
294
295     if (ms->screen)
296         crtc_load_cursor_argb_ga3d(crtc, image);
297 #ifdef HAVE_LIBKMS
298     else if (ms->kms)
299         crtc_load_cursor_argb_kms(crtc, image);
300 #endif
301 }
302
303 static void
304 crtc_show_cursor(xf86CrtcPtr crtc)
305 {
306     modesettingPtr ms = modesettingPTR(crtc->scrn);
307     struct crtc_private *crtcp = crtc->driver_private;
308
309     if (crtcp->cursor_tex || crtcp->cursor_bo)
310         drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id,
311                          crtcp->cursor_handle, 64, 64);
312 }
313
314 static void
315 crtc_hide_cursor(xf86CrtcPtr crtc)
316 {
317     modesettingPtr ms = modesettingPTR(crtc->scrn);
318     struct crtc_private *crtcp = crtc->driver_private;
319
320     drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 0, 0, 0);
321 }
322
323 /**
324  * Called at vt leave
325  */
326 void
327 xorg_crtc_cursor_destroy(xf86CrtcPtr crtc)
328 {
329     struct crtc_private *crtcp = crtc->driver_private;
330
331     if (crtcp->cursor_tex)
332         pipe_texture_reference(&crtcp->cursor_tex, NULL);
333 #ifdef HAVE_LIBKMS
334     if (crtcp->cursor_bo)
335         kms_bo_destroy(&crtcp->cursor_bo);
336 #endif
337 }
338
339 /*
340  * Misc functions
341  */
342
343 static void
344 crtc_destroy(xf86CrtcPtr crtc)
345 {
346     struct crtc_private *crtcp = crtc->driver_private;
347
348     xorg_crtc_cursor_destroy(crtc);
349
350     drmModeFreeCrtc(crtcp->drm_crtc);
351
352     xfree(crtcp);
353     crtc->driver_private = NULL;
354 }
355
356 static const xf86CrtcFuncsRec crtc_funcs = {
357     .dpms = crtc_dpms,
358     .set_mode_major = crtc_set_mode_major,
359
360     .set_cursor_colors = crtc_set_cursor_colors,
361     .set_cursor_position = crtc_set_cursor_position,
362     .show_cursor = crtc_show_cursor,
363     .hide_cursor = crtc_hide_cursor,
364     .load_cursor_argb = crtc_load_cursor_argb,
365
366     .shadow_create = crtc_shadow_create,
367     .shadow_allocate = crtc_shadow_allocate,
368     .shadow_destroy = crtc_shadow_destroy,
369
370     .gamma_set = crtc_gamma_set,
371     .destroy = crtc_destroy,
372 };
373
374 void
375 xorg_crtc_init(ScrnInfoPtr pScrn)
376 {
377     modesettingPtr ms = modesettingPTR(pScrn);
378     xf86CrtcPtr crtc;
379     drmModeResPtr res;
380     drmModeCrtcPtr drm_crtc = NULL;
381     struct crtc_private *crtcp;
382     int c;
383
384     res = drmModeGetResources(ms->fd);
385     if (res == 0) {
386         ErrorF("Failed drmModeGetResources %d\n", errno);
387         return;
388     }
389
390     for (c = 0; c < res->count_crtcs; c++) {
391         drm_crtc = drmModeGetCrtc(ms->fd, res->crtcs[c]);
392
393         if (!drm_crtc)
394             continue;
395
396         crtc = xf86CrtcCreate(pScrn, &crtc_funcs);
397         if (crtc == NULL)
398             goto out;
399
400         crtcp = xcalloc(1, sizeof(struct crtc_private));
401         if (!crtcp) {
402             xf86CrtcDestroy(crtc);
403             goto out;
404         }
405
406         crtcp->drm_crtc = drm_crtc;
407
408         crtc->driver_private = crtcp;
409     }
410
411   out:
412     drmModeFreeResources(res);
413 }
414
415 /* vim: set sw=4 ts=8 sts=4: */