From 2b907bdc5f455ae8d560d979ebd4c7f6c3e973c9 Mon Sep 17 00:00:00 2001 From: sidorares Date: Fri, 5 Aug 2011 13:20:30 +1000 Subject: [PATCH] working RenderTriangle test --- lib/x11/corereqs.js | 3 +- lib/x11/unpackbuffer.js | 2 + lib/x11/unpackstream.js | 4 + lib/x11/xcore.js | 6 +- test/render-simplest.pl | 46 ++++++++ test/render.js | 254 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 test/render-simplest.pl create mode 100644 test/render.js diff --git a/lib/x11/corereqs.js b/lib/x11/corereqs.js index dca9b43..7306089 100644 --- a/lib/x11/corereqs.js +++ b/lib/x11/corereqs.js @@ -234,7 +234,8 @@ module.exports = { ], CreatePixmap: [ - function(depth, pid, drawable, width, height) { + function(pid, drawable, depth, width, height) { + console.log(['CreatePixmap:', 'CCSLLSS', [53, depth, 4, pid, drawable, width, height]]); return [ 'CCSLLSS', [53, depth, 4, pid, drawable, width, height] ]; } ], diff --git a/lib/x11/unpackbuffer.js b/lib/x11/unpackbuffer.js index fbe47b1..706fcd8 100644 --- a/lib/x11/unpackbuffer.js +++ b/lib/x11/unpackbuffer.js @@ -26,6 +26,7 @@ module.exports.addUnpack = function(Buffer) data.push(this[offset++]); break; case 'S': + case 's': //TODO: 16bit signed unpack var b1 = this[offset++]; var b2 = this[offset++]; data.push(b2*256+b1); @@ -36,6 +37,7 @@ module.exports.addUnpack = function(Buffer) data.push(b1*256+b2); break; case 'L': + case 'l': //TODO: 32bit signed unpack var b1 = this[offset++]; var b2 = this[offset++]; var b3 = this[offset++]; diff --git a/lib/x11/unpackstream.js b/lib/x11/unpackstream.js index d20d975..b4c0a5d 100644 --- a/lib/x11/unpackstream.js +++ b/lib/x11/unpackstream.js @@ -8,6 +8,7 @@ argument_length.C = 1; argument_length.S = 2; argument_length.s = 2; argument_length.L = 4; +argument_length.l = 4; argument_length.x = 1; function ReadFormatRequest(format, callback) @@ -58,10 +59,12 @@ ReadFormatRequest.prototype.execute = function(bufferlist, tag1, tag2) this.data.push(bufferlist.getbyte()); break; case 'S': + case 's': var b1 = bufferlist.getbyte(); var b2 = bufferlist.getbyte(); this.data.push(b2*256+b1); break; + case 'l': case 'L': var b1 = bufferlist.getbyte(); var b2 = bufferlist.getbyte(); @@ -248,6 +251,7 @@ UnpackStream.prototype.pack = function(format, arguments) buf[offset++] = n & 0xff; buf[offset++] = (n >> 8) & 0xff; break; + case 'l': // TODO: implement signed INT32!!! case 'L': var n = arguments[arg++]; buf[offset++] = n & 0xff; diff --git a/lib/x11/xcore.js b/lib/x11/xcore.js index ce1077d..a5ab567 100644 --- a/lib/x11/xcore.js +++ b/lib/x11/xcore.js @@ -44,10 +44,14 @@ function XClient(stream, displayNum, screenNum) pack_stream.on('data', function( data ) { //console.error(hexy(data, {prefix: 'from packer '})); + for (var i=0; i < data.length; ++i) + console.error('<<< ' + data[i]); stream.write(data); }); stream.on('data', function( data ) { //console.error(hexy(data, {prefix: 'to unpacker '})); + for (var i=0; i < data.length; ++i) + console.error('>>> ' + data[i]); pack_stream.write(data); }); @@ -55,7 +59,7 @@ function XClient(stream, displayNum, screenNum) this.rcrc_id = 0; // generated for each new resource this.seq_num = 0; // incremented in each request. (even if we don't expect reply) - + // in/out packets indexed by sequence ID //this.requests = {}; this.replies = {}; diff --git a/test/render-simplest.pl b/test/render-simplest.pl new file mode 100644 index 0000000..666145e --- /dev/null +++ b/test/render-simplest.pl @@ -0,0 +1,46 @@ +#!/usr/bin/perl + +use X11::Protocol; +use strict; +use IO::Select; +my $X = new X11::Protocol; +$X->init_extension("RENDER") or die; + +my($rgb24, $rgba32); + +$rgb24 = 71; +$rgba32 = 69; + +my $win = $X->new_rsrc; +$X->CreateWindow($win, $X->root, 'InputOutput', $X->root_depth, + 'CopyFromParent', (0, 0), 500, 500, 4, + 'event_mask' => $X->pack_event_mask('Exposure')); + +$X->MapWindow($win); +my $picture = $X->new_rsrc; +$X->RenderCreatePicture($picture, $win, $rgb24);#, 'poly_edge' => 'Smooth', 'poly_mode' => 'Precise'); + +my $pixmap = $X->new_rsrc; +$X->CreatePixmap($pixmap, $win, 32, 1000, 1000); +my $pix_pict = $X->new_rsrc; +$X->RenderCreatePicture($pix_pict, $pixmap, $rgba32);#, 'poly_edge' => 'Smooth', 'poly_mode' => 'Precise'); +$X->RenderFillRectangles('Src', $pix_pict, [0xffff, 0, 0, 0x8000], [0, 0, 1000, 1000]); + +$X->event_handler('queue'); +#my $fds = IO::Select->new($X->connection->fh); + +sub draw { + $X->RenderFillRectangles('Src', $picture, [(0xffff)x4], [0, 0, 500, 500]); + $X->RenderTriangles('Over', $pix_pict, 500, 500, $picture, 0, [(250, 100), (100, 350), (400, 350)]); + #$X->RenderFillRectangles('Src', $picture, [(0xffff, 0, 0, 0xffff)], [10, 10, 50, 50]); +} + +for (;;) { + my %e; + $X->handle_input; + if (%e = $X->dequeue_event) { + if ($e{'name'} eq "Expose") { + draw(); + } + } +} diff --git a/test/render.js b/test/render.js new file mode 100644 index 0000000..6f94804 --- /dev/null +++ b/test/render.js @@ -0,0 +1,254 @@ +var x11 = require('../lib/x11'); + +// adding XRender functions manually from +// http://cgit.freedesktop.org/xcb/proto/tree/src/render.xml?id=HEAD +// and http://www.x.org/releases/X11R7.6/doc/renderproto/renderproto.txt +// TODO: move to templates +x11.createClient( + function(display) { + var X = display.client; + X.QueryExtension('RENDER', function(ext) { + function RenderQueryVersion(clientMaj, clientMin, callback) + { + X.seq_num++; + X.pack_stream.pack('CCSLL', [ext.majorOpcode, 0, 3, clientMaj, clientMin]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var res = buf.unpack('LL'); + return res; + }, + callback + ]; + X.pack_stream.flush(); + } + + function RenderQueryPictFormat(callback) + { + X.seq_num++; + X.pack_stream.pack('CCS', [ext.majorOpcode, 1, 1]); + X.replies[X.seq_num] = [ + function (buf, opt) { + var res1 = buf.unpack('LLLLL'); + // [ 28, 1, 7, 32, 0 ] + + console.log(res1); + return res1; + }, + callback + ]; + X.pack_stream.flush(); + } + + function RenderQueryFilters(callback) + { + X.seq_num++; + X.pack_stream.pack('CCSL', [ext.majorOpcode, 29, 2, display.screen[0].root]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var h = buf.unpack('LL'); + var num_aliases = h[0]; + var num_filters = h[1]; + var aliases = []; + var offset = 24; // LL + 16 bytes pad + for (var i=0; i < num_aliases; ++i) + { + aliases.push(buf.unpack('S', offset)[0]); + offset+=2; + } + var filters = []; + for (var i=0; i < num_filters; ++i) + { + var len = buf.unpack('C', offset)[0]; + //if (!len) break; + offset++; + filters.push(buf.toString('ascii', offset, offset+len)); + offset+=len; + } + return [aliases, filters]; + }, + callback + ]; + X.pack_stream.flush(); + } + + var valueList = [ + ['repeat', 'C'], + ['alphaMap', 'L'], + ['alphaXOrigin', 's'], + ['alphaYOrigin', 's'], + ['clipMask', 'L'], + ['graphicsExposures', 'C'], + ['subwindowMode', 'C'], + ['polyEdge', 'C'], + ['polyMode', 'C'], + ['dither', 'L'], + ['componentAlpha', 'C'] + ]; + + var argumentLength = { + C: 1, + S: 2, + s: 2, + L: 4, + x: 1 + }; + + function RenderCreatePicture(pid, drawable, pictformat, values) + { + X.seq_num++; + var mask = 0; + var reqLen = 5; // + (values + pad)/4 + var format = 'CCSLLLL'; + var params = [ext.majorOpcode, 4, reqLen, pid, drawable, pictformat, mask]; + + if (values) + { + var valuesLength = 0; + for (var i=0; i < valueList.length; ++i) + { + var val = values[valueList[i][0]]; + if (val) { + mask |= (1 << i); + params.push(val); + var valueFormat = valueList[i][1]; + format += valueFormat; + valuesLength += argumentLength[valueFormat]; + } + } + var pad4 = (valuesLength + 3) >> 2; + var toPad = (pad4 << 2) - valuesLength; + for (var i=0; i < toPad; ++i) + format += 'x'; + reqLen += pad4; + params[2] = reqLen; + params[6] = mask; + } + console.log([format, params]); + X.pack_stream.pack(format, params); + X.pack_stream.flush(); + } + + function floatToFix(f) + { + return parseInt(f*65536); + } + + function RenderLinearGradient(pid, p1, p2, stops) + { + X.seq_num++; + var reqLen = 7+stops.length*3; //header + params + 1xStopfix+2xColors + var format = 'CCSLLLLLL'; + var params = [ext.majorOpcode, 34, reqLen, pid]; + params.push(floatToFix(p1[0])); // L + params.push(floatToFix(p1[1])); + params.push(floatToFix(p2[0])); + params.push(floatToFix(p2[1])); // L + + params.push(stops.length); + + // [ [float stopDist, [float r, g, b, a] ], ...] + // stop distances + for (var i=0; i < stops.length; ++i) + { + format += 'L'; + // TODO: we know total params length in advance. ? params[index] = + params.push(floatToFix(stops[i][0])) + } + // colors + for (var i=0; i < stops.length; ++i) + { + format += 'SSSS'; + for (var j=0; j < 4; ++j) + params.push(stops[i][1][j]); + } + console.log([format, params]); + X.pack_stream.pack(format, params); + X.pack_stream.flush(); + } + + function RenderFillRectangles(op, pid, color, rects) + { + X.seq_num++; + var reqLen = 5+rects.length/2; + var format = 'CCSCxxxLSSSS'; + var params = [ext.majorOpcode, 26, reqLen, op, pid]; + for (var j=0; j < 4; ++j) + params.push(color[j]); + for (var i=0; i < rects.length; i+=4) + { + format += 'ssSS'; + params.push(rects[i*4]); + params.push(rects[i*4 + 1]); + params.push(rects[i*4 + 2]); + params.push(rects[i*4 + 3]); + } + console.log([format, params]); + X.pack_stream.pack(format, params); + X.pack_stream.flush(); + } + + function RenderComposite(op, src, mask, dst, srcX, srcY, maskX, maskY, dstX, dstY, width, height) + { + X.seq_num++; + X.pack_stream.pack( + 'CCSCxxxLLLssssssSS', + [ext.majorOpcode, 8, 9, op, mask, dst, srcX, srcY, maskX, maskY, dstX, dstY, width, height] + ) + .flush(); + } + + function RenderTriangles(op, src, srcX, srcY, dst, maskFormat, tris) + { + X.seq_num++; + var format = 'CCSCxxxLLLss'; + //var format = 'CCSCxxxLLLSS'; + var params = [ext.majorOpcode, 11, 6+tris.length, op, src, dst, maskFormat, srcX, srcY]; + for (var i=0; i < tris.length; i+=6) + { + format += 'llllll'; + //format += 'LLLLLL'; + //TODO: Array.copy + params.push(floatToFix(tris[i*6 + 0])); // x1 + params.push(floatToFix(tris[i*6 + 1])); // y1 + params.push(floatToFix(tris[i*6 + 2])); // x2 + params.push(floatToFix(tris[i*6 + 3])); // y2 + params.push(floatToFix(tris[i*6 + 4])); // x3 + params.push(floatToFix(tris[i*6 + 5])); // y3 + } + console.log([format, params]); + X.pack_stream.pack(format, params); + X.pack_stream.flush(); + } + + var root = display.screen[0].root; + var win = X.AllocID(); + var white = display.screen[0].white_pixel; + var black = display.screen[0].black_pixel; + X.CreateWindow(win, root, 0, 0, 300, 300, 4, 1, 0, { backgroundPixel: white, eventMask: x11.eventMask.Exposure }); + X.MapWindow(win); + + var picture = X.AllocID(); + RenderCreatePicture(picture, win, 71); //, { polyEdge: 1, polyMode: 0 } ); + var pixmap = X.AllocID(); + X.CreatePixmap(pixmap, win, 32, 1000, 1000); + var pix_pict = X.AllocID(); + console.log(['!!!!!!!!!!!!!!!', picture, pixmap, pix_pict]); + RenderCreatePicture(pix_pict, pixmap, 69); //, { polyEdge: 1, polyMode: 0 }); + RenderFillRectangles(1, pix_pict, [0xffff, 0, 0, 0x8000], [0, 0, 1000, 1000]); + + var pic_grad = X.AllocID(); + RenderLinearGradient(pic_grad, [0,0], [100,100], [ [0, [0,0,0,0xffff]], [100, [0xffff, 0xffff, 0xffff, 0xffff]]]); + + X.on('event', function(ev) { + console.log(ev); + RenderFillRectangles(1, picture, [0xffff, 0xffff, 0xffff, 0xffff], [0, 0, 500, 500]); + //RenderFillRectangles(1, picture, [0xffff, 0xffff, 0x0000, 0xffff], [10, 10, 50, 50]); + RenderTriangles(3, pix_pict, 500, 500, picture, 0, [250, 100, 100, 350, 400, 350]); + //RenderTriangles(3, pic_grad, 500, 500, picture, 0, [250, 100, 100, 350, 400, 350]); + }); + }); + } + +).on('error', function(err) { + console.log(['error! : ', err]); +});