diff options
-rw-r--r-- | hw/vigs/vigs_backend.h | 3 | ||||
-rw-r--r-- | hw/vigs/vigs_device.c | 25 | ||||
-rw-r--r-- | hw/vigs/vigs_gl_backend.c | 39 | ||||
-rw-r--r-- | hw/vigs/vigs_gl_backend_glx.c | 13 | ||||
-rw-r--r-- | hw/vigs/vigs_onscreen_server.c | 49 | ||||
-rw-r--r-- | hw/vigs/vigs_onscreen_server.h | 15 | ||||
-rw-r--r-- | hw/vigs/vigs_qt5.cpp | 23 | ||||
-rw-r--r-- | hw/vigs/vigs_qt5.h | 6 | ||||
-rw-r--r-- | hw/vigs/vigs_server.c | 11 | ||||
-rw-r--r-- | hw/vigs/vigs_server.h | 3 | ||||
-rw-r--r-- | hw/vigs/vigs_sw_backend.c | 9 | ||||
-rw-r--r-- | tizen/src/display/qt5_supplement.cpp | 31 | ||||
-rw-r--r-- | tizen/src/ui/mainwindow.cpp | 42 | ||||
-rw-r--r-- | tizen/src/ui/mainwindow.h | 7 | ||||
-rw-r--r-- | tizen/src/ui/menu/contextmenu.cpp | 11 | ||||
-rw-r--r-- | tizen/src/ui/menu/contextmenu.h | 1 |
16 files changed, 285 insertions, 3 deletions
diff --git a/hw/vigs/vigs_backend.h b/hw/vigs/vigs_backend.h index c300195f35..bbbd90abfe 100644 --- a/hw/vigs/vigs_backend.h +++ b/hw/vigs/vigs_backend.h @@ -54,6 +54,9 @@ struct vigs_backend bool /*planes_dirty*/, uint8_t */*display_data*/); + bool (*capture)(struct vigs_surface */*surface*/, + void */*pixels*/); + void (*batch_end)(struct vigs_backend */*backend*/); bool (*display)(struct vigs_backend */*backend*/, diff --git a/hw/vigs/vigs_device.c b/hw/vigs/vigs_device.c index 90bd2af6aa..8e190df32f 100644 --- a/hw/vigs/vigs_device.c +++ b/hw/vigs/vigs_device.c @@ -291,6 +291,23 @@ static void vigs_io_write(void *opaque, hwaddr offset, } } +static void vigs_register_capture_request_listener(void *listener, + void (*handler)(void *)) +{ + return vigs_qt5_register_capture_request_listener(listener, handler); +} + +static void vigs_unregister_capture_request_listener(void *listener) +{ + return vigs_qt5_unregister_capture_request_listener(listener); +} + +static void vigs_process_captured(bool captured, void *pixels, + uint32_t width, uint32_t height) +{ + return vigs_qt5_process_captured(captured, pixels, width, height); +} + static struct GraphicHwOps vigs_hw_ops = { .invalidate = vigs_hw_invalidate, @@ -319,6 +336,13 @@ static struct vigs_display_ops vigs_dpy_ops = .fence_ack = vigs_fence_ack, }; +static struct vigs_onscreen_server_capture_ops vigs_capture_ops = +{ + .register_listener = vigs_register_capture_request_listener, + .unregister_listener = vigs_unregister_capture_request_listener, + .process_captured = vigs_process_captured, +}; + static int vigs_device_init(PCIDevice *dev) { VIGSState *s = DO_UPCAST(VIGSState, dev, dev); @@ -457,6 +481,7 @@ static int vigs_device_init(PCIDevice *dev) memory_region_get_ram_ptr(&s->ram_bar), &vigs_dpy_ops, s, + &vigs_capture_ops, backend, wqobj->wq); } else { diff --git a/hw/vigs/vigs_gl_backend.c b/hw/vigs/vigs_gl_backend.c index 24f8b16b78..d80db57170 100644 --- a/hw/vigs/vigs_gl_backend.c +++ b/hw/vigs/vigs_gl_backend.c @@ -2234,6 +2234,44 @@ out: return false; } +static bool vigs_gl_backend_capture(struct vigs_surface *surface, + void *pixels) +{ + struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)surface->backend; + + if (gl_backend->read_pixels_make_current(gl_backend, true)) { + + if (!gl_backend->dpy_fb) { + gl_backend->GenFramebuffers(1, &gl_backend->dpy_fb); + + if (!gl_backend->dpy_fb) { + VIGS_LOG_ERROR("cannot create capture FB"); + + gl_backend->read_pixels_make_current(gl_backend, false); + + return false; + } + + } + + gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_backend->dpy_fb); + gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, gl_backend->dpy_tex, 0); + + gl_backend->ReadPixels(0, 0, gl_backend->dpy_tex_width, + gl_backend->dpy_tex_height, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, + pixels); + gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); + + gl_backend->read_pixels_make_current(gl_backend, false); + + return true; + } + + return false; +} + static void vigs_gl_backend_batch_end(struct vigs_backend *backend) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend; @@ -2623,6 +2661,7 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend) gl_backend->base.batch_start = &vigs_gl_backend_batch_start; gl_backend->base.create_surface = &vigs_gl_backend_create_surface; gl_backend->base.composite = &vigs_gl_backend_composite; + gl_backend->base.capture = &vigs_gl_backend_capture; gl_backend->base.batch_end = &vigs_gl_backend_batch_end; gl_backend->base.display = &vigs_gl_backend_display; diff --git a/hw/vigs/vigs_gl_backend_glx.c b/hw/vigs/vigs_gl_backend_glx.c index 4306420d66..b065dd977c 100644 --- a/hw/vigs/vigs_gl_backend_glx.c +++ b/hw/vigs/vigs_gl_backend_glx.c @@ -552,6 +552,19 @@ struct vigs_backend *vigs_gl_backend_create(void *display) if (!config) { goto fail2; } + + if (!vigs_gl_backend_glx_create_surface(gl_backend_glx, + config, + &gl_backend_glx->read_pixels_sfc)) { + goto fail2; + } + + if (!vigs_gl_backend_glx_create_context(gl_backend_glx, + config, + gl_backend_glx->ctx, + &gl_backend_glx->read_pixels_ctx)) { + goto fail2; + } } else { config = vigs_gl_backend_glx_get_config(gl_backend_glx); diff --git a/hw/vigs/vigs_onscreen_server.c b/hw/vigs/vigs_onscreen_server.c index 984fd1bed2..8a06219b26 100644 --- a/hw/vigs/vigs_onscreen_server.c +++ b/hw/vigs/vigs_onscreen_server.c @@ -29,6 +29,33 @@ #include "vigs_onscreen_server.h" #include "vigs_backend.h" +#include "vigs_log.h" +#include "work_queue.h" + +struct vigs_capture_work_item +{ + struct work_queue_item base; + + struct vigs_onscreen_server *server; +}; + +static void vigs_onscreen_server_capture_work(struct work_queue_item *wq_item) +{ + struct vigs_capture_work_item *item = (struct vigs_capture_work_item*)wq_item; + struct vigs_onscreen_server *server = item->server; + struct vigs_surface *root_sfc = server->base.root_sfc; + bool captured = false; + uint32_t width, height; + void *pixels; + + pixels = vigs_server_get_capture_buffer(&server->base, &width, &height); + if (root_sfc && pixels) { + captured = server->base.backend->capture(root_sfc, pixels); + } + server->capture_ops->process_captured(captured, pixels, width, height); + + g_free(item); +} static bool vigs_onscreen_server_begin_update(struct vigs_server *server, bool is_capturing, @@ -136,11 +163,27 @@ static bool vigs_onscreen_server_display(struct vigs_server *server, return false; } +static void vigs_onscreen_server_capture(void *data) +{ + struct vigs_onscreen_server *server = (struct vigs_onscreen_server*)data; + struct vigs_capture_work_item *item; + + item = g_malloc(sizeof(*item)); + + work_queue_item_init(&item->base, &vigs_onscreen_server_capture_work); + + item->server = server; + + work_queue_add_item(server->capture_queue, &item->base); +} + static void vigs_onscreen_server_destroy(struct vigs_server *server) { struct vigs_onscreen_server *onscreen_server = (struct vigs_onscreen_server*)server; + onscreen_server->capture_ops->unregister_listener(onscreen_server); + qemu_cond_destroy(&onscreen_server->cond); qemu_mutex_destroy(&onscreen_server->mutex); @@ -153,6 +196,7 @@ struct vigs_server *vigs_onscreen_server_create(uint8_t *vram_ptr, uint8_t *ram_ptr, struct vigs_display_ops *display_ops, void *display_user_data, + struct vigs_onscreen_server_capture_ops *capture_ops, struct vigs_backend *backend, struct work_queue *render_queue) { @@ -175,5 +219,10 @@ struct vigs_server *vigs_onscreen_server_create(uint8_t *vram_ptr, server->base.display = &vigs_onscreen_server_display; server->base.destroy = &vigs_onscreen_server_destroy; + server->capture_queue = work_queue_create("capture_queue"); + server->capture_ops = capture_ops; + server->capture_ops->register_listener(server, + vigs_onscreen_server_capture); + return &server->base; } diff --git a/hw/vigs/vigs_onscreen_server.h b/hw/vigs/vigs_onscreen_server.h index a3b443332c..57e6abeaad 100644 --- a/hw/vigs/vigs_onscreen_server.h +++ b/hw/vigs/vigs_onscreen_server.h @@ -32,6 +32,17 @@ #include "vigs_server.h" +struct vigs_onscreen_server_capture_ops +{ + void (*register_listener)(void */*listener*/, + void (*handler)(void */*listener*/)); + void (*unregister_listener)(void */*listener*/); + void (*process_captured)(bool /*captured*/, + void */*pixels*/, + uint32_t /*width*/, + uint32_t /*height*/); +}; + struct vigs_onscreen_server { struct vigs_server base; @@ -43,12 +54,16 @@ struct vigs_onscreen_server bool dirty; int invalidate_cnt; + + struct vigs_onscreen_server_capture_ops *capture_ops; + struct work_queue *capture_queue; }; struct vigs_server *vigs_onscreen_server_create(uint8_t *vram_ptr, uint8_t *ram_ptr, struct vigs_display_ops *display_ops, void *display_user_data, + struct vigs_onscreen_server_capture_ops *capture_ops, struct vigs_backend *backend, struct work_queue *render_queue); diff --git a/hw/vigs/vigs_qt5.cpp b/hw/vigs/vigs_qt5.cpp index 2df737510f..e31184dc16 100644 --- a/hw/vigs/vigs_qt5.cpp +++ b/hw/vigs/vigs_qt5.cpp @@ -38,6 +38,12 @@ extern QApplication *qt5App; extern QOpenGLContext *qt5GLContext; extern QSurfaceFormat qt5GLFormat; +extern void qt5_register_capture_request_listener(void *listener, + void (*handler)(void *)); +extern void qt5_unregister_capture_request_listener(void *listener); +extern void qt5_process_captured(bool captured, void *pixels, + int width, int height); + bool vigs_qt5_enabled(void) { return qt5App != NULL; @@ -138,3 +144,20 @@ void *vigs_qt5_gl_context_create(bool is_gl2) return ret; } + +void vigs_qt5_register_capture_request_listener(void *listener, + void (*handler)(void *)) +{ + qt5_register_capture_request_listener(listener, handler); +} + +void vigs_qt5_unregister_capture_request_listener(void *listener) +{ + qt5_unregister_capture_request_listener(listener); +} + +void vigs_qt5_process_captured(bool captured, void *pixels, + int width, int height) +{ + qt5_process_captured(captured, pixels, width, height); +} diff --git a/hw/vigs/vigs_qt5.h b/hw/vigs/vigs_qt5.h index 741cf56197..57b4a5b690 100644 --- a/hw/vigs/vigs_qt5.h +++ b/hw/vigs/vigs_qt5.h @@ -40,6 +40,12 @@ void *vigs_qt5_display(void); void *vigs_qt5_gl_context_create(bool is_gl2); +void vigs_qt5_register_capture_request_listener(void *listener, + void (*handler)(void *)); +void vigs_qt5_unregister_capture_request_listener(void *listener); +void vigs_qt5_process_captured(bool captured, void *pixels, + int width, int height); + #ifdef __cplusplus }; #endif diff --git a/hw/vigs/vigs_server.c b/hw/vigs/vigs_server.c index 4839e69f5d..50488f9d39 100644 --- a/hw/vigs/vigs_server.c +++ b/hw/vigs/vigs_server.c @@ -771,6 +771,17 @@ bool vigs_server_display(struct vigs_server *server, bool *displayed) return server->display(server, displayed); } +void *vigs_server_get_capture_buffer(struct vigs_server *server, + uint32_t *width, uint32_t *height) +{ + int index = (&server->capture_buffers[0] == server->captured) ? 1 : 0; + + *width = server->capture_buffers[index].width; + *height = server->capture_buffers[index].height; + + return server->capture_buffers[index].data; +} + bool vigs_server_process_captured(struct vigs_server *server, bool force) { bool updated = false; diff --git a/hw/vigs/vigs_server.h b/hw/vigs/vigs_server.h index 5c2248510b..8b6af81363 100644 --- a/hw/vigs/vigs_server.h +++ b/hw/vigs/vigs_server.h @@ -148,6 +148,9 @@ bool vigs_server_update_display(struct vigs_server *server, int invalidate_cnt); bool vigs_server_display(struct vigs_server *server, bool *displayed); +void *vigs_server_get_capture_buffer(struct vigs_server *server, + uint32_t *width, uint32_t *height); + /* * For internal use only. * @{ diff --git a/hw/vigs/vigs_sw_backend.c b/hw/vigs/vigs_sw_backend.c index fa8cfb8566..2261ebcb71 100644 --- a/hw/vigs/vigs_sw_backend.c +++ b/hw/vigs/vigs_sw_backend.c @@ -401,6 +401,14 @@ static bool vigs_sw_backend_composite(struct vigs_surface *surface, return true; } +static bool vigs_sw_backend_capture(struct vigs_surface *surface, + void *pixels) +{ + vigs_sw_backend_composite(surface, NULL, false, pixels); + + return true; +} + static void vigs_sw_backend_batch_end(struct vigs_backend *backend) { } @@ -430,6 +438,7 @@ struct vigs_backend *vigs_sw_backend_create(void) backend->base.batch_start = &vigs_sw_backend_batch_start; backend->base.create_surface = &vigs_sw_backend_create_surface; backend->base.composite = &vigs_sw_backend_composite; + backend->base.capture = &vigs_sw_backend_capture; backend->base.batch_end = &vigs_sw_backend_batch_end; backend->base.display = &vigs_sw_backend_display; backend->base.destroy = &vigs_sw_backend_destroy; diff --git a/tizen/src/display/qt5_supplement.cpp b/tizen/src/display/qt5_supplement.cpp index b5bb7188ca..b21bc447e1 100644 --- a/tizen/src/display/qt5_supplement.cpp +++ b/tizen/src/display/qt5_supplement.cpp @@ -55,6 +55,9 @@ QApplication *qt5App = NULL; static int argc = 0; static char *argv[0]; +static void *captureRequestListener; +static void (*captureRequestHandler)(void *); + static MainWindow *mainwindow; static UIInformation *uiInfo; @@ -173,6 +176,7 @@ void qt5_gui_init(void) qDebug("start!"); mainwindow = new MainWindow(uiInfo); + mainwindow->setCaptureRequestHandler(captureRequestListener, captureRequestHandler); /* position */ QRect hostBounds = UIUtil::getHostScreenBounds(); @@ -288,6 +292,33 @@ void qt5_refresh_internal(void) qt5App->processEvents(); } +void qt5_register_capture_request_listener(void *listener, void (*handler)(void *)) +{ + if (mainwindow) { + mainwindow->setCaptureRequestHandler(listener, handler); + } + + captureRequestListener = listener; + captureRequestHandler = handler; +} + +void qt5_unregister_capture_request_listener(void *listener) +{ + if (mainwindow) { + mainwindow->unsetCaptureRequestHandler(listener); + } + + captureRequestListener = NULL; + captureRequestHandler = NULL; +} + +void qt5_process_captured(bool captured, void *pixels, int width, int height) +{ + if (mainwindow) { + mainwindow->processCaptured(captured, pixels, width, height); + } +} + void qMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QByteArray localMsg = msg.toLocal8Bit(); diff --git a/tizen/src/ui/mainwindow.cpp b/tizen/src/ui/mainwindow.cpp index c00cc2dd36..d514824774 100644 --- a/tizen/src/ui/mainwindow.cpp +++ b/tizen/src/ui/mainwindow.cpp @@ -81,6 +81,9 @@ MainWindow::MainWindow(UIInformation *uiInfo, QWidget *parent) skinView = NULL; display = NULL; + captureRequestHandler = NULL; + captureRequestData = NULL; + /* windowing */ setWindowTitle("Emulator"); setWindowIcon(QIcon(QPixmap(":/icons/emulator_icon.ico"))); @@ -323,6 +326,45 @@ void MainWindow::scale(int scale) adjustSize(); } +void MainWindow::capture(void) +{ + qDebug("window screen capture: handler(%p), data(%p)", + captureRequestHandler, captureRequestData); + + if (captureRequestHandler && captureRequestData) { + captureRequestHandler(captureRequestData); + } +} + +void MainWindow::setCaptureRequestHandler(void *data, void (*handler)(void *)) +{ + captureRequestHandler = handler; + captureRequestData = data; +} + +void MainWindow::unsetCaptureRequestHandler(void *data) +{ + captureRequestHandler = NULL; + captureRequestData = NULL; +} + +void MainWindow::processCaptured(bool captured, void *pixels, + int width, int height) +{ + qDebug("window process captured: %d %p[%dx%d]", + captured, pixels, width, height); + + if (captured) { + /* TODO Perform what is needed here */ + QString path("/tmp/screenshot.png"); + QImage image = QImage((uchar *)pixels, width, height, + QImage::Format_RGB32); + bool saved = image.save(path, "PNG"); + + qDebug() << path << " " << saved; + } +} + void MainWindow::setTopMost(bool on) { popupMenu->slotTopMost(on); diff --git a/tizen/src/ui/mainwindow.h b/tizen/src/ui/mainwindow.h index 4a636403dc..6b50dcec6b 100644 --- a/tizen/src/ui/mainwindow.h +++ b/tizen/src/ui/mainwindow.h @@ -76,6 +76,10 @@ public: UIState *getUIState(void); void rotate(int angle); void scale(int scale); + void capture(void); + void setCaptureRequestHandler(void *data, void (*handler)(void *)); + void unsetCaptureRequestHandler(void *data); + void processCaptured(bool captured, void *pixels, int width, int height); void setTopMost(bool on); DockingController *getDockingCon(); FloatingController *getFloatingCon(); @@ -107,6 +111,9 @@ private: QThread *swapperThread; DisplaySwapper *swapper; + + void (*captureRequestHandler)(void *data); + void *captureRequestData; }; #endif // MAINWINDOW_H diff --git a/tizen/src/ui/menu/contextmenu.cpp b/tizen/src/ui/menu/contextmenu.cpp index aebfac4eba..82a19c3128 100644 --- a/tizen/src/ui/menu/contextmenu.cpp +++ b/tizen/src/ui/menu/contextmenu.cpp @@ -179,12 +179,10 @@ void ContextMenu::createItems() { /* = Advanced menu = */ QMenu *advancedMenu = addMenu(QIcon(QPixmap(":/icons/advanced.png")), "Ad&vanced"); -#if 0 /* Advanced > Screen Shot menu */ action = advancedMenu->addAction("Screen Shot"); action->setIcon(QIcon(QPixmap(":/icons/screen_shot.png"))); - // TODO: -#endif + connect(action, SIGNAL(triggered()), this, SLOT(slotScreenshot())); /* = Host Keyboard menu = */ QMenu *keyboardMenu = advancedMenu->addMenu( @@ -470,6 +468,13 @@ void ContextMenu::slotControlPanel() } } +void ContextMenu::slotScreenshot() +{ + qDebug("screenshot"); + + parent->capture(); +} + void ContextMenu::slotHostKeyboard(bool on) { qDebug("host keyboard : %s", on? "on" : "off"); diff --git a/tizen/src/ui/menu/contextmenu.h b/tizen/src/ui/menu/contextmenu.h index 2edb4321ce..a8e4212f88 100644 --- a/tizen/src/ui/menu/contextmenu.h +++ b/tizen/src/ui/menu/contextmenu.h @@ -69,6 +69,7 @@ public slots: void slotCloseCon(); void slotShell(); void slotControlPanel(); + void slotScreenshot(); void slotHostKeyboard(bool on); void slotAbout(); void slotForceClose(); |