00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifdef __HAVE_KMS__
00034
00035 #include <unistd.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <errno.h>
00039 #include <string.h>
00040 #include <strings.h>
00041 #include <fcntl.h>
00042 #include <sys/ioctl.h>
00043 #include <sys/mman.h>
00044 #include <sys/kd.h>
00045 #include "mmsgui/fb/mmskms.h"
00046 #include "mmsgui/fb/mmsfbconv.h"
00047 #include "mmsgui/fb/fb.h"
00048
00049 #define INITCHECK if(!this->isinitialized){MMSFB_SetError(0,"MMSKms is not initialized");return false;}
00050
00051 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
00052
00053 static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data)
00054 {
00055 int *waiting_for_flip = (int*)data;
00056 *waiting_for_flip = 0;
00057 }
00058
00059 MMSKms::MMSKms() {
00060
00061 this->isinitialized = false;
00062 this->framebuffer_base = NULL;
00063 this->drm.fd = -1;
00064 memset(this->layers, 0, sizeof(this->layers));
00065 this->layers_cnt = 0;
00066 this->active_screen = 0;
00067
00068 if (MMSFBBase_rotate180) {
00069 this->rotate180 = true;
00070 MMSFBBase_rotate180 = false;
00071 } else {
00072 this->rotate180 = false;
00073 }
00074
00075 }
00076
00077 MMSKms::~MMSKms() {
00078 closeDevice();
00079 }
00080
00081
00082 void MMSKms::dump_blob(uint32_t blob_id)
00083 {
00084 uint32_t i;
00085 unsigned char *blob_data;
00086 drmModePropertyBlobPtr blob;
00087
00088 blob = drmModeGetPropertyBlob(this->drm.fd, blob_id);
00089 if (!blob)
00090 return;
00091
00092 blob_data = (unsigned char *)blob->data;
00093
00094 for (i = 0; i < blob->length; i++) {
00095 if (i % 16 == 0)
00096 printf("\n\t\t\t");
00097 printf("%.2hhx", blob_data[i]);
00098 }
00099 printf("\n");
00100
00101 drmModeFreePropertyBlob(blob);
00102 }
00103
00104
00105 void MMSKms::dump_prop(uint32_t prop_id, uint64_t value)
00106 {
00107 int i;
00108 drmModePropertyPtr prop;
00109
00110 prop = drmModeGetProperty(this->drm.fd, prop_id);
00111
00112 printf("\t%d", prop_id);
00113 if (!prop) {
00114 printf("\n");
00115 return;
00116 }
00117
00118 printf(" %s:\n", prop->name);
00119
00120 printf("\t\tflags:");
00121 if (prop->flags & DRM_MODE_PROP_PENDING)
00122 printf(" pending");
00123 if (prop->flags & DRM_MODE_PROP_RANGE)
00124 printf(" range");
00125 if (prop->flags & DRM_MODE_PROP_IMMUTABLE)
00126 printf(" immutable");
00127 if (prop->flags & DRM_MODE_PROP_ENUM)
00128 printf(" enum");
00129 if (prop->flags & DRM_MODE_PROP_BITMASK)
00130 printf(" bitmask");
00131 if (prop->flags & DRM_MODE_PROP_BLOB)
00132 printf(" blob");
00133 printf("\n");
00134
00135 if (prop->flags & DRM_MODE_PROP_RANGE) {
00136 printf("\t\tvalues:");
00137 for (i = 0; i < prop->count_values; i++)
00138 printf(" %llu", prop->values[i]);
00139 printf("\n");
00140 }
00141
00142 if (prop->flags & DRM_MODE_PROP_ENUM) {
00143 printf("\t\tenums:");
00144 for (i = 0; i < prop->count_enums; i++)
00145 printf(" %s=%llu", prop->enums[i].name,
00146 prop->enums[i].value);
00147 printf("\n");
00148 } else if (prop->flags & DRM_MODE_PROP_BITMASK) {
00149 printf("\t\tvalues:");
00150 for (i = 0; i < prop->count_enums; i++)
00151 printf(" %s=0x%llx", prop->enums[i].name,
00152 (1LL << prop->enums[i].value));
00153 printf("\n");
00154 } else {
00155 }
00156
00157 if (prop->flags & DRM_MODE_PROP_BLOB) {
00158 printf("\t\tblobs:\n");
00159 for (i = 0; i < prop->count_blobs; i++)
00160 dump_blob(prop->blob_ids[i]);
00161 printf("\n");
00162 } else {
00163 }
00164
00165 printf("\t\tvalue:");
00166 if (prop->flags & DRM_MODE_PROP_BLOB)
00167 dump_blob(value);
00168 else
00169 printf(" %llu\n", value);
00170
00171 drmModeFreeProperty(prop);
00172 }
00173
00174 bool MMSKms::init_drm()
00175 {
00176 static const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos" };
00177 drmModeRes *resources;
00178 drmModeConnector *connector = NULL;
00179 drmModeEncoder *encoder = NULL;
00180 int i, area;
00181
00182 for (i = 0; i < ARRAY_SIZE(modules); i++) {
00183 printf("trying to load module %s...", modules[i]);
00184 this->drm.fd = drmOpen(modules[i], NULL);
00185
00186 if (this->drm.fd < 0) {
00187 printf("failed.\n");
00188 } else {
00189 printf("success.\n");
00190 break;
00191 }
00192 }
00193
00194 if (this->drm.fd < 0) {
00195 printf("could not open drm device\n");
00196 return false;
00197 }
00198
00199 resources = drmModeGetResources(this->drm.fd);
00200 if (!resources) {
00201 printf("drmModeGetResources failed: %s\n", strerror(errno));
00202 drmClose(this->drm.fd);
00203 this->drm.fd = -1;
00204 return false;
00205 }
00206
00207
00208 for (i = 0; i < resources->count_connectors; i++) {
00209 connector = drmModeGetConnector(this->drm.fd, resources->connectors[i]);
00210
00211 if (connector->connection == DRM_MODE_CONNECTED) {
00212
00213 break;
00214 }
00215
00216 drmModeFreeConnector(connector);
00217 connector = NULL;
00218 }
00219
00220 if (!connector) {
00221
00222
00223
00224 printf("no connected connector!\n");
00225 drmClose(this->drm.fd);
00226 this->drm.fd = -1;
00227 return false;
00228 }
00229
00230
00231 for (i = 0, area = 0; i < connector->count_modes; i++) {
00232 drmModeModeInfo *current_mode = &connector->modes[i];
00233
00234 int current_area = current_mode->hdisplay * current_mode->vdisplay;
00235
00236 if (current_area > area) {
00237 this->drm.mode = current_mode;
00238 area = current_area;
00239 }
00240 }
00241
00242 if (!this->drm.mode) {
00243 printf("could not find mode!\n");
00244 drmClose(this->drm.fd);
00245 this->drm.fd = -1;
00246 return false;
00247 }
00248
00249
00250 for (i = 0; i < resources->count_encoders; i++) {
00251 encoder = drmModeGetEncoder(this->drm.fd, resources->encoders[i]);
00252
00253 if (encoder->encoder_id == connector->encoder_id)
00254 break;
00255
00256 drmModeFreeEncoder(encoder);
00257 encoder = NULL;
00258 }
00259
00260 if (!encoder) {
00261 printf("no encoder!\n");
00262 drmClose(this->drm.fd);
00263 this->drm.fd = -1;
00264 return false;
00265 }
00266
00267 this->drm.crtc_id = encoder->crtc_id;
00268 this->drm.connector_id = connector->connector_id;
00269
00270 if (this->rotate180) {
00271 drmModeObjectSetProperty(this->drm.fd, encoder->crtc_id, DRM_MODE_OBJECT_CRTC, 8, 4);
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 drmModePlaneRes *plane_resources;
00293 drmModePlane *ovr;
00294
00295 plane_resources = drmModeGetPlaneResources(this->drm.fd);
00296 if (!plane_resources) {
00297 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
00298 strerror(errno));
00299 return false;
00300 }
00301
00302
00303
00304 for (i = 0; i < plane_resources->count_planes; i++) {
00305 ovr = drmModeGetPlane(this->drm.fd, plane_resources->planes[i]);
00306 if (!ovr) {
00307 fprintf(stderr, "drmModeGetPlane failed: %s\n",
00308 strerror(errno));
00309 continue;
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 if (ovr->possible_crtcs & this->drm.crtc_id){
00339 this->drm.plane_id = ovr->plane_id;
00340 break;
00341 }
00342
00343
00344 }
00345
00346
00347
00348 return true;
00349 }
00350
00351 bool MMSKms::init_gbm()
00352 {
00353 this->drm.dev = gbm_create_device(this->drm.fd);
00354
00355 if (!init_omap()) {
00356 printf("failed to initialize OMAP\n");
00357 return false;
00358 }
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 if (outputtype == MMSFB_OT_OGL) {
00371 this->drm.surface = gbm_surface_create(this->drm.dev, this->drm.mode->hdisplay, this->drm.mode->vdisplay,
00372 GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
00373
00374 if (!this->drm.surface) {
00375 printf("failed to create gbm surface\n");
00376 drmClose(this->drm.fd);
00377 this->drm.fd = -1;
00378 return false;
00379 }
00380
00381 this->bo = gbm_surface_lock_front_buffer(this->drm.surface);
00382 this->fb = (DRM_FB*)drm_fb_get_from_bo(this->bo);
00383 gbm_surface_release_buffer(this->drm.surface, this->bo);
00384 }
00385
00386 return true;
00387 }
00388
00389 static void
00390 drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
00391 {
00392 DRM_FB *fb = (DRM_FB*)data;
00393 struct gbm_device *gbm = gbm_bo_get_device(bo);
00394 if(gbm) {
00395 int fd = gbm_device_get_fd(gbm);
00396 if (fb->fb_id)
00397 drmModeRmFB(fd, fb->fb_id);
00398 }
00399
00400 free(fb);
00401 }
00402
00403 DRM_FB* MMSKms::drm_fb_get_from_bo(struct gbm_bo *bo)
00404 {
00405 DRM_FB *fb = (DRM_FB*)gbm_bo_get_user_data(bo);
00406 uint32_t width, height, stride, handle;
00407 int ret;
00408
00409 if (fb)
00410 return fb;
00411
00412 fb = (DRM_FB*)calloc(1, sizeof *fb);
00413 fb->bo = bo;
00414
00415 width = gbm_bo_get_width(bo);
00416 height = gbm_bo_get_height(bo);
00417 stride = gbm_bo_get_stride(bo);
00418 handle = gbm_bo_get_handle(bo).u32;
00419
00420 ret = drmModeAddFB(this->drm.fd, width, height, 24, 32, stride, handle, &fb->fb_id);
00421 if (ret) {
00422 printf("failed to create fb: %s\n", strerror(errno));
00423 free(fb);
00424 return NULL;
00425 }
00426
00427 ret =0;
00428 ret = drmModeSetCrtc(this->drm.fd, this->drm.crtc_id, fb->fb_id, 0, 0,
00429 &this->drm.connector_id, 1, this->drm.mode);
00430
00431 if (ret) {
00432 printf("failed to set mode: %s\n", strerror(errno));
00433 }
00434
00435 if (this->rotate180) {
00436 drmModeObjectSetProperty(this->drm.fd, this->drm.plane_id, DRM_MODE_OBJECT_PLANE, 8, 4);
00437 }
00438
00439 if ((this->drm.width != this->drm.mode->hdisplay) || (this->drm.height != this->drm.mode->vdisplay)) {
00440 ret = drmModeSetPlane(this->drm.fd, this->drm.plane_id, this->drm.crtc_id,
00441 fb->fb_id, 0, 0, 0, this->drm.mode->hdisplay, this->drm.mode->vdisplay,
00442 0, (this->drm.mode->vdisplay-this->drm.height) << 16, this->drm.width << 16, this->drm.height << 16);
00443
00444 if (ret)
00445 printf("drmModeSetPlane failed\n");
00446 }
00447
00448 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
00449
00450 return fb;
00451 }
00452
00453 bool MMSKms::init_omap()
00454 {
00455 this->drm.o_dev = omap_device_new(this->drm.fd);
00456
00457 if (!this->drm.dev) {
00458 printf("ERROR:couldn't create omap device\n");
00459 return false;
00460 }
00461
00462 uint32_t bo_flags = OMAP_BO_TILED_32 | OMAP_BO_SCANOUT | OMAP_BO_WC;
00463
00464 if (bo_flags & OMAP_BO_TILED) {
00465 this->o_bo = omap_bo_new_tiled(this->drm.o_dev, this->drm.mode->hdisplay, this->drm.mode->vdisplay, bo_flags);
00466 } else {
00467 this->o_bo = omap_bo_new(this->drm.o_dev, this->drm.mode->hdisplay * this->drm.mode->vdisplay * 32 / 8, bo_flags);
00468 }
00469
00470 if (!this->o_bo) {
00471 printf("failed to create omap bo\n");
00472 drmClose(this->drm.fd);
00473 this->drm.fd = -1;
00474 return false;
00475 }
00476
00477
00478 uint32_t handle;
00479 int ret;
00480
00481 this->fb = (DRM_FB*)calloc(1, sizeof *this->fb);
00482
00483 unsigned int alignedWidth;
00484 alignedWidth = (this->drm.mode->hdisplay + (32 - 1)) & ~(32 - 1);
00485 this->stride = ((alignedWidth * 32) + 7) / 8;
00486 if (bo_flags & OMAP_BO_TILED)
00487 this->stride = (stride + (4096 - 1)) & ~(4096 - 1);
00488
00489 handle = omap_bo_handle(this->o_bo);
00490
00491 ret = drmModeAddFB(this->drm.fd, this->drm.mode->hdisplay, this->drm.mode->vdisplay, 24, 32, this->stride, handle, &fb->fb_id);
00492 if (ret) {
00493 printf("failed to create fb: %s\n", strerror(errno));
00494 free(this->fb);
00495 return false;
00496 }
00497
00498
00499 this->framebuffer_base = omap_bo_map(this->o_bo);
00500
00501
00502 return true;
00503 }
00504
00505 bool MMSKms::openDevice(MMSFBOutputType outputtype) {
00506
00507 this->outputtype = outputtype;
00508 closeDevice();
00509
00510 if (!init_drm()) {
00511 printf("failed to initialize DRM\n");
00512 return false;
00513 }
00514
00515 if (!init_gbm()) {
00516 printf("failed to initialize GBM\n");
00517 return false;
00518 }
00519
00520 memset(&this->evctx, 0, sizeof(this->evctx));
00521 this->evctx.version = DRM_EVENT_CONTEXT_VERSION;
00522 this->evctx.page_flip_handler = page_flip_handler;
00523
00524
00525 this->isinitialized = true;
00526
00527 return true;
00528 }
00529
00530 void MMSKms::closeDevice() {
00531
00532 if (this->drm.fd != -1) {
00533 drmClose(this->drm.fd);
00534 this->drm.fd = -1;
00535 }
00536
00537
00538 this->isinitialized = false;
00539 memset(this->layers, 0, sizeof(this->layers));
00540 this->layers_cnt = 0;
00541 this->active_screen = 0;
00542 }
00543
00544 bool MMSKms::isInitialized() {
00545 return this->isinitialized;
00546 }
00547
00548 bool MMSKms::panDisplay(int buffer_id, void *framebuffer_base) {
00549
00550 INITCHECK;
00551
00552
00553 if (framebuffer_base) {
00554 if (framebuffer_base != this->framebuffer_base) {
00555 printf("MMSFBDev: framebuffer base pointer not correct\n");
00556 return false;
00557 }
00558 }
00559
00560 fd_set fds;
00561 FD_ZERO(&fds);
00562 FD_SET(0, &fds);
00563 FD_SET(this->drm.fd, &fds);
00564
00565 int waiting_for_flip = 1;
00566 int ret = 0;
00567
00568 printf("MMSKMS: page flip (pan display)\n");
00569
00570 ret = drmModePageFlip(this->drm.fd, this->drm.crtc_id, this->fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
00571 if (ret) {
00572 printf("OPENGL_SWAP: failed to queue page flip\n");
00573 return false;
00574 }
00575
00576 while (waiting_for_flip) {
00577 ret = select(this->drm.fd + 1, &fds, NULL, NULL, NULL);
00578 if (ret < 0) {
00579 printf("OPENGL_SWAP: select err\n");
00580 return false;
00581 } else if (ret == 0) {
00582 printf("OPENGL_SWAP: select timeout!\n");
00583 return false;
00584 } else if (FD_ISSET(0, &fds)) {
00585 printf("OPENGL_SWAP: user interrupted!\n");
00586 break;
00587 }
00588 drmHandleEvent(this->drm.fd, &this->evctx);
00589 }
00590
00591 return true;
00592 }
00593
00594 bool MMSKms::testLayer(int layer_id) {
00595
00596 INITCHECK;
00597
00598
00599 if (layer_id != 0) {
00600 printf("MMSKms: layer %d is not supported\n", layer_id);
00601 return false;
00602 }
00603
00604 return true;
00605 }
00606
00607 bool MMSKms::initLayer(int layer_id, int width, int height, MMSFBSurfacePixelFormat pixelformat, int backbuffer) {
00608
00609 INITCHECK;
00610
00611
00612
00613 this->drm.width = width;
00614 this->drm.height = height;
00615
00616
00617 if (layer_id != 0) {
00618 printf("MMSKms: layer %d is not supported\n", layer_id);
00619 return false;
00620 }
00621
00622 int ret =0;
00623
00624
00625 ret = 0;
00626 ret = drmModeSetCrtc(this->drm.fd, this->drm.crtc_id, this->fb->fb_id, 0, 0,
00627 &this->drm.connector_id, 1, this->drm.mode);
00628
00629 if (ret) {
00630 printf("failed to set mode: %s\n", strerror(errno));
00631 return false;
00632 }
00633
00634 if (this->rotate180) {
00635 drmModeObjectSetProperty(this->drm.fd, this->drm.plane_id, DRM_MODE_OBJECT_PLANE, 8, 4);
00636 }
00637
00638 if ((this->drm.width != this->drm.mode->hdisplay) || (this->drm.height != this->drm.mode->vdisplay)) {
00639 ret = drmModeSetPlane(this->drm.fd, this->drm.plane_id, this->drm.crtc_id,
00640 this->fb->fb_id, 0, 0, 0, this->drm.mode->hdisplay, this->drm.mode->vdisplay,
00641 0, 0, this->drm.width << 16, this->drm.height << 16);
00642
00643 if (ret)
00644 printf("drmModeSetPlane failed\n");
00645 }
00646
00647 if (width <= 0 || height <= 0) {
00648
00649 this->layers[layer_id].isinitialized = false;
00650 return true;
00651 }
00652
00653
00654 this->layers[layer_id].width = width;
00655 this->layers[layer_id].height = height;
00656 this->layers[layer_id].pixelformat = pixelformat;
00657
00658
00659 memset(&this->layers[layer_id].buffers, 0, sizeof(this->layers[layer_id].buffers));
00660
00661 this->layers[layer_id].buffers[0].ptr = this->framebuffer_base;
00662 this->layers[layer_id].buffers[0].pitch= this->stride;
00663 this->layers[layer_id].buffers[0].hwbuffer = true;
00664
00665
00666 this->layers[layer_id].isinitialized = true;
00667
00668
00669 this->active_screen = 0;
00670
00671 return true;
00672 }
00673
00674 bool MMSKms::releaseLayer(int layer_id) {
00675 printf("MMSKms: layer %d cannot be released\n", layer_id);
00676 return false;
00677 }
00678
00679 bool MMSKms::restoreLayer(int layer_id) {
00680 printf("MMSKms: layer %d cannot be restored\n", layer_id);
00681 return false;
00682 }
00683
00684 bool MMSKms::getPixelFormat(int layer_id, MMSFBSurfacePixelFormat *pf) {
00685
00686 INITCHECK;
00687
00688
00689 if (!this->layers[layer_id].isinitialized)
00690 return false;
00691
00692
00693 *pf = this->layers[layer_id].pixelformat;
00694 return true;
00695 }
00696
00697 bool MMSKms::getFrameBufferPtr(int layer_id, MMSFBSurfacePlanesBuffer buffers, int *width, int *height) {
00698
00699 INITCHECK;
00700
00701
00702 if (!this->layers[layer_id].isinitialized) {
00703 return false;
00704 }
00705
00706
00707 if (buffers)
00708 memcpy(buffers, this->layers[layer_id].buffers, sizeof(this->layers[layer_id].buffers));
00709 *width = this->layers[layer_id].width;
00710 *height = this->layers[layer_id].height;
00711
00712 return true;
00713 }
00714
00715
00716 void MMSKms::genFBPixelFormat(MMSFBSurfacePixelFormat pf, unsigned int *nonstd_format, MMSFBPixelDef *pixeldef) {
00717
00718
00719 if (nonstd_format) *nonstd_format = 0;
00720 getBitsPerPixel(pf, pixeldef);
00721
00722
00723 this->onGenFBPixelFormat.emit(pf, nonstd_format, pixeldef);
00724 }
00725
00726 DRM *MMSKms::getDrm() {
00727 return &(this->drm);
00728 }
00729
00730 void MMSKms::pageFlip() {
00731
00732 fd_set fds;
00733 FD_ZERO(&fds);
00734 FD_SET(0, &fds);
00735 FD_SET(this->drm.fd, &fds);
00736
00737 DRM_FB *my_fb;
00738 struct gbm_bo *next_bo;
00739 int waiting_for_flip = 1;
00740
00741 next_bo = gbm_surface_lock_front_buffer(this->drm.surface);
00742 my_fb = (DRM_FB*)drm_fb_get_from_bo(next_bo);
00743
00744
00745
00746 int ret =0;
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 ret = 0;
00768 ret = drmModePageFlip(this->drm.fd, this->drm.crtc_id, my_fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
00769 if (ret) {
00770 printf("OPENGL_SWAP: failed to queue page flip\n");
00771 return;
00772 }
00773
00774 while (waiting_for_flip) {
00775 ret = select(this->drm.fd + 1, &fds, NULL, NULL, NULL);
00776 if (ret < 0) {
00777 printf("OPENGL_SWAP: select err\n");
00778 return;
00779 } else if (ret == 0) {
00780 printf("OPENGL_SWAP: select timeout!\n");
00781 return;
00782 } else if (FD_ISSET(0, &fds)) {
00783 printf("OPENGL_SWAP: user interrupted!\n");
00784 break;
00785 }
00786 drmHandleEvent(this->drm.fd, &this->evctx);
00787 }
00788
00789 gbm_surface_release_buffer(this->drm.surface, next_bo);
00790
00791 }
00792
00793 #endif