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->cullRect().width() * picture->cullRect().height()); 86 SkScalar r = rand.nextRangeScalar(0, picture->cullRect().width()), 87 b = rand.nextRangeScalar(0, picture->cullRect().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->playback(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