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