OLD | NEW |
(Empty) | |
| 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 us
e 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, SkCanv
as* 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 st
op. |
| 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 pi
ctures."); |
| 179 DEFINE_string(control, "ipc://nanomsg-picture-control", "Endpoint for control ch
annel."); |
| 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_Ty
pe, 100); |
| 203 SkDebugf("Wrote %s.\n", FLAGS_png[0]); |
| 204 } |
| 205 |
| 206 return 0; |
| 207 } |
OLD | NEW |