17949SN/A/*
212230Sgiacomo.travaglini@arm.com * Copyright (c) 2010, 2015, 2017 ARM Limited
37949SN/A * All rights reserved
47949SN/A *
57949SN/A * The license below extends only to copyright in the software and shall
67949SN/A * not be construed as granting a license to any other intellectual
77949SN/A * property including but not limited to intellectual property relating
87949SN/A * to a hardware implementation of the functionality of the software
97949SN/A * licensed hereunder.  You may use the software subject to the license
107949SN/A * terms below provided that you ensure that this notice is replicated
117949SN/A * unmodified and in its entirety in all distributions of the software,
127949SN/A * modified or unmodified, in source code or in binary form.
137949SN/A *
147949SN/A * Redistribution and use in source and binary forms, with or without
157949SN/A * modification, are permitted provided that the following conditions are
167949SN/A * met: redistributions of source code must retain the above copyright
177949SN/A * notice, this list of conditions and the following disclaimer;
187949SN/A * redistributions in binary form must reproduce the above copyright
197949SN/A * notice, this list of conditions and the following disclaimer in the
207949SN/A * documentation and/or other materials provided with the distribution;
217949SN/A * neither the name of the copyright holders nor the names of its
227949SN/A * contributors may be used to endorse or promote products derived from
237949SN/A * this software without specific prior written permission.
247949SN/A *
257949SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
267949SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
277949SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
287949SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
297949SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
307949SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
317949SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
327949SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
337949SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
347949SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
357949SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
367949SN/A *
377949SN/A * Authors: Ali Saidi
387949SN/A *          William Wang
397949SN/A */
407949SN/A
417949SN/A/** @file
429330Schander.sudanthi@arm.com * Implementiation of a VNC input
437949SN/A */
447949SN/A
4511793Sbrandon.potter@amd.com#include "base/vnc/vncinput.hh"
4611793Sbrandon.potter@amd.com
478635SN/A#include <sys/types.h>
487949SN/A
4912334Sgabeblack@google.com#include "base/logging.hh"
5011800Sbrandon.potter@amd.com#include "base/output.hh"
5112230Sgiacomo.travaglini@arm.com
529356Snilay@cs.wisc.edu#include "base/trace.hh"
538232SN/A#include "debug/VNC.hh"
547949SN/A
557949SN/Ausing namespace std;
567949SN/A
579330Schander.sudanthi@arm.comVncInput::VncInput(const Params *p)
589330Schander.sudanthi@arm.com    : SimObject(p), keyboard(NULL), mouse(NULL),
5910839Sandreas.sandberg@arm.com      fb(&FrameBuffer::dummy),
6010839Sandreas.sandberg@arm.com      _videoWidth(fb->width()), _videoHeight(fb->height()),
6110839Sandreas.sandberg@arm.com      captureEnabled(p->frame_capture),
6212230Sgiacomo.travaglini@arm.com      captureCurrentFrame(0), captureLastHash(0),
6312230Sgiacomo.travaglini@arm.com      imgFormat(p->img_format)
647949SN/A{
658635SN/A    if (captureEnabled) {
668635SN/A        // remove existing frame output directory if it exists, then create a
678635SN/A        //   clean empty directory
688635SN/A        const string FRAME_OUTPUT_SUBDIR = "frames_" + name();
698635SN/A        simout.remove(FRAME_OUTPUT_SUBDIR, true);
708635SN/A        captureOutputDirectory = simout.createSubdirectory(
718635SN/A                                FRAME_OUTPUT_SUBDIR);
728635SN/A    }
737949SN/A}
747949SN/A
757949SN/Avoid
7610839Sandreas.sandberg@arm.comVncInput::setFrameBuffer(const FrameBuffer *rfb)
777949SN/A{
7810839Sandreas.sandberg@arm.com    if (!rfb)
7910839Sandreas.sandberg@arm.com        panic("Trying to VNC frame buffer to NULL!");
807949SN/A
8110839Sandreas.sandberg@arm.com    fb = rfb;
8210839Sandreas.sandberg@arm.com
8312230Sgiacomo.travaglini@arm.com    // Create the Image Writer object in charge of dumping
8412230Sgiacomo.travaglini@arm.com    // the frame buffer raw data into a file in a specific format.
8512230Sgiacomo.travaglini@arm.com    if (captureEnabled) {
8612230Sgiacomo.travaglini@arm.com        captureImage = createImgWriter(imgFormat, rfb);
8712230Sgiacomo.travaglini@arm.com    }
8810839Sandreas.sandberg@arm.com
8910839Sandreas.sandberg@arm.com    // Setting a new frame buffer means that we need to send an update
9010839Sandreas.sandberg@arm.com    // to the client. Mark the internal buffers as dirty to do so.
9110839Sandreas.sandberg@arm.com    setDirty();
9210839Sandreas.sandberg@arm.com}
9310839Sandreas.sandberg@arm.com
9410839Sandreas.sandberg@arm.comvoid
9510839Sandreas.sandberg@arm.comVncInput::setDirty()
9610839Sandreas.sandberg@arm.com{
9710839Sandreas.sandberg@arm.com    const unsigned width(fb->width());
9810839Sandreas.sandberg@arm.com    const unsigned height(fb->height());
9910839Sandreas.sandberg@arm.com
10010839Sandreas.sandberg@arm.com    if (_videoWidth != width || _videoHeight != height) {
10110839Sandreas.sandberg@arm.com        DPRINTF(VNC, "Updating video params: width: %d height: %d\n",
10210839Sandreas.sandberg@arm.com                width, height);
10310839Sandreas.sandberg@arm.com
1047949SN/A        _videoWidth = width;
1057949SN/A        _videoHeight = height;
1067949SN/A
10710839Sandreas.sandberg@arm.com        frameBufferResized();
10810839Sandreas.sandberg@arm.com    }
1097949SN/A
11010839Sandreas.sandberg@arm.com     if (captureEnabled)
11110839Sandreas.sandberg@arm.com        captureFrameBuffer();
1127949SN/A}
1137949SN/A
1148635SN/Avoid
1159330Schander.sudanthi@arm.comVncInput::captureFrameBuffer()
1168635SN/A{
11712230Sgiacomo.travaglini@arm.com    assert(captureImage);
1188635SN/A
1198635SN/A    // skip identical frames
12010839Sandreas.sandberg@arm.com    uint64_t new_hash = fb->getHash();
1218635SN/A    if (captureLastHash == new_hash)
1228635SN/A        return;
1238635SN/A    captureLastHash = new_hash;
1248635SN/A
1258635SN/A    // get the filename for the current frame
1268635SN/A    char frameFilenameBuffer[64];
12712230Sgiacomo.travaglini@arm.com    snprintf(frameFilenameBuffer, 64, "fb.%06d.%lld.%s.gz",
12812230Sgiacomo.travaglini@arm.com            captureCurrentFrame, static_cast<long long int>(curTick()),
12912230Sgiacomo.travaglini@arm.com            captureImage->getImgExtension());
1308635SN/A    const string frameFilename(frameFilenameBuffer);
1318635SN/A
1328635SN/A    // create the compressed framebuffer file
13311359Sandreas@sandberg.pp.se    OutputStream *fb_out(captureOutputDirectory->create(frameFilename, true));
13412230Sgiacomo.travaglini@arm.com    captureImage->write(*fb_out->stream());
13511359Sandreas@sandberg.pp.se    captureOutputDirectory->close(fb_out);
1368635SN/A
1378635SN/A    ++captureCurrentFrame;
1388635SN/A}
1399330Schander.sudanthi@arm.com
1409330Schander.sudanthi@arm.com// create the VNC Replayer object
1419330Schander.sudanthi@arm.comVncInput *
1429330Schander.sudanthi@arm.comVncInputParams::create()
1439330Schander.sudanthi@arm.com{
1449330Schander.sudanthi@arm.com    return new VncInput(this);
1459330Schander.sudanthi@arm.com}
146