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