Home | History | Annotate | Download | only in nanomsg
      1 #include "nanomsg/src/nn.h"
      2 #include "nanomsg/src/pipeline.h"
      3 #include "nanomsg/src/reqrep.h"
      4 
      5 #include "SkCanvas.h"
      6 #include "SkCommandLineFlags.h"
      7 #include "SkData.h"
      8 #include "SkForceLinking.h"
      9 #include "SkGraphics.h"
     10 #include "SkImageEncoder.h"
     11 #include "SkOSFile.h"
     12 #include "SkPicture.h"
     13 #include "SkRandom.h"
     14 #include "SkStream.h"
     15 
     16 __SK_FORCE_IMAGE_DECODER_LINKING;
     17 
     18 // To keep things simple, PictureHeader is fixed-size POD.
     19 struct PictureHeader {
     20     SkMatrix         matrix;
     21     SkRect           clip;
     22     SkXfermode::Mode xfermode;
     23     pid_t            pid;
     24     uint8_t          alpha;
     25 
     26     PictureHeader()
     27         : matrix(SkMatrix::I())
     28         , clip(SkRect::MakeLargest())
     29         , xfermode(SkXfermode::kSrcOver_Mode)
     30         , pid(getpid())
     31         , alpha(0xFF) {}
     32 };
     33 
     34 // A little adaptor: nn_iovec wants a non-const pointer for no obvious reason.
     35 static struct nn_iovec create_iov(const void* ptr, size_t size) {
     36     struct nn_iovec iov = { const_cast<void*>(ptr), size };
     37     return iov;
     38 }
     39 
     40 static void send_picture(int socket, const PictureHeader& header, const SkData& skp) {
     41     // Vectored IO lets us send header and skp contiguously without first
     42     // copying them to a contiguous buffer.
     43     struct nn_iovec iov[] = {
     44         create_iov(&header, sizeof(header)),
     45         create_iov(skp.data(), skp.size()),
     46     };
     47 
     48     struct nn_msghdr msg;
     49     sk_bzero(&msg, sizeof(msg));
     50     msg.msg_iov    = iov;
     51     msg.msg_iovlen = SK_ARRAY_COUNT(iov);
     52 
     53     nn_sendmsg(socket, &msg, 0/*flags*/);
     54 }
     55 
     56 static SkPicture* recv_picture(int socket, PictureHeader* header) {
     57     static const size_t hSize = sizeof(*header);  // It's easy to slip up and use sizeof(header).
     58 
     59     void* msg;
     60     int size = nn_recv(socket, &msg, NN_MSG, 0/*flags*/);
     61     SkDebugf("%d bytes", size);
     62 
     63     // msg is first a fixed-size header, then an .skp.
     64     memcpy(header, msg, hSize);
     65     SkMemoryStream stream((uint8_t*)msg + hSize, size - hSize);
     66     SkPicture* pic = SkPicture::CreateFromStream(&stream);
     67 
     68     SkDebugf(" from proccess %d:", header->pid);
     69 
     70     nn_freemsg(msg);
     71     return pic;
     72 }
     73 
     74 static void client(const char* skpPath, const char* dataEndpoint) {
     75     // Read the .skp.
     76     SkAutoTUnref<const SkData> skp(SkData::NewFromFileName(skpPath));
     77     if (!skp) {
     78         SkDebugf("Couldn't read %s\n", skpPath);
     79         exit(1);
     80     }
     81     SkMemoryStream stream(skp->data(), skp->size());
     82     SkAutoTUnref<SkPicture> picture(SkPicture::CreateFromStream(&stream));
     83 
     84     PictureHeader header;
     85     SkRandom rand(picture->width() * picture->height());
     86     SkScalar r = rand.nextRangeScalar(0, picture->width()),
     87              b = rand.nextRangeScalar(0, picture->height()),
     88              l = rand.nextRangeScalar(0, r),
     89              t = rand.nextRangeScalar(0, b);
     90     header.clip.setLTRB(l,t,r,b);
     91     header.matrix.setTranslate(-l, -t);
     92     header.matrix.postRotate(rand.nextRangeScalar(-25, 25));
     93     header.alpha = 0x7F;
     94 
     95     //Clients use NN_REQ (request) type sockets.
     96     int socket = nn_socket(AF_SP, NN_REQ);
     97 
     98     // Clients connect a socket to an endpoint.
     99     nn_connect(socket, dataEndpoint);
    100 
    101     // Send the picture and its header.
    102     SkDebugf("Sending %s (%d bytes)...", skpPath, skp->size());
    103     send_picture(socket, header, *skp);
    104 
    105     // Wait for ack.
    106     uint8_t ack;
    107     nn_recv(socket, &ack, sizeof(ack), 0/*flags*/);
    108     SkDebugf(" ok.\n");
    109 }
    110 
    111 // Wait until socketA or socketB has something to tell us, and return which one.
    112 static int poll_in(int socketA, int socketB) {
    113     struct nn_pollfd polls[] = {
    114         { socketA, NN_POLLIN, 0 },
    115         { socketB, NN_POLLIN, 0 },
    116     };
    117 
    118     nn_poll(polls, SK_ARRAY_COUNT(polls), -1/*no timeout*/);
    119 
    120     if (polls[0].revents & NN_POLLIN) { return socketA; }
    121     if (polls[1].revents & NN_POLLIN) { return socketB; }
    122 
    123     SkFAIL("unreachable");
    124     return 0;
    125 }
    126 
    127 static void server(const char* dataEndpoint, const char* controlEndpoint, SkCanvas* canvas) {
    128     // NN_REP sockets receive a request then make a reply.  NN_PULL sockets just receive a request.
    129     int data    = nn_socket(AF_SP, NN_REP);
    130     int control = nn_socket(AF_SP, NN_PULL);
    131 
    132     // Servers bind a socket to an endpoint.
    133     nn_bind(data,    dataEndpoint);
    134     nn_bind(control, controlEndpoint);
    135 
    136     while (true) {
    137         int ready = poll_in(data, control);
    138 
    139         // If we got any message on the control socket, we can stop.
    140         if (ready == control) {
    141             break;
    142         }
    143 
    144         // We should have an .skp waiting for us on data socket.
    145         PictureHeader header;
    146         SkAutoTUnref<SkPicture> picture(recv_picture(data, &header));
    147 
    148         SkPaint paint;
    149         paint.setAlpha(header.alpha);
    150         paint.setXfermodeMode(header.xfermode);
    151 
    152         canvas->saveLayer(NULL, &paint);
    153             canvas->concat(header.matrix);
    154             canvas->clipRect(header.clip);
    155             picture->draw(canvas);
    156         canvas->restore();
    157         SkDebugf(" drew");
    158 
    159         // Send back an ack.
    160         uint8_t ack = 42;
    161         nn_send(data, &ack, sizeof(ack), 0/*flags*/);
    162         SkDebugf(" and acked.\n");
    163     }
    164 }
    165 
    166 static void stop(const char* controlEndpoint) {
    167     // An NN_PUSH socket can send messages but not receive them.
    168     int control = nn_socket(AF_SP, NN_PUSH);
    169     nn_connect(control, controlEndpoint);
    170 
    171     // Sending anything (including this 0-byte message) will tell server() to stop.
    172     nn_send(control, NULL, 0, 0/*flags*/);
    173 }
    174 
    175 DEFINE_string2(skp, r, "", ".skp to send (as client)");
    176 DEFINE_string2(png, w, "", ".png to write (as server)");
    177 DEFINE_bool(stop, false, "If true, tell server to stop and write its canvas out as a .png.");
    178 DEFINE_string(data,    "ipc://nanomsg-picture-data",    "Endpoint for sending pictures.");
    179 DEFINE_string(control, "ipc://nanomsg-picture-control", "Endpoint for control channel.");
    180 
    181 int main(int argc, char** argv) {
    182     SkAutoGraphics ag;
    183     SkCommandLineFlags::Parse(argc, argv);
    184 
    185     if (FLAGS_stop) {
    186         stop(FLAGS_control[0]);
    187     }
    188 
    189     if (!FLAGS_skp.isEmpty()) {
    190         client(FLAGS_skp[0], FLAGS_data[0]);
    191     }
    192 
    193     if (!FLAGS_png.isEmpty()) {
    194         SkBitmap bitmap;
    195         bitmap.allocN32Pixels(1000, 1000);
    196         SkCanvas canvas(bitmap);
    197         canvas.clear(0xFFFFFFFF);
    198 
    199         server(FLAGS_data[0], FLAGS_control[0], &canvas);
    200         canvas.flush();
    201 
    202         SkImageEncoder::EncodeFile(FLAGS_png[0], bitmap, SkImageEncoder::kPNG_Type, 100);
    203         SkDebugf("Wrote %s.\n", FLAGS_png[0]);
    204     }
    205 
    206     return 0;
    207 }
    208