summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Levy <alevy@redhat.com>2011-05-12 11:17:46 +0300
committerAlon Levy <alevy@redhat.com>2011-08-26 16:22:11 +0300
commit25036820ffd594bd5da4fe3586c463ab6e2ff8eb (patch)
treee9932f96834d5e9fb72350e8044673622df82913
parent9765dede7556f7ccfef1d90bab14a2bfa03384e5 (diff)
gallium/drivers/remote with s/uint64/uint64_t
-rw-r--r--src/gallium/drivers/remote/README64
-rw-r--r--src/gallium/drivers/remote/debug.c330
-rw-r--r--src/gallium/drivers/remote/remote_comms.c646
-rw-r--r--src/gallium/drivers/remote/remote_comms.h17
-rw-r--r--src/gallium/drivers/remote/remote_debug.h15
-rw-r--r--src/gallium/drivers/remote/remote_messages.h861
-rw-r--r--src/gallium/drivers/remote/remote_state.h47
-rw-r--r--src/gallium/drivers/remote/remote_util.h30
-rw-r--r--src/gallium/drivers/remote/tr_context.c1195
-rw-r--r--src/gallium/drivers/remote/tr_context.h69
-rw-r--r--src/gallium/drivers/remote/tr_screen.c848
-rw-r--r--src/gallium/drivers/remote/tr_screen.h97
-rw-r--r--src/gallium/drivers/remote/winsys_bindings.h10
13 files changed, 4229 insertions, 0 deletions
diff --git a/src/gallium/drivers/remote/README b/src/gallium/drivers/remote/README
new file mode 100644
index 0000000000..e7a2f12b02
--- /dev/null
+++ b/src/gallium/drivers/remote/README
@@ -0,0 +1,64 @@
+ TRACE PIPE DRIVER
+
+
+= About =
+
+This directory contains a Gallium3D pipe driver which traces all incoming calls.
+
+
+= Build Instructions =
+
+To build, invoke scons on the top dir as
+
+ scons statetrackers=mesa drivers=softpipe,i915simple,trace winsys=xlib
+
+
+= Usage =
+
+To use do
+
+ ln -s libGL.so build/linux-x86-debug/gallium/winsys/xlib/libGL.so.1
+ export LD_LIBRARY_PATH=$PWD/build/linux-x86-debug/gallium/winsys/xlib
+
+ensure the right libGL.so is being picked by doing
+
+ ldd progs/trivial/tri
+
+and then try running
+
+ GALLIUM_TRACE=tri.trace progs/trivial/tri
+
+which should create a tri.trace file, which is an XML file. You can view copying
+trace.xsl to the same directory, and opening with a XSLT capable browser such as
+Firefox or Internet Explorer.
+
+
+= Integrating =
+
+You can integrate the trace pipe driver either inside the state tracker or the
+winsys. The procedure on both cases is the same. Let's assume you have a
+pipe_screen and a pipe_context pair obtained by the usual means (variable and
+function names are just for illustration purposes):
+
+ real_screen = real_screen_create(...);
+
+ real_context = real_context_create(...);
+
+The trace screen and pipe_context is then created by doing
+
+ trace_screen = trace_screen_create(real_screen);
+
+ trace_context = trace_context_create(trace_screen, real_context);
+
+You can then simply use trace_screen and trace_context instead of real_screen
+and real_context.
+
+Do not call trace_winsys_create. Simply pass trace_screen->winsys or
+trace_context->winsys in places you would pass winsys.
+
+You can create as many contexts you wish. Just ensure that you don't mistake
+trace_screen with real_screen when creating them.
+
+
+--
+Jose Fonseca <jrfonseca@tungstengraphics.com>
diff --git a/src/gallium/drivers/remote/debug.c b/src/gallium/drivers/remote/debug.c
new file mode 100644
index 0000000000..06c7cddbae
--- /dev/null
+++ b/src/gallium/drivers/remote/debug.c
@@ -0,0 +1,330 @@
+
+#include "remote_messages.h"
+
+char* optotext(unsigned opcode) {
+
+ switch(opcode) {
+
+ case REMREQ_SET_EDGEFLAGS:
+
+ return "REMREQ_SET_EDGEFLAGS";
+
+ case REMREQ_DRAW_ARRAYS:
+
+ return "REMREQ_DRAW_ARRAYS";
+
+ case REMREP_DRAW_ARRAYS:
+
+ return "REMREP_DRAW_ARRAYS";
+
+ case REMREQ_DRAW_ELEMENTS:
+
+ return "REMREQ_DRAW_ELEMENTS";
+
+ case REMREP_DRAW_ELEMENTS:
+
+ return "REMREP_DRAW_ELEMENTS";
+
+ case REMREQ_DRAW_RANGE_ELEMENTS:
+
+ return "REMREQ_DRAW_RANGE_ELEMENTS";
+
+ case REMREP_DRAW_RANGE_ELEMENTS:
+
+ return "REMREP_DRAW_RANGE_ELEMENTS";
+
+ case REMREQ_CREATE_QUERY:
+
+ return "REMREQ_CREATE_QUERY";
+
+ case REMREQ_DESTROY_QUERY:
+
+ return "REMREQ_DESTROY_QUERY";
+
+ case REMREQ_BEGIN_QUERY:
+
+ return "REMREQ_BEGIN_QUERY";
+
+ case REMREQ_END_QUERY:
+
+ return "REMREQ_END_QUERY";
+
+ case REMREQ_GET_QUERY_RESULT:
+
+ return "REMREQ_GET_QUERY_RESULT";
+
+ case REMREP_GET_QUERY_RESULT:
+
+ return "REMREP_GET_QUERY_RESULT";
+
+ case REMREQ_CREATE_BLEND_STATE:
+
+ return "REMREQ_CREATE_BLEND_STATE";
+
+ case REMREQ_BIND_BLEND_STATE:
+
+ return "REMREQ_BIND_BLEND_STATE";
+
+ case REMREQ_DELETE_BLEND_STATE:
+
+ return "REMREQ_DELETE_BLEND_STATE";
+
+ case REMREQ_CREATE_SAMPLER_STATE:
+
+ return "REMREQ_CREATE_SAMPLER_STATE";
+
+ case REMREQ_BIND_SAMPLER_STATE:
+
+ return "REMREQ_BIND_SAMPLER_STATE";
+
+ case REMREQ_DELETE_SAMPLER_STATE:
+
+ return "REMREQ_DELETE_SAMPLER_STATE";
+
+ case REMREQ_CREATE_RAST_STATE:
+
+ return "REMREQ_CREATE_RAST_STATE";
+
+ case REMREQ_BIND_RAST_STATE:
+
+ return "REMREQ_BIND_RAST_STATE";
+
+ case REMREQ_DELETE_RAST_STATE:
+
+ return "REMREQ_DELETE_RAST_STATE";
+
+ case REMREQ_CREATE_DSA_STATE:
+
+ return "REMREQ_CREATE_DSA_STATE";
+
+ case REMREQ_BIND_DSA_STATE:
+
+ return "REMREQ_BIND_DSA_STATE";
+
+ case REMREQ_DELETE_DSA_STATE:
+
+ return "REMREQ_DELETE_DSA_STATE";
+
+ case REMREQ_CREATE_FS_STATE:
+
+ return "REMREQ_CREATE_FS_STATE";
+
+ case REMREQ_BIND_FS_STATE:
+
+ return "REMREQ_BIND_FS_STATE";
+
+ case REMREQ_DELETE_FS_STATE:
+
+ return "REMREQ_DELETE_FS_STATE";
+
+ case REMREQ_CREATE_VS_STATE:
+
+ return "REMREQ_CREATE_VS_STATE";
+
+ case REMREQ_BIND_VS_STATE:
+
+ return "REMREQ_BIND_VS_STATE";
+
+ case REMREQ_DELETE_VS_STATE:
+
+ return "REMREQ_DELETE_VS_STATE";
+
+ case REMREQ_SET_BLEND_COLOR:
+
+ return "REMREQ_SET_BLEND_COLOR";
+
+ case REMREQ_SET_CLIP_STATE:
+
+ return "REMREQ_SET_CLIP_STATE";
+
+ case REMREQ_SET_POLYGON_STIPPLE:
+
+ return "REMREQ_SET_POLYGON_STIPPLE";
+
+ case REMREQ_SET_SCISSOR_STATE:
+
+ return "REMREQ_SET_SCISSOR_STATE";
+
+ case REMREQ_SET_VIEWPORT_STATE:
+
+ return "REMREQ_SET_VIEWPORT_STATE";
+
+ case REMREQ_SET_CONSTANT_BUFFER:
+
+ return "REMREQ_SET_CONSTANT_BUFFER";
+
+ case REMREQ_SET_FRAMEBUFFER_STATE:
+
+ return "REMREQ_SET_FRAMEBUFFER_STATE";
+
+ case REMREQ_SET_SAMPLER_TEXTURES:
+
+ return "REMREQ_SET_SAMPLER_TEXTURES";
+
+ case REMREQ_SET_VERTEX_BUFFERS:
+
+ return "REMREQ_SET_VERTEX_BUFFERS";
+
+ case REMREQ_SET_VERTEX_ELEMENTS:
+
+ return "REMREQ_SET_VERTEX_ELEMENTS";
+
+ case REMREQ_SURFACE_COPY:
+
+ return "REMREQ_SURFACE_COPY";
+
+ case REMREQ_SURFACE_FILL:
+
+ return "REMREQ_SURFACE_FILL";
+
+ case REMREQ_CLEAR:
+
+ return "REMREQ_CLEAR";
+
+ case REMREQ_FLUSH:
+
+ return "REMREQ_FLUSH";
+
+ case REMREQ_DESTROY_CONTEXT:
+
+ return "REMREQ_DESTROY_CONTEXT";
+
+ case REMREQ_CREATE_CONTEXT:
+
+ return "REMREQ_CREATE_CONTEXT";
+
+ case REMREP_CREATE_CONTEXT:
+
+ return "REMREP_CREATE_CONTEXT";
+
+ case REMREQ_GET_PARAM:
+
+ return "REMREQ_GET_PARAM";
+
+ case REMREP_GET_PARAM:
+
+ return "REMREP_GET_PARAM";
+
+ case REMREQ_GET_PARAMF:
+
+ return "REMREQ_GET_PARAMF";
+
+ case REMREP_GET_PARAMF:
+
+ return "REMREP_GET_PARAMF";
+
+ case REMREQ_IS_FORMAT_SUPPORTED:
+
+ return "REMREQ_IS_FORMAT_SUPPORTED";
+
+ case REMREP_IS_FORMAT_SUPPORTED:
+
+ return "REMREP_IS_FORMAT_SUPPORTED";
+
+ case REMREQ_TEXTURE_CREATE:
+
+ return "REMREQ_TEXTURE_CREATE";
+
+ case REMREP_TEXTURE_CREATE:
+
+ return "REMREP_TEXTURE_CREATE";
+
+ case REMREQ_TEXTURE_BLANKET:
+
+ return "REMREQ_TEXTURE_BLANKET";
+
+ case REMREP_TEXTURE_BLANKET:
+
+ return "REMREP_TEXTURE_BLANKET";
+
+ case REMREQ_TEXTURE_RELEASE:
+
+ return "REMREQ_TEXTURE_RELEASE";
+
+ case REMREQ_GET_TEX_SURFACE:
+
+ return "REMREQ_GET_TEX_SURFACE";
+
+ case REMREP_GET_TEX_SURFACE:
+
+ return "REMREP_GET_TEX_SURFACE";
+
+ case REMREQ_TEX_SURFACE_RELEASE:
+
+ return "REMREQ_TEX_SURFACE_RELEASE";
+
+ /* case REMREQ_SURFACE_MAP:
+
+ return "REMREQ_SURFACE_MAP";
+
+ case REMREP_SURFACE_MAP:
+
+ return "REMREP_SURFACE_MAP";
+
+ case REMREQ_SURFACE_UNMAP:
+
+ return "REMREQ_SURFACE_UNMAP";*/
+
+ case REMREQ_CREATE_SCREEN:
+
+ return "REMREQ_CREATE_SCREEN";
+
+ case REMREP_CREATE_SCREEN:
+
+ return "REMREP_CREATE_SCREEN";
+
+ case REMREQ_FLUSH_FRONTBUFFER:
+
+ return "REMREQ_FLUSH_FRONTBUFFER";
+
+ case REMREQ_BUFFER_CREATE:
+
+ return "REMREQ_BUFFER_CREATE";
+
+ case REMREQ_USER_BUFFER_CREATE:
+
+ return "REMREQ_USER_BUFFER_CREATE";
+
+ case REMREQ_USER_BUFFER_UPDATE:
+
+ return "REMREQ_USER_BUFFER_UPDATE";
+
+ /* case REMREQ_BUFFER_MAP:
+
+ return "REMREQ_BUFFER_MAP";
+
+ case REMREP_BUFFER_MAP:
+
+ return "REMREP_BUFFER_MAP";
+
+ case REMREQ_BUFFER_UNMAP:
+
+ return "REMREQ_BUFFER_UNMAP";*/
+
+ case REMREQ_BUFFER_GET_DATA:
+ return "REMREQ_BUFFER_GET_DATA";
+
+ case REMREP_BUFFER_GET_DATA:
+ return "REMREP_BUFFER_GET_DATA";
+
+ case REMREQ_BUFFER_SET_DATA:
+ return "REMREQ_BUFFER_SET_DATA";
+
+ case REMREP_BUFFER_SET_DATA:
+ return "REMREP_BUFFER_SET_DATA";
+
+ case REMREQ_BUFFER_DESTROY:
+
+ return "REMREQ_BUFFER_DESTROY";
+
+ case REMREQ_SWAP_BUFFERS:
+
+ return "REMREQ_SWAP_BUFFERS";
+
+
+
+ default:
+ return "*** UNRECOGNISED OPCODE ***";
+ }
+}
+
diff --git a/src/gallium/drivers/remote/remote_comms.c b/src/gallium/drivers/remote/remote_comms.c
new file mode 100644
index 0000000000..aaa100d703
--- /dev/null
+++ b/src/gallium/drivers/remote/remote_comms.c
@@ -0,0 +1,646 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "pipe/p_compiler.h"
+
+#include "winsys_bindings.h"
+#include "tr_screen.h"
+#include "remote_messages.h"
+#include "remote_comms.h"
+#include "remote_debug.h"
+
+int last_alloc_is_in_place = 0;
+// XXX this relies on no two calls to allocate_message_memory without an
+// enqueue_message in between. If this changes, need to start properly tracking
+// whether each alloc is in-place or not.
+
+int last_read_is_in_place = 0;
+
+extern int analyse_waits;
+
+void check_for_asynchronous_failures(void);
+void wait_for_synchronous_message(void);
+
+int drain_events(int fd) {
+
+ int flags = fcntl(fd, F_GETFL);
+
+ int nbflags = flags | O_NONBLOCK;
+
+ fcntl(fd, F_SETFL, nbflags);
+
+ char waste[1024];
+
+ int ret;
+ while((ret = recv(fd, waste, 1024, 0)) > 0) {
+
+ }
+
+ fcntl(fd, F_SETFL, flags);
+
+ if(ret == -1 && errno == EAGAIN)
+ return 0;
+ else {
+ printf("Failed draining events: return %d, errno %d\n", ret, errno);
+ return -1;
+ }
+
+}
+
+int wait_for_char(int fd, char c) {
+
+ char received = c + 1;
+
+ DBG("Waiting for a %c\n", c);
+
+ while(received != c) {
+ int ret = recv(fd, &received, 1, 0);
+ DBG("Got a char: %c\n", received);
+ if(ret <= 0) {
+ printf("Error waiting for a %c (return %d, errno %d)\n", c, ret, errno);
+ return -1;
+ }
+ }
+
+ DBG("That's what I was looking for; returning success\n");
+
+ return 0;
+
+}
+
+int wait_for_tx_not_full() {
+
+ DBG("Waiting for an event on the transmit ring\n");
+ return wait_for_char(singleton_screen->socketfd, 'T');
+
+}
+
+int wait_for_rx_not_empty() {
+
+ DBG("Waiting for an event on the read-ring\n");
+ return wait_for_char(singleton_screen->socketfd, 'R');
+
+}
+
+void* allocate_message_memory(size_t bytes) {
+
+ uint32_t bufsize = ((uint32_t*)singleton_screen->tx_buffer)[0];
+ uint32_t readoff = ((uint32_t*)singleton_screen->tx_buffer)[1];
+ uint32_t writeoff = ((uint32_t*)singleton_screen->tx_buffer)[2];
+ char* writebuf = (char*)&(((uint32_t*)singleton_screen->tx_buffer)[3]);
+
+ int contiguous_available_space;
+
+ if(readoff > writeoff)
+ contiguous_available_space = (readoff - writeoff) - 1;
+ else {
+ contiguous_available_space = (bufsize - writeoff);
+ if(readoff == 0)
+ contiguous_available_space--;
+ /* We can write up to the end of the buffer, except if the read pointer is at 0;
+ if it is, writing to the end would set write == read, and therefore empty the buffer,
+ discarding a full ring. */
+ }
+
+ struct message_header* new_message = 0;
+
+ if(contiguous_available_space >= bytes) {
+ new_message = (struct message_header*)(writebuf + writeoff);
+ last_alloc_is_in_place = 1;
+ }
+ else {
+ new_message = (struct message_header*)malloc(bytes);
+ if(!new_message) {
+ printf("Malloc failed allocating a message (wanted %d bytes)\n", (int)bytes);
+ exit(1);
+ }
+ last_alloc_is_in_place = 0;
+ }
+
+ new_message->length = bytes;
+
+ return new_message;
+
+}
+
+void debug_print_bytes(char* bytes, int n) {
+
+ for(int i = 0; i < n; i++) {
+ printf("%x ", (unsigned int)(bytes[i]));
+ if(i && (!(i % 16)))
+ printf("\n");
+ }
+
+ printf("\n");
+
+}
+
+int sendsome(uint32_t* readoff, uint32_t* writeoff, uint32_t bufsize, char* writebuf, char* data, int length) {
+
+ uint32_t base = *writeoff;
+ uint32_t limit = *readoff;
+ uint32_t space;
+ int writewrapsbuffer;
+
+ if(limit > base) {
+ space = (limit - base) - 1;
+ }
+ else {
+ space = base - limit;
+ space = (bufsize - space) - 1;
+ // Care! > rather than >= because if it == buffersize, the write does
+ // not wrap, but the pointer does
+ }
+
+ int towrite = space >= length ? length : space;
+
+ DBG("WRITING: Will write %d bytes (current r/w %u/%u)\n", towrite, limit, base);
+ //DBG("Those bytes of the user's buffer:\n");
+ //debug_print_bytes(data, towrite);
+
+ if((base + towrite) > bufsize)
+ writewrapsbuffer = 1;
+ else
+ writewrapsbuffer = 0;
+
+ if(towrite == 0) {
+ // Looks like the buffer is full: let's wait
+ return 0;
+ }
+
+ // Okay, we have (towrite) bytes to write: let's do that.
+ if(!writewrapsbuffer) {
+ DBG("Wrote %d bytes (contiguous)\n", towrite);
+ memcpy(writebuf + base, data, towrite);
+ }
+ else {
+ int bytestoend = bufsize - base;
+ memcpy(writebuf + base, data, bytestoend);
+ DBG("Wrote %d bytes at buffer end\n", bytestoend);
+ memcpy(writebuf, data + bytestoend, towrite - bytestoend);
+ DBG("Wrote %d bytes at buffer start\n", towrite - bytestoend);
+ }
+
+ return towrite;
+
+}
+
+void enqueue_message(void* message) {
+
+ struct message_header* header = (struct message_header*)message;
+ uint32_t bufsize = ((uint32_t*)singleton_screen->tx_buffer)[0];
+ uint32_t* readoff = &(((uint32_t*)singleton_screen->tx_buffer)[1]);
+ uint32_t* writeoff = &(((uint32_t*)singleton_screen->tx_buffer)[2]);
+ char* writebuf = (char*)&(((uint32_t*)singleton_screen->tx_buffer)[3]);
+
+ DBG("Sending %s (length %u)\n", optotext(header->opcode), header->length);
+
+ check_for_asynchronous_failures();
+
+ if(last_alloc_is_in_place) {
+
+ uint32_t newwriteoff = *writeoff + header->length;
+ if(newwriteoff >= bufsize)
+ newwriteoff -= bufsize;
+
+ *writeoff = newwriteoff;
+
+ send(singleton_screen->socketfd, "T", 1, 0);
+ return;
+ }
+
+ int bytesSent = 0;
+
+ while(bytesSent < header->length) {
+
+ if(drain_events(singleton_screen->socketfd) == -1) {
+ printf("Socket error draining events\n");
+ exit(1);
+ }
+
+#ifdef DEBUG_RING_WRITE
+ uint32_t base = *readoff;
+ uint32_t limit = *writeoff;
+
+ int bytes_available_for_readers;
+ if(limit > base)
+ bytes_available_for_readers = limit - base;
+ else
+ bytes_available_for_readers = bufsize - (base - limit);
+
+ int read_would_wrap = 0;
+ if((base + bytes_available_for_readers) > bufsize)
+ read_would_wrap = 1;
+
+ printf("Writing with readoff %u, writeoff %u: dumping unread bytes\n", base, limit);
+
+ if(!read_would_wrap) {
+ debug_print_bytes(writebuf + base, bytes_available_for_readers);
+ }
+ else {
+ int bytes_to_end = bufsize - base;
+ debug_print_bytes(writebuf + base, bytes_to_end);
+ printf("---buffer end---\n");
+ debug_print_bytes(writebuf, bytes_available_for_readers - bytes_to_end);
+ }
+
+#endif // DEBUG_RING_WRITE
+
+ int sent = sendsome(readoff, writeoff, bufsize, writebuf, ((char*)header + bytesSent), header->length - bytesSent);
+
+ if(sent == 0) {
+ if(analyse_waits)
+ printf("Wait: transmit buffer full... ");
+ if(wait_for_tx_not_full() == -1) {
+ printf("Socket error waiting for tx-not-full\n");
+ exit(1);
+ }
+ if(analyse_waits)
+ printf("Woke to find read %u, write %u\n", *readoff, *writeoff);
+ }
+
+ uint32_t newwriteoff = *writeoff + sent;
+ if(newwriteoff >= bufsize)
+ newwriteoff -= bufsize;
+
+ *writeoff = newwriteoff;
+
+ bytesSent += sent;
+
+ // Notify the remote that we have sent something
+ send(singleton_screen->socketfd, "T", 1, 0);
+
+ }
+
+ free(header);
+
+}
+
+uint32_t read_avail(uint32_t* readoff, uint32_t* writeoff, uint32_t buffersize) {
+
+ uint32_t limit = *writeoff;
+ uint32_t base = *readoff;
+
+ DBG("read-avail: found limit = %u, base = %u\n", limit, base);
+
+ if(limit > base)
+ return limit - base;
+ else if(limit == base)
+ return 0;
+ else
+ return buffersize - (base - limit);
+
+}
+
+int read_would_wrap(uint32_t* readoff, uint32_t buffersize, uint32_t bytes) {
+
+ return (((*readoff) + bytes) > buffersize);
+
+}
+
+int recvsome(uint32_t* readoff, uint32_t* writeoff, uint32_t bufsize, char* readbuf, void* outbuf, int length) {
+
+ int available = (int)read_avail(readoff, writeoff, bufsize);
+
+ if(!available)
+ return 0;
+
+ int tocopy = available < length ? available : length;
+
+ if(read_would_wrap(readoff, bufsize, tocopy)) {
+ int bytestoend = (bufsize - *readoff);
+ memcpy(outbuf, readbuf + (*readoff), bytestoend);
+ memcpy(((char*)outbuf) + bytestoend, readbuf, tocopy - bytestoend);
+ }
+ else {
+ memcpy(outbuf, readbuf + (*readoff), tocopy);
+ }
+
+ return tocopy;
+
+}
+
+static void discard_ring_bytes(uint32_t* readoff, uint32_t bufsize, int bytes_to_discard) {
+
+ uint32_t newreadoff = *readoff + bytes_to_discard;
+ if(newreadoff >= bufsize)
+ newreadoff -= bufsize;
+
+ *readoff = newreadoff;
+ send(singleton_screen->socketfd, "R", 1, 0);
+
+}
+
+
+static void partial_recv(uint32_t* readoff, uint32_t* writeoff, uint32_t bufsize, char* readbuf, struct message_header* message, int* current_bytes, int target_bytes) {
+
+ while(*current_bytes < target_bytes) {
+
+ if(drain_events(singleton_screen->socketfd) == -1) {
+ printf("Socket error draining events\n");
+ exit(1);
+ }
+
+ int this_recv = recvsome(readoff, writeoff, bufsize, readbuf,
+ (void*)((char*)message + *current_bytes),
+ target_bytes - *current_bytes);
+
+ if(this_recv == 0) {
+ if(analyse_waits)
+ printf("Wait: receive buffer empty\n");
+ if(wait_for_rx_not_empty() == -1) {
+ printf("Socket error waiting for rx-not-empty\n");
+ exit(1);
+ }
+ }
+
+ discard_ring_bytes(readoff, bufsize, this_recv);
+
+ *current_bytes += this_recv;
+
+ }
+
+}
+
+struct message_header* get_message() {
+
+ uint32_t bufsize = ((uint32_t*)singleton_screen->rx_buffer)[0];
+ uint32_t* readoff = &(((uint32_t*)singleton_screen->rx_buffer)[1]);
+ uint32_t* writeoff = &(((uint32_t*)singleton_screen->rx_buffer)[2]);
+ char* readbuf = (char*)&(((uint32_t*)singleton_screen->rx_buffer)[3]);
+
+ int size;
+
+ DBG("Entering get_message: readoff = %u, writeoff = %u\n", *readoff, *writeoff);
+
+ int avail;
+
+ wait_for_synchronous_message();
+
+ if(!read_would_wrap(readoff, bufsize, sizeof(struct message_header))) {
+
+ DBG("Looking for a message header's worth of data\n");
+
+ while((avail = read_avail(readoff, writeoff, bufsize)) < sizeof(struct message_header)) {
+ DBG("Waiting for more to be written (currently have %d, wanting %d\n)\n", avail, sizeof(struct message_header));
+ wait_for_rx_not_empty();
+ }
+
+ size = ((struct message_header*)(readbuf + *readoff))->length;
+ DBG("Found message has length %d\n", size);
+
+ if(read_would_wrap(readoff, bufsize, size)) {
+ DBG("Read would wrap; not reading in place\n");
+ last_read_is_in_place = 0;
+ }
+ else {
+ DBG("Read would not wrap; reading in place\n");
+ last_read_is_in_place = 1;
+ }
+
+ }
+ else {
+ DBG("Reading only a message_header would wrap; not reading in place\n");
+ last_read_is_in_place = 0;
+ }
+
+ if(last_read_is_in_place) {
+
+ DBG("Reading in place\n");
+
+ // Pass out a pointer to the ring buffer in-place, once it is full enough
+ while((avail = read_avail(readoff, writeoff, bufsize)) < size) {
+ DBG("Waiting for more to be written (got %d, wanting %d)\n", avail, size);
+ wait_for_rx_not_empty();
+ }
+
+ DBG("Got enough; passing out in-place pointer\n");
+ return (struct message_header*)(readbuf + *readoff);
+
+ }
+ else {
+
+ DBG("Not reading in place\n");
+
+ // Malloc a temporary and progressively copy into it
+ struct message_header* new_message = (struct message_header*)malloc(sizeof(struct message_header));
+
+ int bytes_received = 0;
+
+ partial_recv(readoff, writeoff, bufsize, readbuf, new_message, &bytes_received, sizeof(struct message_header));
+
+ if(new_message->length < sizeof(struct message_header)) {
+ printf("Unreasonably short message encountered whilst receiving (length %d)\n", new_message->length);
+ exit(1);
+ }
+
+ new_message = (struct message_header*)realloc(new_message, new_message->length);
+
+ partial_recv(readoff, writeoff, bufsize, readbuf, new_message, &bytes_received, new_message->length);
+
+ DBG("Received %s (length %u)\n", optotext(new_message->opcode), new_message->length);
+
+ return new_message;
+ }
+
+}
+
+void free_message(void* message) {
+
+
+ if(last_read_is_in_place) {
+ // Move the read pointer forwards
+ uint32_t bufsize = ((uint32_t*)singleton_screen->rx_buffer)[0];
+ uint32_t* readoff = &(((uint32_t*)singleton_screen->rx_buffer)[1]);
+
+ int size = ((struct message_header*)message)->length;
+
+ uint32_t newreadoff = *readoff + size;
+ if(newreadoff >= bufsize)
+ newreadoff -= bufsize;
+ *readoff = newreadoff;
+
+ send(singleton_screen->socketfd, "R", 1, 0);
+
+ }
+ else {
+
+ free(message);
+
+ }
+
+}
+
+int message_is_asynchronous(uint32_t opcode) {
+
+ if(opcode == REMREP_TEXTURE_CREATE ||
+ opcode == REMREP_TEXTURE_BLANKET ||
+ opcode == REMREP_GET_TEX_SURFACE ||
+ opcode == REMREP_BUFFER_SET_DATA)
+ return 1;
+ else
+ return 0;
+
+}
+
+void check_async_result(char* message, uint32_t opcode) {
+
+ switch(opcode) {
+ case REMREP_TEXTURE_CREATE: {
+ struct remrep_texture_create* rep = (struct remrep_texture_create*)message;
+ if(rep->success) {
+ DBG("Ack: texture_create\n");
+ }
+ else {
+ printf("!!! TEXTURE_CREATE FAILED. This may cause subsequent failures and incorrect rendering\n");
+ }
+ break;
+ }
+ case REMREP_TEXTURE_BLANKET: {
+ struct remrep_texture_blanket* rep = (struct remrep_texture_blanket*)message;
+ if(rep->success) {
+ DBG("Ack: texture_blanket\n");
+ }
+ else {
+ printf("!!! TEXTURE_BLANKET FAILED. This may cause subsequent failures and incorrect rendering\n");
+ }
+ break;
+ }
+ case REMREP_GET_TEX_SURFACE: {
+ struct remrep_get_tex_surface* rep = (struct remrep_get_tex_surface*)message;
+ if(rep->success) {
+ DBG("Ack: get_tex_surface\n");
+ }
+ else {
+ printf("!!! GET_TEX_SURFACE FAILED. This may cause subsequent failures and incorrect rendering\n");
+ }
+ break;
+ }
+ case REMREP_BUFFER_SET_DATA: {
+ struct remrep_buffer_set_data* rep = (struct remrep_buffer_set_data*)message;
+ if(rep->success) {
+ DBG("Ack: buffer_set_data\n");
+ }
+ else {
+ printf("!!! BUFFER_SET_DATA FAILED. This may cause subsequent failures and incorrect rendering\n");
+ }
+ break;
+ }
+ default:
+ printf("BUG! Check async result handed opcode %s\n", optotext(opcode));
+ }
+
+
+}
+
+void discard_asynchronous_messages(int block) {
+
+ uint32_t bufsize = ((uint32_t*)singleton_screen->rx_buffer)[0];
+ uint32_t* readoff = &(((uint32_t*)singleton_screen->rx_buffer)[1]);
+ uint32_t* writeoff = &(((uint32_t*)singleton_screen->rx_buffer)[2]);
+ char* readbuf = (char*)&(((uint32_t*)singleton_screen->rx_buffer)[3]);
+
+ if(block) {
+ DBG("Discarding async messages (blocking)\n");
+ }
+ else {
+ DBG("Discarding async messages (non-blocking)\n");
+ }
+ // WARNING HERE: This method assumes that no async failure notification
+ // is bigger than the ring. If one were, we would wait fruitlessly until
+ // the entire thing were present before deleting it from the ring.
+
+ /* If block is set, we should wait until a synchronous message arrives.
+ If block is not set, we should return as soon as we're short of data. */
+
+ int need_more_bytes = 0;
+
+ while(1) {
+
+ struct message_header head;
+
+ if(need_more_bytes) {
+ if(block) {
+ DBG("Insufficient data, but invoked blocking: sleeping\n");
+ wait_for_rx_not_empty();
+ need_more_bytes = 0;
+ DBG("Woken\n");
+ }
+ else {
+ DBG("Non-blocking discard_async_messages: exiting\n");
+ return;
+ }
+ }
+
+ if(drain_events(singleton_screen->socketfd) == -1) {
+ printf("Socket error draining events in discard_async\n");
+ return;
+ }
+
+ int bytes_peeked = recvsome(readoff, writeoff, bufsize, readbuf, (char*)&head, sizeof(struct message_header));
+
+ if(bytes_peeked < sizeof(struct message_header)) {
+ DBG(" Less than a header available (%d bytes); exiting\n", bytes_peeked);
+ need_more_bytes = 1;
+ continue;
+ }
+
+ if(!message_is_asynchronous(head.opcode)) {
+ DBG(" Next message (%s) not asynchronous: exiting\n", optotext(head.opcode));
+ return;
+ }
+
+ int bytes_available = read_avail(readoff, writeoff, bufsize);
+
+ if(bytes_available < head.length) {
+ DBG(" Message had length %d but only %d available: exiting\n", head.length, bytes_available);
+ need_more_bytes = 1;
+ continue;
+ }
+
+ char* message_proper = malloc(head.length);
+ if(!message_proper) {
+ printf("OOM checking for asynchronous failures\n");
+ return;
+ }
+
+ int bytes_read = recvsome(readoff, writeoff, bufsize, readbuf, message_proper, head.length);
+
+ if(bytes_read < head.length) {
+ printf("BUG! read_avail returned %d, yet we could only actually read %d bytes\n", bytes_available, bytes_read);
+ free(message_proper);
+ return;
+ }
+
+ DBG(" Got a message: checking its result\n");
+
+ check_async_result(message_proper, head.opcode);
+
+ free(message_proper);
+
+ discard_ring_bytes(readoff, bufsize, head.length);
+
+ }
+
+}
+
+void wait_for_synchronous_message(void) {
+
+ /* This is like check_for_asynchronous_failures, but we must block
+ until a synchronous message comes along */
+
+ discard_asynchronous_messages(1);
+
+}
+
+void check_for_asynchronous_failures(void) {
+
+ discard_asynchronous_messages(0);
+
+}
diff --git a/src/gallium/drivers/remote/remote_comms.h b/src/gallium/drivers/remote/remote_comms.h
new file mode 100644
index 0000000000..658b8d7b28
--- /dev/null
+++ b/src/gallium/drivers/remote/remote_comms.h
@@ -0,0 +1,17 @@
+
+#ifndef REMOTE_COMMS_H
+#define REMOTE_COMMS_H
+
+#define ALLOC_OUT_MESSAGE(req, name) struct remreq_##req* name = (struct remreq_##req*)allocate_message_memory(sizeof(struct remreq_##req));
+
+#define QUEUE_AND_WAIT(msg, req, reply_name) enqueue_message(msg); struct remrep_##req* reply_name = (struct remrep_##req*)get_message();
+
+void* allocate_message_memory(size_t);
+
+void enqueue_message(void*);
+
+struct message_header* get_message();
+
+void free_message(void*);
+
+#endif
diff --git a/src/gallium/drivers/remote/remote_debug.h b/src/gallium/drivers/remote/remote_debug.h
new file mode 100644
index 0000000000..f9a11620c0
--- /dev/null
+++ b/src/gallium/drivers/remote/remote_debug.h
@@ -0,0 +1,15 @@
+
+#ifndef REMOTE_DEBUG_H
+#define REMOTE_DEBUG_H
+
+#ifdef CS_DEBUG
+#include <stdio.h>
+#define DBG(format, args...) printf(format, ## args)
+
+char* optotext(unsigned);
+
+#else
+#define DBG(format, args...)
+#endif
+
+#endif
diff --git a/src/gallium/drivers/remote/remote_messages.h b/src/gallium/drivers/remote/remote_messages.h
new file mode 100644
index 0000000000..8b2b7ee062
--- /dev/null
+++ b/src/gallium/drivers/remote/remote_messages.h
@@ -0,0 +1,861 @@
+
+#ifndef REMOTE_MESSAGES_H
+#define REMOTE_MESSAGES_H
+
+#include "pipe/p_state.h"
+#include "pipe/p_compiler.h"
+
+struct message_header {
+
+ uint32_t opcode;
+ uint32_t length;
+ uint32_t xid;
+
+};
+
+struct remreq_set_edgeflags {
+
+ struct message_header base;
+ uint32_t pipe;
+ unsigned flag;
+ boolean isnull;
+
+};
+
+#define REMREQ_SET_EDGEFLAGS 1
+
+struct remreq_draw_arrays {
+
+ struct message_header base;
+ uint32_t pipe;
+ unsigned mode;
+ unsigned start;
+ unsigned count;
+
+};
+
+#define REMREQ_DRAW_ARRAYS 2
+
+struct remrep_draw_arrays {
+
+ struct message_header base;
+ boolean success;
+
+};
+
+#define REMREP_DRAW_ARRAYS 73
+
+struct remreq_draw_elements {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t buffer;
+ unsigned indexSize;
+ unsigned mode;
+ unsigned start;
+ unsigned count;
+
+};
+
+#define REMREQ_DRAW_ELEMENTS 3
+
+struct remrep_draw_elements {
+
+ struct message_header base;
+ boolean success;
+
+};
+
+#define REMREP_DRAW_ELEMENTS 74
+
+struct remreq_draw_range_elements {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t buffer;
+ unsigned indexSize;
+ unsigned mode;
+ unsigned start;
+ unsigned count;
+ unsigned minIndex;
+ unsigned maxIndex;
+
+};
+
+#define REMREQ_DRAW_RANGE_ELEMENTS 4
+
+struct remrep_draw_range_elements {
+
+ struct message_header base;
+ boolean success;
+
+};
+
+#define REMREP_DRAW_RANGE_ELEMENTS 75
+
+struct remreq_create_query {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t handle;
+ unsigned query_type;
+
+};
+
+#define REMREQ_CREATE_QUERY 5
+
+struct remreq_destroy_query {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t query;
+
+};
+
+#define REMREQ_DESTROY_QUERY 6
+
+struct remreq_begin_query {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t query;
+
+};
+
+#define REMREQ_BEGIN_QUERY 7
+
+struct remreq_end_query {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t query;
+
+};
+
+#define REMREQ_END_QUERY 8
+
+struct remreq_get_query_result {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t query;
+ boolean wait;
+
+};
+
+#define REMREQ_GET_QUERY_RESULT 9
+
+struct remrep_get_query_result {
+
+ struct message_header base;
+ uint64_t result;
+ boolean done;
+
+};
+
+#define REMREP_GET_QUERY_RESULT 10
+
+struct remreq_create_blend_state {
+
+ struct message_header base;
+ uint32_t handle;
+ uint32_t pipe;
+ struct pipe_blend_state state;
+
+};
+
+#define REMREQ_CREATE_BLEND_STATE 11
+
+struct remreq_bind_blend_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t blend_handle;
+
+};
+
+#define REMREQ_BIND_BLEND_STATE 12
+
+struct remreq_delete_blend_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t blend_handle;
+
+};
+
+#define REMREQ_DELETE_BLEND_STATE 13
+
+struct remreq_create_sampler_state {
+
+ struct message_header base;
+ uint32_t handle;
+ uint32_t pipe;
+ struct pipe_sampler_state state;
+
+};
+
+#define REMREQ_CREATE_SAMPLER_STATE 14
+
+struct remreq_bind_sampler_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t nstates;
+
+};
+
+#define REMREQ_BIND_SAMPLER_STATE 15
+
+struct remreq_delete_sampler_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t sampler_handle;
+
+};
+
+#define REMREQ_DELETE_SAMPLER_STATE 16
+
+struct remreq_create_rast_state {
+
+ struct message_header base;
+ uint32_t handle;
+ uint32_t pipe;
+ struct pipe_rasterizer_state state;
+
+};
+
+#define REMREQ_CREATE_RAST_STATE 17
+
+struct remreq_bind_rast_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t rast_handle;
+
+};
+
+#define REMREQ_BIND_RAST_STATE 18
+
+struct remreq_delete_rast_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t rast_handle;
+
+};
+
+#define REMREQ_DELETE_RAST_STATE 19
+
+struct remreq_create_dsa_state {
+
+ struct message_header base;
+ uint32_t handle;
+ uint32_t pipe;
+ struct pipe_depth_stencil_alpha_state state;
+
+};
+
+#define REMREQ_CREATE_DSA_STATE 20
+
+struct remreq_bind_dsa_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t dsa_handle;
+
+};
+
+#define REMREQ_BIND_DSA_STATE 21
+
+struct remreq_delete_dsa_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t dsa_handle;
+
+};
+
+#define REMREQ_DELETE_DSA_STATE 22
+
+struct remreq_create_fs_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t fs_handle;
+
+};
+
+#define REMREQ_CREATE_FS_STATE 23
+
+struct remreq_bind_fs_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t fs_handle;
+
+};
+
+#define REMREQ_BIND_FS_STATE 24
+
+struct remreq_delete_fs_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t fs_handle;
+
+};
+
+#define REMREQ_DELETE_FS_STATE 25
+
+struct remreq_create_vs_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t vs_handle;
+
+};
+
+#define REMREQ_CREATE_VS_STATE 26
+
+struct remreq_bind_vs_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t vs_handle;
+
+};
+
+#define REMREQ_BIND_VS_STATE 27
+
+struct remreq_delete_vs_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t vs_handle;
+
+};
+
+#define REMREQ_DELETE_VS_STATE 28
+
+struct remreq_set_blend_color {
+
+ struct message_header base;
+ uint32_t pipe;
+ struct pipe_blend_color state;
+
+};
+
+#define REMREQ_SET_BLEND_COLOR 29
+
+struct remreq_set_clip_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ struct pipe_clip_state state;
+
+};
+
+#define REMREQ_SET_CLIP_STATE 30
+
+struct remreq_set_polygon_stipple {
+
+ struct message_header base;
+ uint32_t pipe;
+ struct pipe_poly_stipple state;
+
+};
+
+#define REMREQ_SET_POLYGON_STIPPLE 31
+
+struct remreq_set_scissor_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ struct pipe_scissor_state state;
+
+};
+
+#define REMREQ_SET_SCISSOR_STATE 32
+
+struct remreq_set_viewport_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ struct pipe_viewport_state state;
+
+};
+
+#define REMREQ_SET_VIEWPORT_STATE 33
+
+struct remreq_set_constant_buffer {
+
+ struct message_header base;
+ uint32_t pipe;
+ unsigned int shader, index;
+ unsigned buffer_size;
+ uint32_t buffer;
+
+};
+
+#define REMREQ_SET_CONSTANT_BUFFER 34
+
+struct remreq_set_framebuffer_state {
+
+ struct message_header base;
+ uint32_t pipe;
+ unsigned fbwidth, fbheight;
+ unsigned fbnum_cbufs;
+ uint32_t fbzsbuf;
+ uint32_t fbcbufs[PIPE_MAX_COLOR_BUFS];
+
+};
+
+#define REMREQ_SET_FRAMEBUFFER_STATE 35
+
+struct remreq_set_sampler_textures {
+
+ struct message_header base;
+ uint32_t pipe;
+ unsigned num_textures;
+
+};
+
+#define REMREQ_SET_SAMPLER_TEXTURES 36
+
+struct opaque_pipe_vertex_element {
+
+ unsigned pitch, max_index, buffer_offset;
+ uint32_t buffer;
+
+};
+
+struct remreq_set_vertex_buffers {
+
+ struct message_header base;
+ uint32_t pipe;
+ unsigned num_buffers;
+
+};
+
+#define REMREQ_SET_VERTEX_BUFFERS 37
+
+struct remreq_set_vertex_elements {
+
+ struct message_header base;
+ uint32_t pipe;
+ unsigned num_elements;
+
+};
+
+#define REMREQ_SET_VERTEX_ELEMENTS 38
+
+struct remreq_surface_copy {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t src, dest;
+ unsigned sx, sy, dx, dy;
+ unsigned w, h;
+ boolean do_flip;
+
+};
+
+#define REMREQ_SURFACE_COPY 39
+
+struct remreq_surface_fill {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t surface;
+ unsigned x, y;
+ unsigned w, h;
+ unsigned value;
+
+};
+
+#define REMREQ_SURFACE_FILL 40
+
+struct remreq_clear {
+
+ struct message_header base;
+ uint32_t pipe;
+ uint32_t surface;
+ unsigned clearValue;
+
+};
+
+#define REMREQ_CLEAR 41
+
+struct remreq_flush {
+
+ struct message_header base;
+ uint32_t pipe;
+ unsigned flags;
+
+};
+
+#define REMREQ_FLUSH 42
+
+struct remreq_destroy_context {
+
+ struct message_header base;
+ uint32_t pipe;
+
+};
+
+#define REMREQ_DESTROY_CONTEXT 44
+
+struct remreq_create_context {
+
+ struct message_header base;
+ uint32_t screen;
+
+};
+
+#define REMREQ_CREATE_CONTEXT 45
+
+struct remrep_create_context {
+
+ struct message_header base;
+ uint32_t handle;
+
+};
+
+#define REMREP_CREATE_CONTEXT 46
+
+// Screen-wide messages
+
+struct remreq_get_param {
+
+ struct message_header base;
+ uint32_t screen;
+ int param;
+
+};
+
+#define REMREQ_GET_PARAM 47
+
+struct remrep_get_param {
+
+ struct message_header base;
+ int response;
+
+};
+
+#define REMREP_GET_PARAM 48
+
+struct remreq_get_paramf {
+
+ struct message_header base;
+ uint32_t screen;
+ float param;
+
+};
+
+#define REMREQ_GET_PARAMF 49
+
+struct remrep_get_paramf {
+
+ struct message_header base;
+ float response;
+
+};
+
+#define REMREP_GET_PARAMF 50
+
+struct remreq_is_format_supported {
+
+ struct message_header base;
+ uint32_t screen;
+ enum pipe_format format;
+ enum pipe_texture_target target;
+ unsigned tex_usage, geom_flags;
+
+};
+
+#define REMREQ_IS_FORMAT_SUPPORTED 51
+
+struct remrep_is_format_supported {
+
+ struct message_header base;
+ boolean response;
+
+};
+
+#define REMREP_IS_FORMAT_SUPPORTED 52
+
+struct remreq_texture_create {
+
+ struct message_header base;
+ uint32_t screen;
+ struct pipe_texture templat;
+ uint32_t handle;
+
+};
+
+#define REMREQ_TEXTURE_CREATE 53
+
+struct remrep_texture_create {
+
+ struct message_header base;
+ boolean success;
+
+};
+
+#define REMREP_TEXTURE_CREATE 54
+
+struct remreq_texture_blanket {
+
+ struct message_header base;
+ uint32_t screen;
+ struct pipe_texture templat;
+ uint32_t handle;
+ unsigned pitch;
+ uint32_t buffer;
+
+};
+
+#define REMREQ_TEXTURE_BLANKET 55
+
+struct remrep_texture_blanket {
+
+ struct message_header base;
+ boolean success;
+
+};
+
+#define REMREP_TEXTURE_BLANKET 56
+
+struct remreq_texture_release {
+
+ struct message_header base;
+ uint32_t screen;
+ uint32_t texture;
+
+};
+
+#define REMREQ_TEXTURE_RELEASE 57
+
+struct remreq_get_tex_surface {
+
+ struct message_header base;
+ uint32_t screen;
+ uint32_t texture;
+ unsigned face, level, zslice, usage;
+ uint32_t handle;
+ uint32_t buffer_handle;
+
+};
+
+#define REMREQ_GET_TEX_SURFACE 58
+
+struct remrep_get_tex_surface {
+
+ struct message_header base;
+ boolean success;
+
+};
+
+#define REMREP_GET_TEX_SURFACE 59
+
+struct remreq_tex_surface_release {
+
+ struct message_header base;
+ uint32_t screen;
+ uint32_t surface;
+
+};
+
+#define REMREQ_TEX_SURFACE_RELEASE 60
+
+/*
+struct remreq_surface_map {
+
+ struct message_header base;
+ uint32_t screen;
+ uint32_t surface;
+ boolean map_ro;
+
+};
+
+#define REMREQ_SURFACE_MAP 61
+
+struct remrep_surface_map {
+
+ struct message_header base;
+ boolean success;
+ unsigned nbytes;
+
+};
+
+#define REMREP_SURFACE_MAP 62
+
+struct remreq_surface_unmap {
+
+ struct message_header base;
+ uint32_t screen;
+ uint32_t surface;
+ boolean has_data;
+
+};
+
+#define REMREQ_SURFACE_UNMAP 63
+*/
+
+struct remreq_buffer_get_data {
+
+ struct message_header base;
+ uint32_t winsys;
+ uint32_t buffer;
+
+};
+
+#define REMREQ_BUFFER_GET_DATA 61
+
+struct remrep_buffer_get_data {
+
+ struct message_header base;
+ boolean success;
+
+};
+
+#define REMREP_BUFFER_GET_DATA 78
+
+struct remreq_buffer_set_data {
+
+ struct message_header base;
+ uint32_t winsys;
+ uint32_t buffer;
+
+};
+
+#define REMREQ_BUFFER_SET_DATA 62
+
+struct remrep_buffer_set_data {
+
+ struct message_header base;
+ boolean success;
+
+};
+
+#define REMREP_BUFFER_SET_DATA 79
+
+struct remreq_create_screen {
+
+ struct message_header base;
+
+};
+
+#define REMREQ_CREATE_SCREEN 64
+
+struct remrep_create_screen {
+
+ struct message_header base;
+ uint32_t handle;
+
+};
+
+#define REMREP_CREATE_SCREEN 65
+
+// winsys messages
+
+struct remreq_flush_frontbuffer {
+
+ struct message_header base;
+ uint32_t screen;
+ uint32_t surface;
+
+};
+
+#define REMREQ_FLUSH_FRONTBUFFER 66
+
+struct remreq_buffer_create {
+
+ struct message_header base;
+ uint32_t screen;
+ unsigned alignment, size, usage;
+ uint32_t handle;
+
+};
+
+#define REMREQ_BUFFER_CREATE 67
+
+struct remreq_user_buffer_create {
+
+ struct message_header base;
+ uint32_t screen;
+ unsigned size;
+ uint32_t handle;
+
+};
+
+#define REMREQ_USER_BUFFER_CREATE 68
+
+struct remreq_user_buffer_update {
+
+ struct message_header base;
+ uint32_t screen;
+ uint32_t buffer;
+
+};
+
+#define REMREQ_USER_BUFFER_UPDATE 69
+
+/*
+struct remreq_buffer_map {
+
+ struct message_header base;
+ uint32_t screen;
+ uint32_t buffer;
+ unsigned usage;
+ boolean need_copy;
+
+};
+
+#define REMREQ_BUFFER_MAP 70
+
+struct remrep_buffer_map {
+
+ struct message_header base;
+ boolean success;
+ boolean has_data;
+
+};
+
+#define REMREP_BUFFER_MAP 77
+
+struct remreq_buffer_unmap {
+
+ struct message_header base;
+ uint32_t screen;
+ uint32_t buffer;
+ boolean has_data;
+
+};
+
+#define REMREQ_BUFFER_UNMAP 71
+*/
+
+struct remreq_buffer_destroy {
+
+ struct message_header base;
+ uint32_t screen;
+ uint32_t buffer;
+
+};
+
+#define REMREQ_BUFFER_DESTROY 72
+
+struct remreq_swap_buffers {
+
+ struct message_header base;
+ uint32_t window;
+ uint32_t texture;
+
+};
+
+#define REMREQ_SWAP_BUFFERS 76
+
+#endif
diff --git a/src/gallium/drivers/remote/remote_state.h b/src/gallium/drivers/remote/remote_state.h
new file mode 100644
index 0000000000..13b7cfed01
--- /dev/null
+++ b/src/gallium/drivers/remote/remote_state.h
@@ -0,0 +1,47 @@
+
+#ifndef REMOTE_STATE_H
+#define REMOTE_STATE_H
+
+#include <pipe/p_state.h>
+
+#define TRIVIAL_REMOTE(x) struct x { uint32_t handle; };
+
+TRIVIAL_REMOTE(remote_opaque_sampler_state)
+TRIVIAL_REMOTE(remote_pipe_query)
+TRIVIAL_REMOTE(remote_opaque_blend_state)
+TRIVIAL_REMOTE(remote_opaque_rast_state)
+TRIVIAL_REMOTE(remote_opaque_dsa_state)
+TRIVIAL_REMOTE(opaque_remote_fs)
+TRIVIAL_REMOTE(opaque_remote_vs)
+
+#undef TRIVIAL_REMOTE
+
+struct remote_buffer {
+
+ struct pipe_buffer base;
+ unsigned is_user;
+ unsigned nmaps;
+ void* map;
+ uint32_t handle;
+ boolean local_dirty, remote_dirty;
+
+};
+
+struct remote_surface {
+
+ struct pipe_surface base;
+ uint32_t handle;
+
+};
+
+struct remote_texture {
+
+ struct pipe_texture base;
+ unsigned long stride[PIPE_MAX_TEXTURE_LEVELS];
+ unsigned long level_offset[PIPE_MAX_TEXTURE_LEVELS];
+ struct pipe_buffer* backing_buffer;
+ uint32_t handle;
+
+};
+
+#endif
diff --git a/src/gallium/drivers/remote/remote_util.h b/src/gallium/drivers/remote/remote_util.h
new file mode 100644
index 0000000000..f5c6182b3d
--- /dev/null
+++ b/src/gallium/drivers/remote/remote_util.h
@@ -0,0 +1,30 @@
+
+#include "remote_state.h"
+
+#define PANIC_IF_NULL(ptr) if(!ptr) { printf("Unexpected null pointer; exiting.\n"); exit(1); }
+
+#define SCREEN_HANDLE(screen) (screen ? ((struct remote_screen*)screen)->remote_handle : 0)
+
+#define PIPE_HANDLE(pipe) (pipe ? ((struct remote_context*)pipe)->remote_handle : 0)
+
+#define WINSYS_HANDLE(ws) (ws ? ((struct remote_winsys*)ws)->screen->remote_handle : 0)
+
+#define SAMPLER_HANDLE(samp) (samp ? ((struct remote_opaque_sampler_state*)samp)->handle : 0)
+
+#define QUERY_HANDLE(q) (q ? ((struct remote_pipe_query*)q)->handle : 0)
+
+#define BLEND_HANDLE(b) (b ? ((struct remote_opaque_blend_state*)b)->handle : 0)
+
+#define RAST_HANDLE(r) (r ? ((struct remote_opaque_rast_state*)r)->handle : 0)
+
+#define DSA_HANDLE(dsa) (dsa ? ((struct remote_opaque_dsa_state*)dsa)->handle : 0)
+
+#define FS_HANDLE(fs) (fs ? ((struct opaque_remote_fs*)fs)->handle : 0)
+
+#define VS_HANDLE(vs) (vs ? ((struct opaque_remote_vs*)vs)->handle : 0)
+
+#define TEXTURE_HANDLE(t) (t ? ((struct remote_texture*)t)->handle : 0)
+
+#define SURFACE_HANDLE(s) (s ? ((struct remote_surface*)s)->handle : 0)
+
+#define BUFFER_HANDLE(buf) (buf ? ((struct remote_buffer*)buf)->handle : 0)
diff --git a/src/gallium/drivers/remote/tr_context.c b/src/gallium/drivers/remote/tr_context.c
new file mode 100644
index 0000000000..70ec9cc2ee
--- /dev/null
+++ b/src/gallium/drivers/remote/tr_context.c
@@ -0,0 +1,1195 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "util/u_memory.h"
+#include "pipe/p_screen.h"
+#include "tgsi/tgsi_parse.h"
+#include "pipe/p_shader_tokens.h"
+#include "pipe/p_inlines.h"
+
+#include "tr_screen.h"
+#include "tr_context.h"
+#include "remote_comms.h"
+#include "remote_state.h"
+#include "remote_util.h"
+#include "remote_messages.h"
+#include "remote_debug.h"
+
+static INLINE void
+remote_context_set_edgeflags(struct pipe_context *_pipe,
+ const unsigned *bitfield)
+{
+
+ if(bitfield) {
+ DBG("Set edge flags: %u\n", *bitfield);
+ }
+ else {
+ DBG("Set edge flags: null\n");
+ }
+
+ ALLOC_OUT_MESSAGE(set_edgeflags, message);
+
+ message->base.opcode = REMREQ_SET_EDGEFLAGS;
+ message->pipe = PIPE_HANDLE(_pipe);
+ if(bitfield) {
+ message->isnull = 0;
+ message->flag = *bitfield;
+ }
+ else {
+ message->isnull = 1;
+ }
+
+ enqueue_message(message);
+
+}
+
+static INLINE void mark_surface_dirty(struct pipe_surface* surf) {
+
+ struct remote_texture* rtex = (struct remote_texture*)surf->texture;
+
+ if(!rtex) {
+ printf("!!! Surface with no texture encountered\n");
+ }
+ else {
+ struct remote_buffer* rbuf = (struct remote_buffer*)rtex->backing_buffer;
+ rbuf->remote_dirty = 1;
+ }
+
+}
+
+static INLINE void mark_framebuffer_dirty(struct pipe_context* pipe) {
+
+ struct remote_context* rctx = (struct remote_context*)pipe;
+
+ for(int i = 0; i < rctx->current_framebuffer_state.num_cbufs; i++)
+ if(rctx->current_framebuffer_state.cbufs[i])
+ mark_surface_dirty(rctx->current_framebuffer_state.cbufs[i]);
+
+ if(rctx->current_framebuffer_state.zsbuf)
+ mark_surface_dirty(rctx->current_framebuffer_state.zsbuf);
+
+}
+
+static INLINE boolean
+remote_context_draw_arrays(struct pipe_context *_pipe,
+ unsigned mode, unsigned start, unsigned count)
+{
+
+ DBG("Draw arrays: mode %u, start %u, count %u\n", mode, start, count);
+
+ mark_framebuffer_dirty(_pipe);
+
+ ALLOC_OUT_MESSAGE(draw_arrays, message);
+
+ message->base.opcode = REMREQ_DRAW_ARRAYS;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->mode = mode;
+ message->start = start;
+ message->count = count;
+
+ enqueue_message(message);
+
+ return true;
+ /*
+ QUEUE_AND_WAIT(message, draw_arrays, reply);
+ PANIC_IF_NULL(reply);
+
+ boolean success = reply->success;
+
+ free_message(reply);
+
+ return success;
+ */
+
+}
+
+
+static INLINE boolean
+remote_context_draw_elements(struct pipe_context *_pipe,
+ struct pipe_buffer *indexBuffer,
+ unsigned indexSize,
+ unsigned mode, unsigned start, unsigned count)
+
+{
+
+ DBG("Draw elements: using index buffer %u, size %u, mode %u, start %u, count %u\n", BUFFER_HANDLE(indexBuffer), indexSize, mode, start, count);
+
+ mark_framebuffer_dirty(_pipe);
+
+ ALLOC_OUT_MESSAGE(draw_elements, message);
+
+ message->base.opcode = REMREQ_DRAW_ELEMENTS;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->buffer = BUFFER_HANDLE(indexBuffer);
+ message->indexSize = indexSize;
+ message->mode = mode;
+ message->start = start;
+ message->count = count;
+
+ enqueue_message(message);
+
+ return true;
+
+ /*
+ QUEUE_AND_WAIT(message, draw_elements, reply);
+ PANIC_IF_NULL(reply);
+
+ boolean success = reply->success;
+ free_message(reply);
+
+ return success;
+ */
+
+}
+
+
+static INLINE boolean
+remote_context_draw_range_elements(struct pipe_context *_pipe,
+ struct pipe_buffer *indexBuffer,
+ unsigned indexSize,
+ unsigned minIndex,
+ unsigned maxIndex,
+ unsigned mode,
+ unsigned start,
+ unsigned count)
+{
+
+ DBG("Draw range elements: using index buffer %u, size %u, mode %u, start %u, count %u, limits %u/%u\n", BUFFER_HANDLE(indexBuffer), indexSize, mode, start, count, minIndex, maxIndex);
+
+ mark_framebuffer_dirty(_pipe);
+
+ ALLOC_OUT_MESSAGE(draw_range_elements, message);
+
+ message->base.opcode = REMREQ_DRAW_RANGE_ELEMENTS;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->buffer = BUFFER_HANDLE(indexBuffer);
+ message->indexSize = indexSize;
+ message->minIndex = minIndex;
+ message->maxIndex = maxIndex;
+ message->mode = mode;
+ message->start = start;
+ message->count = count;
+
+ enqueue_message(message);
+ return true;
+
+ /*
+ QUEUE_AND_WAIT(message, draw_range_elements, reply);
+
+ PANIC_IF_NULL(reply);
+
+ boolean success = reply->success;
+ free_message(reply);
+
+ return success;
+ */
+
+}
+
+
+static INLINE struct pipe_query *
+remote_context_create_query(struct pipe_context *_pipe,
+ unsigned query_type)
+{
+
+// Despite appearances, pipe_query is actually an opaque struct.
+
+ ALLOC_OUT_MESSAGE(create_query, message);
+
+ message->base.opcode = REMREQ_CREATE_QUERY;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->query_type = query_type;
+
+ uint32_t handle = get_fresh_query_handle(_pipe->screen);
+
+ DBG("New query %u, type %x\n", handle, query_type);
+
+ message->handle = handle;
+
+ enqueue_message(message);
+
+ struct remote_pipe_query* opaque = CALLOC_STRUCT(remote_pipe_query);
+
+ PANIC_IF_NULL(opaque);
+
+ opaque->handle = handle;
+
+ return (struct pipe_query*)opaque;
+
+}
+
+
+static INLINE void
+remote_context_destroy_query(struct pipe_context *_pipe,
+ struct pipe_query *query)
+{
+
+ DBG("Destroy query %u\n", QUERY_HANDLE(query));
+
+ ALLOC_OUT_MESSAGE(destroy_query, message);
+
+ message->base.opcode = REMREQ_DESTROY_QUERY;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->query = QUERY_HANDLE(query);
+
+ enqueue_message(message);
+
+}
+
+
+static INLINE void
+remote_context_begin_query(struct pipe_context *_pipe,
+ struct pipe_query *query)
+{
+
+ DBG("Begin query %u\n", QUERY_HANDLE(query));
+
+ ALLOC_OUT_MESSAGE(begin_query, message);
+
+ message->base.opcode = REMREQ_BEGIN_QUERY;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->query = QUERY_HANDLE(query);
+
+ enqueue_message(message);
+
+}
+
+
+static INLINE void
+remote_context_end_query(struct pipe_context *_pipe,
+ struct pipe_query *query)
+{
+
+ DBG("End query %u\n", QUERY_HANDLE(query));
+
+ ALLOC_OUT_MESSAGE(end_query, message);
+
+ message->base.opcode = REMREQ_END_QUERY;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->query = QUERY_HANDLE(query);
+
+ enqueue_message(message);
+
+}
+
+
+static INLINE boolean
+remote_context_get_query_result(struct pipe_context *_pipe,
+ struct pipe_query *query,
+ boolean wait,
+ uint64 *presult)
+{
+
+ DBG("Get query result for query %u\n", QUERY_HANDLE(query));
+
+ ALLOC_OUT_MESSAGE(get_query_result, message);
+
+ message->base.opcode = REMREQ_GET_QUERY_RESULT;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->query = QUERY_HANDLE(query);
+ message->wait = wait;
+
+ QUEUE_AND_WAIT(message, get_query_result, reply);
+
+ if(reply) {
+ *presult = reply->result;
+ DBG("Query result: %lu\n", reply->result);
+ boolean done = reply->done;
+ free_message(reply);
+ return done;
+ }
+ else {
+ printf("!!! Got a null reply to get_query_result\n");
+ exit(1);
+ }
+
+}
+
+
+static INLINE void *
+remote_context_create_blend_state(struct pipe_context *_pipe,
+ const struct pipe_blend_state *state)
+{
+ ALLOC_OUT_MESSAGE(create_blend_state, message);
+
+ message->base.opcode = REMREQ_CREATE_BLEND_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->state = *state;
+ // Struct copy
+
+ uint32_t handle = get_fresh_blend_handle(_pipe->screen);
+ message->handle = handle;
+
+ DBG("Create blend state %u\n", handle);
+
+ enqueue_message(message);
+
+ struct remote_opaque_blend_state* remote_blend = CALLOC_STRUCT(remote_opaque_blend_state);
+
+ PANIC_IF_NULL(remote_blend);
+ remote_blend->handle = handle;
+ return remote_blend;
+}
+
+
+static INLINE void
+remote_context_bind_blend_state(struct pipe_context *_pipe,
+ void *state)
+{
+
+ DBG("Bind blend state %u\n", BLEND_HANDLE(state));
+
+ ALLOC_OUT_MESSAGE(bind_blend_state, message);
+
+ message->base.opcode = REMREQ_BIND_BLEND_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->blend_handle = BLEND_HANDLE(state);
+
+ enqueue_message(message);
+}
+
+
+static INLINE void
+remote_context_delete_blend_state(struct pipe_context *_pipe,
+ void *state)
+{
+ DBG("Delete blend state %u\n", BLEND_HANDLE(state));
+
+ ALLOC_OUT_MESSAGE(delete_blend_state, message);
+
+ message->base.opcode = REMREQ_DELETE_BLEND_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->blend_handle = BLEND_HANDLE(state);
+
+ enqueue_message(message);
+}
+
+
+static INLINE void *
+remote_context_create_sampler_state(struct pipe_context *_pipe,
+ const struct pipe_sampler_state *state)
+{
+
+ ALLOC_OUT_MESSAGE(create_sampler_state, message);
+
+ message->base.opcode = REMREQ_CREATE_SAMPLER_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->state = *state;
+ // Struct copy
+
+ uint32_t handle = get_fresh_sampler_handle(_pipe->screen);
+ message->handle = handle;
+
+ DBG("Create new sampler state %u\n", handle);
+
+ enqueue_message(message);
+
+ struct remote_opaque_sampler_state* remote_sampler = CALLOC_STRUCT(remote_opaque_sampler_state);
+
+ PANIC_IF_NULL(remote_sampler);
+ remote_sampler->handle = handle;
+ return remote_sampler;
+
+}
+
+
+static INLINE void
+remote_context_bind_sampler_states(struct pipe_context *_pipe,
+ unsigned num_states, void **states)
+{
+
+ DBG("Bind sampler states: %u states\n", num_states);
+
+ struct remreq_bind_sampler_state* header =
+ allocate_message_memory(
+ sizeof(struct remreq_bind_sampler_state)
+ + (num_states * sizeof(uint32_t)));
+
+ header->base.opcode = REMREQ_BIND_SAMPLER_STATE;
+ header->pipe = PIPE_HANDLE(_pipe);
+ header->nstates = num_states;
+
+ uint32_t* state_handles =
+ (uint32_t*)((char*)header + sizeof(struct remreq_bind_sampler_state));
+ unsigned i;
+ for(i = 0; i < num_states; i++) {
+ state_handles[i] = SAMPLER_HANDLE(states[i]);
+ }
+
+ enqueue_message(header);
+}
+
+
+static INLINE void
+remote_context_delete_sampler_state(struct pipe_context *_pipe,
+ void *state)
+{
+
+ DBG("Delete sampler state %u\n", SAMPLER_HANDLE(state));
+
+ ALLOC_OUT_MESSAGE(delete_sampler_state, message);
+
+ message->base.opcode = REMREQ_DELETE_SAMPLER_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->sampler_handle = SAMPLER_HANDLE(state);
+
+ enqueue_message(message);
+}
+
+
+static INLINE void *
+remote_context_create_rasterizer_state(struct pipe_context *_pipe,
+ const struct pipe_rasterizer_state *state)
+{
+
+ ALLOC_OUT_MESSAGE(create_rast_state, message);
+
+ message->base.opcode = REMREQ_CREATE_RAST_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->state = *state;
+ // Struct copy
+
+ uint32_t handle = get_fresh_rast_handle(_pipe->screen);
+ message->handle = handle;
+
+ DBG("Create new rasterizer state: handle %u\n", handle);
+
+ enqueue_message(message);
+
+ struct remote_opaque_rast_state* remote_rast = CALLOC_STRUCT(remote_opaque_rast_state);
+
+ PANIC_IF_NULL(remote_rast);
+ remote_rast->handle = handle;
+ return remote_rast;
+}
+
+
+static INLINE void
+remote_context_bind_rasterizer_state(struct pipe_context *_pipe,
+ void *state)
+{
+
+ ALLOC_OUT_MESSAGE(bind_rast_state, message);
+
+ message->base.opcode = REMREQ_BIND_RAST_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->rast_handle = RAST_HANDLE(state);
+
+ enqueue_message(message);
+}
+
+
+static INLINE void
+remote_context_delete_rasterizer_state(struct pipe_context *_pipe,
+ void *state)
+{
+ DBG("Delete rasterizer state %u\n", RAST_HANDLE(state));
+
+ ALLOC_OUT_MESSAGE(delete_rast_state, message);
+
+ message->base.opcode = REMREQ_DELETE_RAST_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->rast_handle = RAST_HANDLE(state);
+
+ enqueue_message(message);
+}
+
+
+static INLINE void *
+remote_context_create_depth_stencil_alpha_state(struct pipe_context *_pipe,
+ const struct pipe_depth_stencil_alpha_state *state)
+{
+ ALLOC_OUT_MESSAGE(create_dsa_state, message);
+
+ message->base.opcode = REMREQ_CREATE_DSA_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->state = *state;
+ // Struct copy
+
+ uint32_t handle = get_fresh_dsa_handle(_pipe->screen);
+ message->handle = handle;
+
+ DBG("Create depth/stencil/alpha state: handle %u\n", handle);
+
+ enqueue_message(message);
+
+ struct remote_opaque_dsa_state* remote_dsa = CALLOC_STRUCT(remote_opaque_dsa_state);
+
+ PANIC_IF_NULL(remote_dsa);
+ remote_dsa->handle = handle;
+ return remote_dsa;
+}
+
+
+static INLINE void
+remote_context_bind_depth_stencil_alpha_state(struct pipe_context *_pipe,
+ void *state)
+{
+
+ DBG("Bind depth/stencil/alpha state %u\n", DSA_HANDLE(state));
+
+ ALLOC_OUT_MESSAGE(bind_dsa_state, message);
+
+ message->base.opcode = REMREQ_BIND_DSA_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->dsa_handle = DSA_HANDLE(state);
+
+ enqueue_message(message);
+}
+
+
+static INLINE void
+remote_context_delete_depth_stencil_alpha_state(struct pipe_context *_pipe,
+ void *state)
+{
+
+ DBG("Delete depth/stencil/alpha state %u\n", DSA_HANDLE(state));
+
+ ALLOC_OUT_MESSAGE(delete_dsa_state, message);
+
+ message->base.opcode = REMREQ_DELETE_DSA_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->dsa_handle = DSA_HANDLE(state);
+
+ enqueue_message(message);
+}
+
+
+static INLINE void *
+remote_context_create_fs_state(struct pipe_context *_pipe,
+ const struct pipe_shader_state *state)
+{
+ int tokens = tgsi_num_tokens(state->tokens);
+
+ struct remreq_create_fs_state* header =
+ allocate_message_memory(
+ sizeof(struct remreq_create_fs_state)
+ + (tokens * sizeof(struct tgsi_token)));
+
+ uint32_t handle = get_fresh_fs_handle(_pipe->screen);
+
+ header->base.opcode = REMREQ_CREATE_FS_STATE;
+ header->pipe = PIPE_HANDLE(_pipe);
+ header->fs_handle = handle;
+
+ char* copy_dest = ((char*)header) + sizeof(struct remreq_create_fs_state);
+ memcpy(copy_dest, (char*)(state->tokens), sizeof(struct tgsi_token) * tokens);
+
+ DBG("Create new FS state: handle %u\n", handle);
+
+ enqueue_message(header);
+
+ struct opaque_remote_fs* retval = CALLOC_STRUCT(opaque_remote_fs);
+
+ PANIC_IF_NULL(retval);
+
+ retval->handle = handle;
+
+ return retval;
+}
+
+
+static INLINE void
+remote_context_bind_fs_state(struct pipe_context *_pipe,
+ void *state)
+{
+
+ if(state) {
+ DBG("Bind fragment shader %u\n", FS_HANDLE(state));
+ }
+ else {
+ DBG("Bind fragment shader: no shader\n");
+ }
+
+ ALLOC_OUT_MESSAGE(bind_fs_state, message);
+
+ message->base.opcode = REMREQ_BIND_FS_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->fs_handle = FS_HANDLE(state);
+
+ enqueue_message(message);
+}
+
+
+static INLINE void
+remote_context_delete_fs_state(struct pipe_context *_pipe,
+ void *state)
+{
+
+ DBG("Delete fragment shader %u\n", FS_HANDLE(state));
+
+ ALLOC_OUT_MESSAGE(delete_fs_state, message);
+
+ message->base.opcode = REMREQ_DELETE_FS_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->fs_handle = FS_HANDLE(state);
+
+ enqueue_message(message);
+}
+
+
+static INLINE void *
+remote_context_create_vs_state(struct pipe_context *_pipe,
+ const struct pipe_shader_state *state)
+{
+
+ int tokens = tgsi_num_tokens(state->tokens);
+
+ struct remreq_create_vs_state* header =
+ allocate_message_memory(
+ sizeof(struct remreq_create_vs_state)
+ + (tokens * sizeof(struct tgsi_token)));
+
+ uint32_t handle = get_fresh_vs_handle(_pipe->screen);
+
+ DBG("Create new VS state: handle %u\n", handle);
+
+ header->base.opcode = REMREQ_CREATE_VS_STATE;
+ header->pipe = PIPE_HANDLE(_pipe);
+ header->vs_handle = handle;
+
+ char* copy_dest = ((char*)header) + sizeof(struct remreq_create_vs_state);
+ memcpy(copy_dest, (char*)(state->tokens), sizeof(struct tgsi_token) * tokens);
+
+ enqueue_message(header);
+
+ struct opaque_remote_vs* retval = CALLOC_STRUCT(opaque_remote_vs);
+
+ PANIC_IF_NULL(retval);
+
+ retval->handle = handle;
+
+ return retval;
+
+}
+
+
+static INLINE void
+remote_context_bind_vs_state(struct pipe_context *_pipe,
+ void *state)
+{
+
+ if(state) {
+ DBG("Bind vertex shader state %u\n", VS_HANDLE(state));
+ }
+ else {
+ DBG("Bind vertex shader: no shader\n");
+ }
+
+ ALLOC_OUT_MESSAGE(bind_vs_state, message);
+
+ message->base.opcode = REMREQ_BIND_VS_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->vs_handle = VS_HANDLE(state);
+
+ enqueue_message(message);
+
+}
+
+
+static INLINE void
+remote_context_delete_vs_state(struct pipe_context *_pipe,
+ void *state)
+{
+
+ DBG("Delete vertex shader state %u\n", VS_HANDLE(state));
+
+ ALLOC_OUT_MESSAGE(delete_vs_state, message);
+
+ message->base.opcode = REMREQ_DELETE_VS_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->vs_handle = VS_HANDLE(state);
+
+ enqueue_message(message);
+
+}
+
+
+static INLINE void
+remote_context_set_blend_color(struct pipe_context *_pipe,
+ const struct pipe_blend_color *state)
+{
+
+ DBG("Set blend color\n");
+
+ ALLOC_OUT_MESSAGE(set_blend_color, message);
+
+ message->base.opcode = REMREQ_SET_BLEND_COLOR;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->state = *state;
+ // Struct copy
+
+ enqueue_message(message);
+
+}
+
+
+static INLINE void
+remote_context_set_clip_state(struct pipe_context *_pipe,
+ const struct pipe_clip_state *state)
+{
+
+ DBG("Set clip state\n");
+
+ ALLOC_OUT_MESSAGE(set_clip_state, message);
+
+ message->base.opcode = REMREQ_SET_CLIP_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->state = *state;
+ // Struct copy
+
+ enqueue_message(message);
+
+}
+
+
+static INLINE void
+remote_context_set_constant_buffer(struct pipe_context *_pipe,
+ uint shader, uint index,
+ const struct pipe_constant_buffer *buffer)
+{
+
+ DBG("Set constant buffer for shader %u, index %u\n", shader, index);
+
+ ALLOC_OUT_MESSAGE(set_constant_buffer, message);
+
+ message->base.opcode = REMREQ_SET_CONSTANT_BUFFER;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->shader = shader;
+ message->index = index;
+ message->buffer_size = buffer->size;
+ message->buffer = BUFFER_HANDLE(buffer->buffer);
+ /*
+ char* mapped = (char*)pipe_buffer_map(_pipe->screen, buffer->buffer, PIPE_BUFFER_USAGE_CPU_READ);
+
+ printf("On setting, constant buffer goes like this:\n");
+
+ int i;
+ for(i = 0; i < buffer->size; i++) {
+ printf("%4d ", (int)mapped[i]);
+ if(i % 8 == 7)
+ printf("\n");
+ }
+ printf("\n");
+
+ pipe_buffer_unmap(_pipe->screen, buffer->buffer);
+ */
+ enqueue_message(message);
+
+}
+
+
+static INLINE void
+remote_context_set_framebuffer_state(struct pipe_context *_pipe,
+ const struct pipe_framebuffer_state *state)
+{
+ unsigned i;
+ ALLOC_OUT_MESSAGE(set_framebuffer_state, message);
+
+ message->base.opcode = REMREQ_SET_FRAMEBUFFER_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->fbwidth = state->width;
+ message->fbheight = state->height;
+ message->fbnum_cbufs = state->num_cbufs;
+ message->fbzsbuf = state->zsbuf ? SURFACE_HANDLE(state->zsbuf) : 0;
+ for(i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
+ message->fbcbufs[i] = state->cbufs[i] ? SURFACE_HANDLE(state->cbufs[i]) : 0;
+
+ DBG("Set framebuffer state: %dx%d\n", state->width, state->height);
+ if(message->fbzsbuf) {
+ DBG("Z/stencil buffer: %u\n", message->fbzsbuf);
+ }
+ else {
+ DBG("No Z/stencil buffer\n");
+ }
+
+ for(i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
+ if(message->fbcbufs[i])
+ DBG("Colour buffer %d: texture %u\n", i, message->fbcbufs[i]);
+
+ enqueue_message(message);
+
+ struct remote_context* rctx = (struct remote_context*)_pipe;
+
+ rctx->current_framebuffer_state = *state; // Struct copy
+
+}
+
+
+static INLINE void
+remote_context_set_polygon_stipple(struct pipe_context *_pipe,
+ const struct pipe_poly_stipple *state)
+{
+
+ DBG("Set polygon stipple\n");
+
+ ALLOC_OUT_MESSAGE(set_polygon_stipple, message);
+
+ message->base.opcode = REMREQ_SET_POLYGON_STIPPLE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->state = *state;
+ // Struct copy
+
+ enqueue_message(message);
+}
+
+
+static INLINE void
+remote_context_set_scissor_state(struct pipe_context *_pipe,
+ const struct pipe_scissor_state *state)
+{
+
+ DBG("Set scissor state\n");
+
+ ALLOC_OUT_MESSAGE(set_scissor_state, message);
+
+ message->base.opcode = REMREQ_SET_SCISSOR_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->state = *state;
+ // Struct copy
+
+ enqueue_message(message);
+}
+
+
+static INLINE void
+remote_context_set_viewport_state(struct pipe_context *_pipe,
+ const struct pipe_viewport_state *state)
+{
+
+ DBG("Set viewport state\n");
+
+ ALLOC_OUT_MESSAGE(set_viewport_state, message);
+
+ message->base.opcode = REMREQ_SET_VIEWPORT_STATE;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->state = *state;
+ // Struct copy
+
+ enqueue_message(message);
+}
+
+
+static INLINE void
+remote_context_set_sampler_textures(struct pipe_context *_pipe,
+ unsigned num_textures,
+ struct pipe_texture **textures)
+{
+ // Similar to below
+
+ DBG("Set sampler textures\n");
+
+ struct remreq_set_sampler_textures* header =
+ (struct remreq_set_sampler_textures*)
+ allocate_message_memory(
+ sizeof(struct remreq_set_sampler_textures) +
+ num_textures * sizeof(uint32_t));
+
+ header->base.opcode = REMREQ_SET_SAMPLER_TEXTURES;
+ header->pipe = PIPE_HANDLE(_pipe);
+ header->num_textures = num_textures;
+
+ uint32_t* texhandles = (uint32_t*)
+ ((char*)header + sizeof(struct remreq_set_sampler_textures));
+
+ unsigned i;
+
+ for(i = 0; i < num_textures; i++) {
+ texhandles[i] = textures[i] ? TEXTURE_HANDLE(textures[i]) : 0;
+ DBG("Sampler slot %d: texture %u\n", i, texhandles[i]);
+ }
+
+ enqueue_message(header);
+
+}
+
+
+static INLINE void
+remote_context_set_vertex_buffers(struct pipe_context *_pipe,
+ unsigned num_buffers,
+ const struct pipe_vertex_buffer *buffers)
+{
+ // Each vertex_buffer points to a pipe_buffer, which here is actually
+ // a remote_pipe_buffer. Flatten those references and send an array
+ // which gives the buffer by opaque handle
+
+ DBG("Set vertex buffers: %d buffers\n", num_buffers);
+
+ struct remreq_set_vertex_buffers* header =
+ (struct remreq_set_vertex_buffers*)
+ allocate_message_memory(
+ sizeof(struct remreq_set_vertex_buffers) +
+ (num_buffers * sizeof(struct opaque_pipe_vertex_element)));
+
+ PANIC_IF_NULL(header);
+
+ header->base.opcode = REMREQ_SET_VERTEX_BUFFERS;
+ header->pipe = PIPE_HANDLE(_pipe);
+ header->num_buffers = num_buffers;
+
+ struct opaque_pipe_vertex_element* data =
+ (struct opaque_pipe_vertex_element*)
+ (((char*)header) + sizeof(struct remreq_set_vertex_buffers));
+
+ unsigned i;
+
+ for(i = 0; i < num_buffers; i++) {
+ data[i].pitch = buffers[i].pitch;
+ data[i].max_index = buffers[i].max_index;
+ data[i].buffer_offset = buffers[i].buffer_offset;
+ data[i].buffer = buffers[i].buffer ? BUFFER_HANDLE(buffers[i].buffer) : 0;
+ DBG("Buffer slot %d assigned buffer handle %u\n", i, data[i].buffer);
+ }
+
+ enqueue_message(header);
+
+}
+
+
+static INLINE void
+remote_context_set_vertex_elements(struct pipe_context *_pipe,
+ unsigned num_elements,
+ const struct pipe_vertex_element *elements)
+{
+ // Send array
+
+ DBG("Set vertex elements: %u elements\n", num_elements);
+
+ struct remreq_set_vertex_elements* header =
+ (struct remreq_set_vertex_elements*)
+ allocate_message_memory(
+ sizeof(struct remreq_set_vertex_elements) +
+ num_elements * sizeof(struct pipe_vertex_element));
+
+ header->base.opcode = REMREQ_SET_VERTEX_ELEMENTS;
+ header->pipe = PIPE_HANDLE(_pipe);
+ header->num_elements = num_elements;
+
+ char* dest = ((char*)header) + sizeof(struct remreq_set_vertex_elements);
+ memcpy(dest, (void*)elements, num_elements * sizeof(struct pipe_vertex_element));
+
+ enqueue_message(header);
+
+}
+
+
+static INLINE void
+remote_context_surface_copy(struct pipe_context *_pipe,
+ boolean do_flip,
+ struct pipe_surface *dest,
+ unsigned destx, unsigned desty,
+ struct pipe_surface *src,
+ unsigned srcx, unsigned srcy,
+ unsigned width, unsigned height)
+{
+
+ DBG("Surface copy: %u-%ux%u-%ux%u --> %u-%ux%u\n", SURFACE_HANDLE(src), srcx, srcy, srcx + width, srcy + height, SURFACE_HANDLE(dest), destx, desty);
+
+ ALLOC_OUT_MESSAGE(surface_copy, message);
+
+ message->base.opcode = REMREQ_SURFACE_COPY;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->src = SURFACE_HANDLE(src);
+ message->dest = SURFACE_HANDLE(dest);
+ message->sx = srcx;
+ message->sy = srcy;
+ message->dx = destx;
+ message->dy = desty;
+ message->w = width;
+ message->h = height;
+ message->do_flip = do_flip;
+
+ enqueue_message(message);
+
+}
+
+
+static INLINE void
+remote_context_surface_fill(struct pipe_context *_pipe,
+ struct pipe_surface *dst,
+ unsigned dstx, unsigned dsty,
+ unsigned width, unsigned height,
+ unsigned value)
+{
+
+ DBG("Surface fill: %u-%ux%u-%ux%u with %x\n", PIPE_HANDLE(dst), dstx, dsty, dstx + width, dsty + height, value);
+
+ ALLOC_OUT_MESSAGE(surface_fill, message);
+
+ message->base.opcode = REMREQ_SURFACE_FILL;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->surface = SURFACE_HANDLE(dst);
+ message->x = dstx;
+ message->y = dsty;
+ message->w = width;
+ message->h = height;
+ message->value = value;
+
+ enqueue_message(message);
+
+}
+
+
+static INLINE void
+remote_context_clear(struct pipe_context *_pipe,
+ struct pipe_surface *surface,
+ unsigned clearValue)
+{
+
+ DBG("Clear surface %u with %x\n", SURFACE_HANDLE(surface), clearValue);
+
+ ALLOC_OUT_MESSAGE(clear, message);
+
+ message->base.opcode = REMREQ_CLEAR;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->surface = SURFACE_HANDLE(surface);
+ message->clearValue = clearValue;
+
+ enqueue_message(message);
+
+}
+
+
+static INLINE void
+remote_context_flush(struct pipe_context *_pipe,
+ unsigned flags,
+ struct pipe_fence_handle **fence)
+{
+
+ DBG("Flush\n");
+
+ ALLOC_OUT_MESSAGE(flush, message);
+
+ message->base.opcode = REMREQ_FLUSH;
+ message->pipe = PIPE_HANDLE(_pipe);
+ message->flags = flags;
+
+ /* !!! I *think* fence is out-only */
+
+ enqueue_message(message);
+
+ if(fence) *fence = NULL;
+
+}
+
+
+static INLINE void
+remote_context_destroy(struct pipe_context *_pipe)
+{
+ ALLOC_OUT_MESSAGE(destroy_context, message);
+
+ DBG("Destroying context %u\n", PIPE_HANDLE(_pipe));
+
+ message->base.opcode = REMREQ_DESTROY_CONTEXT;
+ message->pipe = PIPE_HANDLE(_pipe);
+
+ enqueue_message(message);
+
+ FREE((struct remote_context*)_pipe);
+}
+
+
+struct pipe_context *
+remote_context_create(struct pipe_screen *screen)
+{
+ struct remote_context *tr_ctx;
+
+ DBG("Creating new context for screen %u\n", SCREEN_HANDLE(screen));
+
+ tr_ctx = CALLOC_STRUCT(remote_context);
+ if(!tr_ctx)
+ goto error1;
+
+ tr_ctx->base.winsys = screen->winsys;
+ tr_ctx->base.screen = screen;
+ tr_ctx->base.destroy = remote_context_destroy;
+ tr_ctx->base.set_edgeflags = remote_context_set_edgeflags;
+ tr_ctx->base.draw_arrays = remote_context_draw_arrays;
+ tr_ctx->base.draw_elements = remote_context_draw_elements;
+ tr_ctx->base.draw_range_elements = remote_context_draw_range_elements;
+ tr_ctx->base.create_query = remote_context_create_query;
+ tr_ctx->base.destroy_query = remote_context_destroy_query;
+ tr_ctx->base.begin_query = remote_context_begin_query;
+ tr_ctx->base.end_query = remote_context_end_query;
+ tr_ctx->base.get_query_result = remote_context_get_query_result;
+ tr_ctx->base.create_blend_state = remote_context_create_blend_state;
+ tr_ctx->base.bind_blend_state = remote_context_bind_blend_state;
+ tr_ctx->base.delete_blend_state = remote_context_delete_blend_state;
+ tr_ctx->base.create_sampler_state = remote_context_create_sampler_state;
+ tr_ctx->base.bind_sampler_states = remote_context_bind_sampler_states;
+ tr_ctx->base.delete_sampler_state = remote_context_delete_sampler_state;
+ tr_ctx->base.create_rasterizer_state = remote_context_create_rasterizer_state;
+ tr_ctx->base.bind_rasterizer_state = remote_context_bind_rasterizer_state;
+ tr_ctx->base.delete_rasterizer_state = remote_context_delete_rasterizer_state;
+ tr_ctx->base.create_depth_stencil_alpha_state = remote_context_create_depth_stencil_alpha_state;
+ tr_ctx->base.bind_depth_stencil_alpha_state = remote_context_bind_depth_stencil_alpha_state;
+ tr_ctx->base.delete_depth_stencil_alpha_state = remote_context_delete_depth_stencil_alpha_state;
+ tr_ctx->base.create_fs_state = remote_context_create_fs_state;
+ tr_ctx->base.bind_fs_state = remote_context_bind_fs_state;
+ tr_ctx->base.delete_fs_state = remote_context_delete_fs_state;
+ tr_ctx->base.create_vs_state = remote_context_create_vs_state;
+ tr_ctx->base.bind_vs_state = remote_context_bind_vs_state;
+ tr_ctx->base.delete_vs_state = remote_context_delete_vs_state;
+ tr_ctx->base.set_blend_color = remote_context_set_blend_color;
+ tr_ctx->base.set_clip_state = remote_context_set_clip_state;
+ tr_ctx->base.set_constant_buffer = remote_context_set_constant_buffer;
+ tr_ctx->base.set_framebuffer_state = remote_context_set_framebuffer_state;
+ tr_ctx->base.set_polygon_stipple = remote_context_set_polygon_stipple;
+ tr_ctx->base.set_scissor_state = remote_context_set_scissor_state;
+ tr_ctx->base.set_viewport_state = remote_context_set_viewport_state;
+ tr_ctx->base.set_sampler_textures = remote_context_set_sampler_textures;
+ tr_ctx->base.set_vertex_buffers = remote_context_set_vertex_buffers;
+ tr_ctx->base.set_vertex_elements = remote_context_set_vertex_elements;
+ tr_ctx->base.surface_copy = remote_context_surface_copy;
+ tr_ctx->base.surface_fill = remote_context_surface_fill;
+ tr_ctx->base.clear = remote_context_clear;
+ tr_ctx->base.flush = remote_context_flush;
+
+ memset(&tr_ctx->current_framebuffer_state, 0, sizeof(struct pipe_framebuffer_state));
+
+ ALLOC_OUT_MESSAGE(create_context, message);
+
+ struct remote_screen* remscreen = (struct remote_screen*)screen;
+
+ message->base.opcode = REMREQ_CREATE_CONTEXT;
+ message->screen = remscreen->remote_handle;
+
+ QUEUE_AND_WAIT(message, create_context, reply);
+
+ if(reply) {
+ DBG("Got reply: assigned handle %u\n", reply->handle);
+ tr_ctx->remote_handle = reply->handle;
+ free_message(reply);
+ return &tr_ctx->base;
+ }
+ else {
+ return NULL;
+ }
+
+error1:
+ return NULL;
+}
diff --git a/src/gallium/drivers/remote/tr_context.h b/src/gallium/drivers/remote/tr_context.h
new file mode 100644
index 0000000000..9b3acd738b
--- /dev/null
+++ b/src/gallium/drivers/remote/tr_context.h
@@ -0,0 +1,69 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef TR_CONTEXT_H_
+#define TR_CONTEXT_H_
+
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_debug.h"
+#include "pipe/p_context.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct remote_context
+{
+ struct pipe_context base;
+ uint32_t remote_handle;
+
+ struct pipe_framebuffer_state current_framebuffer_state;
+
+};
+
+
+static INLINE struct remote_context *
+remote_context(struct pipe_context *pipe)
+{
+ assert(pipe);
+ return (struct remote_context *)pipe;
+}
+
+
+
+struct pipe_context *
+remote_context_create(struct pipe_screen *screen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TR_CONTEXT_H_ */
diff --git a/src/gallium/drivers/remote/tr_screen.c b/src/gallium/drivers/remote/tr_screen.c
new file mode 100644
index 0000000000..6f453b3435
--- /dev/null
+++ b/src/gallium/drivers/remote/tr_screen.c
@@ -0,0 +1,848 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include <xen/sys/gntmem.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+
+#include "remote_state.h"
+#include "remote_util.h"
+#include "remote_comms.h"
+#include "remote_messages.h"
+#include "remote_debug.h"
+#include "tr_screen.h"
+#include "tr_winsys.h"
+
+/* A few of the objects dealt with here are refcounted. Of course, the remote side is refcounting too. Since functions
+ like pipe_texture_reference and so on in some cases just adjust the refcount variable without making a callback,
+ I can't be sure of always letting the remote side know about references.
+
+ My solution:
+
+ * Each proxy object (e.g. remote_texture) corresponds to exactly one remote reference.
+ * The proxies themselves are refcounted. So, when a proxy dies, the remote object gets a single deref.
+
+ i.e. the objects in this address space are being refcounted, and their existence corresponds to a single
+ reference in the remote address space.
+
+*/
+
+int analyse_waits = 0;
+// A global to indicate whether we desire print statements reporting on how and why we waited for remote action
+
+static const char *
+remote_screen_get_name(struct pipe_screen *_screen)
+{
+
+ return "Xen virtual 3D\n";
+
+}
+
+
+static const char *
+remote_screen_get_vendor(struct pipe_screen *_screen)
+{
+
+ return "Chris Smowton\n";
+
+}
+
+
+static int
+remote_screen_get_param(struct pipe_screen *_screen,
+ int param) {
+
+ struct remote_screen* rscreen = (struct remote_screen*)_screen;
+
+ if(rscreen->int_param_is_cached[param])
+ return rscreen->cached_int_params[param];
+
+ ALLOC_OUT_MESSAGE(get_param, message);
+
+ message->base.opcode = REMREQ_GET_PARAM;
+ message->screen = SCREEN_HANDLE(_screen);
+ message->param = param;
+
+ if(analyse_waits)
+ printf("WAIT: get_param\n");
+ QUEUE_AND_WAIT(message, get_param, reply);
+
+ DBG("Get integer parameter %d: value is %d\n", param, reply->response);
+
+ rscreen->cached_int_params[param] = reply->response;
+ rscreen->int_param_is_cached[param] = 1;
+ int response = reply->response;
+ free_message(reply);
+ return response;
+
+}
+
+
+static float
+remote_screen_get_paramf(struct pipe_screen *_screen,
+ int param)
+{
+
+ struct remote_screen* rscreen = (struct remote_screen*)_screen;
+
+ if(rscreen->float_param_is_cached[param])
+ return rscreen->cached_float_params[param];
+
+ ALLOC_OUT_MESSAGE(get_paramf, message);
+
+ message->base.opcode = REMREQ_GET_PARAMF;
+ message->screen = SCREEN_HANDLE(_screen);
+ message->param = param;
+
+ if(analyse_waits)
+ printf("WAIT: float param\n");
+ QUEUE_AND_WAIT(message, get_paramf, reply);
+
+ DBG("Get FP parameter %d: value is %f\n", param, reply->response);
+
+ rscreen->cached_float_params[param] = reply->response;
+ rscreen->float_param_is_cached[param] = 1;
+
+ float response = reply->response;
+ free_message(reply);
+ return response;
+
+}
+
+
+static boolean
+remote_screen_is_format_supported(struct pipe_screen *_screen,
+ enum pipe_format format,
+ enum pipe_texture_target target,
+ unsigned tex_usage,
+ unsigned geom_flags)
+{
+
+ ALLOC_OUT_MESSAGE(is_format_supported, message);
+
+ message->base.opcode = REMREQ_IS_FORMAT_SUPPORTED;
+ message->screen = SCREEN_HANDLE(_screen);
+ message->format = format;
+ message->target = target;
+ message->tex_usage = tex_usage;
+ message->geom_flags = geom_flags;
+
+ if(analyse_waits)
+ printf("WAIT: format_supported\n");
+ QUEUE_AND_WAIT(message, is_format_supported, reply);
+
+ if(reply->response)
+ DBG("Format query: accepted\n");
+ else
+ DBG("Format query: denied\n");
+
+ boolean response = reply->response;
+ free_message(reply);
+ return response;
+
+}
+
+#define minify(x) (((x >> 1) > 0) ? (x >> 1) : 1)
+
+static struct pipe_texture *
+remote_screen_texture_create(struct pipe_screen *_screen,
+ const struct pipe_texture *templat)
+{
+ struct remote_screen *tr_scr = remote_screen(_screen);
+
+ ALLOC_OUT_MESSAGE(texture_create, message);
+
+ uint32_t handle = get_fresh_texture_handle(_screen);
+
+ DBG("Creating new texture, using handle %u\n", handle);
+
+ message->base.opcode = REMREQ_TEXTURE_CREATE;
+ message->templat = *templat;
+ message->screen = tr_scr->remote_handle;
+ message->handle = handle;
+
+ enqueue_message(message);
+
+ struct remote_texture* result = CALLOC_STRUCT(remote_texture);
+
+ result->base = *templat; // Struct copy
+ result->base.screen = _screen;
+ result->base.refcount = 1;
+ result->handle = handle;
+
+ pf_get_block(result->base.format, &result->base.block);
+
+ // This bit heavily based off softpipe's texture allocation stuff
+
+ DBG("Texture create: %d levels, base dimension %dx%dx%d\n", result->base.last_level, result->base.width[0], result->base.height[0], result->base.depth[0]);
+
+ unsigned int width = result->base.width[0];
+ unsigned int height = result->base.height[0];
+ unsigned int depth = result->base.depth[0];
+
+ unsigned int buffer_size = 0;
+
+ for(unsigned int i = 0; i <= result->base.last_level; i++) {
+
+ result->base.width[i] = width;
+ result->base.height[i] = height;
+ result->base.depth[i] = depth;
+ result->base.nblocksx[i] = pf_get_nblocksx(&result->base.block, width);
+ result->base.nblocksy[i] = pf_get_nblocksy(&result->base.block, height);
+ result->level_offset[i] = buffer_size;
+ result->stride[i] = result->base.nblocksx[i] * result->base.block.size;
+
+ int plane_size = result->base.nblocksx[i] * result->base.nblocksy[i] * result->base.block.size;
+
+ buffer_size += (plane_size * ((result->base.target == PIPE_TEXTURE_CUBE) ? 6 : depth));
+
+ DBG("Level %d consists of %dx%d blocks; block size %d; %d planes\n", i, result->base.nblocksx[i], result->base.nblocksy[i], result->base.block.size, (result->base.target == PIPE_TEXTURE_CUBE ? 6 : depth));
+
+ width = minify(width);
+ height = minify(height);
+ depth = minify(depth);
+
+ }
+
+ DBG("In total will allocate a buffer of size %d\n", buffer_size);
+
+ result->backing_buffer = create_anon_buffer(buffer_size);
+
+ if(!result->backing_buffer) {
+ free(result);
+ return 0;
+ }
+ else {
+ return &(result->base);
+ }
+
+}
+
+
+static struct pipe_texture *
+remote_screen_texture_blanket(struct pipe_screen *_screen,
+ const struct pipe_texture *templat,
+ const unsigned *ppitch,
+ struct pipe_buffer *buffer)
+{
+
+ struct remote_screen *tr_scr = remote_screen(_screen);
+
+ if(templat->target != PIPE_TEXTURE_2D ||
+ templat->last_level != 0 ||
+ templat->depth[0] != 1)
+ return NULL;
+
+ // All current Gallium drivers enforce this... and it seems as though
+ // there is no way to express how you want extra mip-levels or planes
+ // to be laid out in the buffer, so it's probably the only reasonable
+ // thing to do with this interface.
+
+ ALLOC_OUT_MESSAGE(texture_blanket, message);
+
+ uint32_t handle = get_fresh_texture_handle(_screen);
+
+ DBG("Blanket: created texture %u based on buffer %u\n", handle, BUFFER_HANDLE(buffer));
+
+ message->base.opcode = REMREQ_TEXTURE_BLANKET;
+ message->templat = *templat;
+ message->screen = tr_scr->remote_handle;
+ message->pitch = *ppitch;
+ message->buffer = BUFFER_HANDLE(buffer);
+ message->handle = handle;
+
+ enqueue_message(message);
+
+ struct remote_texture* result = CALLOC_STRUCT(remote_texture);
+
+ result->base = *templat; // Struct copy
+ result->base.screen = _screen;
+ result->base.refcount = 1;
+ result->handle = handle;
+
+ pf_get_block(result->base.format, &result->base.block);
+
+ // This bit heavily based off softpipe's texture allocation stuff
+
+ pipe_buffer_reference(_screen, &result->backing_buffer, buffer);
+
+ return &(result->base);
+
+}
+
+
+static void
+remote_screen_texture_release(struct pipe_screen *_screen,
+ struct pipe_texture **ptexture)
+{
+
+ if(*ptexture)
+ DBG("Texture release: had refcount %d\n", (*ptexture)->refcount);
+ else
+ DBG("Texture release called against null pointer\n");
+
+ if((*ptexture) && !(--((*ptexture)->refcount))) {
+
+ DBG("Our local refcount reached zero; remote deref on texture %u\n", TEXTURE_HANDLE(*ptexture));
+
+ ALLOC_OUT_MESSAGE(texture_release, message);
+
+ message->base.opcode = REMREQ_TEXTURE_RELEASE;
+ message->screen = SCREEN_HANDLE(_screen);
+ message->texture = TEXTURE_HANDLE(*ptexture);
+
+ enqueue_message(message);
+
+ struct remote_texture* rtex = (struct remote_texture*)*ptexture;
+ if(rtex->backing_buffer) {
+ pipe_buffer_reference(_screen, &rtex->backing_buffer, NULL);
+ }
+ else {
+ printf("!!! Freeing a texture with no backing buffer\n");
+ }
+
+ FREE(*ptexture);
+
+ }
+
+ *ptexture = NULL;
+
+}
+
+static int get_or_alloc_buffer_handle(struct remote_buffer* rbuf,
+ struct pipe_screen* screen,
+ uint32_t* handle) {
+
+ if(rbuf->handle) {
+ *handle = rbuf->handle;
+ return 0;
+ }
+ else {
+ *handle = get_fresh_buffer_handle(screen);
+ rbuf->handle = *handle;
+ return 1;
+ }
+
+}
+
+static struct pipe_surface *
+remote_screen_get_tex_surface(struct pipe_screen *_screen,
+ struct pipe_texture *texture,
+ unsigned face, unsigned level,
+ unsigned zslice,
+ unsigned usage)
+{
+
+ DBG("Get texture surface for texture %u\n", TEXTURE_HANDLE(texture));
+ DBG("Face %u, level %u, zslice %u, usage %x\n", face, level, zslice, usage);
+
+ struct remote_texture* rtex = (struct remote_texture*)texture;
+
+ uint32_t buffer_handle;
+ int new_name = get_or_alloc_buffer_handle((struct remote_buffer*)rtex->backing_buffer, _screen, &buffer_handle);
+ // Gives the buffer a name, if it hadn't one already
+
+ if(new_name)
+ DBG("Get tex surface: the buffer had no name\n");
+ else
+ DBG("Get tex surface: the buffer had a name already\n");
+
+ uint32_t surf_handle = get_fresh_surface_handle(_screen);
+
+ DBG("Using handle %u for new surface\n", surf_handle);
+ DBG("Using handle %u for its related buffer\n", buffer_handle);
+
+ ALLOC_OUT_MESSAGE(get_tex_surface, message);
+
+ message->base.opcode = REMREQ_GET_TEX_SURFACE;
+ message->screen = SCREEN_HANDLE(_screen);
+ message->texture = TEXTURE_HANDLE(texture);
+ message->face = face;
+ message->level = level;
+ message->zslice = zslice;
+ message->usage = usage;
+ message->handle = surf_handle;
+ message->buffer_handle = new_name ? buffer_handle : 0;
+ // 0 here signifies that we already have a name for that buffer
+ // This is the *only* way for anonymous buffers to get a name
+
+ enqueue_message(message);
+
+ struct remote_surface* result = CALLOC_STRUCT(remote_surface);
+
+ result->base.winsys = _screen->winsys;
+ result->base.texture = texture;
+ result->base.face = face;
+ result->base.level = level;
+ result->base.zslice = zslice;
+ result->base.format = texture->format;
+ result->base.clear_value = 0;
+ result->base.width = texture->width[level];
+ result->base.height = texture->height[level];
+ result->base.block = texture->block;
+ result->base.nblocksx = texture->nblocksx[level];
+ result->base.nblocksy = texture->nblocksy[level];
+ result->base.stride = rtex->stride[level];
+ result->base.offset = rtex->level_offset[level];
+
+ if(texture->target == PIPE_TEXTURE_CUBE || texture->target == PIPE_TEXTURE_3D) {
+ result->base.offset += ((texture->target == PIPE_TEXTURE_CUBE) ? face : zslice) * result->base.nblocksy * result->base.stride;
+ }
+
+ result->base.usage = usage;
+
+ // ...and one is used for communication between the various driver components without a callback :(
+ // In the current mesa-anything arrangment of state-tracker/pipe/winsys, the winsys calls into the Mesa ST
+ // to notify st_notify_swapbuffers_complete, which sets pipe status to UNDEFINED; it then gets set back to DEFINED
+ // by the next call to any drawing function (softpipe,) or upon a clear or get_tex_surface (i915).
+
+ // For now I will always consider my surfaces to be defined, and since my winsys doesn't call notify_swapbuffers_complete,
+ // this won't be interfered with. Its only use seems to be deciding how to clear a surface, so this could easily be
+ // faked out at the remote side.
+
+ // At the remote, then, the winsys might well call notify_complete, but I don't do anything about it, meaning buffers will be
+ // DEFINED the first time the pipe chooses and stay that way. I might need to get the DEFINED/UNDEFINED cycle going on the remote,
+ // set UNDEFINED here so I get Clear() calls and not clear-with-quad, and then finally recreate the "with-quad?" logic in the remote
+ // state tracker depending on DEFINED'ness.
+
+ result->base.status = PIPE_SURFACE_STATUS_DEFINED;
+
+ // Not sure whether we or the remote are expected to fill this in: better safe than sorry.
+ result->base.refcount = 1;
+
+ result->handle = surf_handle;
+
+ pipe_buffer_reference(_screen, &result->base.buffer, rtex->backing_buffer);
+
+ return (&(result->base));
+
+}
+
+
+static void
+remote_screen_tex_surface_release(struct pipe_screen *_screen,
+ struct pipe_surface **psurface)
+{
+
+ if(*psurface)
+ DBG("Texture surface release on %u: old refcount %d\n", SURFACE_HANDLE(*psurface), (*psurface)->refcount);
+ else
+ DBG("Texture surface release passed a null pointer\n");
+
+ if(*psurface && !(--((*psurface)->refcount))) {
+
+ if((*psurface)->buffer) {
+ pipe_buffer_reference(_screen, &((*psurface)->buffer), NULL);
+ }
+ else {
+ printf("!!! tex_surface_release with no buffer\n");
+ }
+
+ ALLOC_OUT_MESSAGE(tex_surface_release, message);
+
+ message->base.opcode = REMREQ_TEX_SURFACE_RELEASE;
+ message->screen = SCREEN_HANDLE(_screen);
+ message->surface = SURFACE_HANDLE(*psurface);
+
+ enqueue_message(message);
+
+ FREE(*psurface);
+
+ }
+
+ *psurface = NULL;
+}
+
+
+static void*
+remote_screen_surface_map(struct pipe_screen *_screen,
+ struct pipe_surface *surface,
+ unsigned flags)
+{
+
+ DBG("Map surface %u (flags: %x)\n", SURFACE_HANDLE(surface), flags);
+ DBG("(-->mapping buffer %u, with offset %u)\n", BUFFER_HANDLE(surface->buffer), surface->offset);
+
+ char* map = (char*)pipe_buffer_map(_screen, surface->buffer, flags);
+
+ return (void*)(map + surface->offset);
+
+}
+
+
+static void
+remote_screen_surface_unmap(struct pipe_screen *_screen,
+ struct pipe_surface *surface)
+{
+
+ DBG("Unmap surface %u\n", SURFACE_HANDLE(surface));
+
+ pipe_buffer_unmap(_screen, surface->buffer);
+
+}
+
+
+static void
+remote_screen_destroy(struct pipe_screen *_screen)
+{
+ struct remote_screen *tr_scr = remote_screen(_screen);
+
+ DBG("Destroying screen %u: closing connection\n", SCREEN_HANDLE(_screen));
+
+ close(tr_scr->socketfd);
+
+ FREE(tr_scr);
+}
+
+struct pipe_screen *
+remote_screen_create(struct pipe_winsys* winsys)
+{
+
+ struct remote_screen* tr_scr = CALLOC_STRUCT(remote_screen);
+
+ memset(tr_scr, 0, sizeof(struct remote_screen));
+
+ DBG("Creating new screen\n");
+
+ if(!tr_scr) {
+ printf("Alloc failed in remote_screen_create!\n");
+ return NULL;
+ }
+
+ tr_scr->base.winsys = winsys;
+ tr_scr->base.destroy = remote_screen_destroy;
+ tr_scr->base.get_name = remote_screen_get_name;
+ tr_scr->base.get_vendor = remote_screen_get_vendor;
+ tr_scr->base.get_param = remote_screen_get_param;
+ tr_scr->base.get_paramf = remote_screen_get_paramf;
+ tr_scr->base.is_format_supported = remote_screen_is_format_supported;
+ tr_scr->base.texture_create = remote_screen_texture_create;
+ tr_scr->base.texture_blanket = remote_screen_texture_blanket;
+ tr_scr->base.texture_release = remote_screen_texture_release;
+ tr_scr->base.get_tex_surface = remote_screen_get_tex_surface;
+ tr_scr->base.tex_surface_release = remote_screen_tex_surface_release;
+ tr_scr->base.surface_map = remote_screen_surface_map;
+ tr_scr->base.surface_unmap = remote_screen_surface_unmap;
+
+ tr_scr->last_query_handle = 1;
+ tr_scr->last_blend_handle = 1;
+ tr_scr->last_dsa_handle = 1;
+ tr_scr->last_rast_handle = 1;
+ tr_scr->last_sampler_handle = 1;
+ tr_scr->last_fs_handle = 1;
+ tr_scr->last_vs_handle = 1;
+ tr_scr->last_texture_handle = 1;
+ tr_scr->last_surface_handle = 1;
+ tr_scr->last_buffer_handle = 1;
+ tr_scr->last_window_handle = 1;
+
+ // Check if the user requests wait analysis
+
+ analyse_waits = 0;
+
+ char* analyse_waits_env = getenv("VG_ANALYSE_WAITS");
+ if(analyse_waits_env) {
+ if(analyse_waits_env[0] == '1') {
+ printf("Enabled wait analysis\n");
+ analyse_waits = 1;
+ }
+ }
+
+ // Set up a Xen-IDC connection to describe graphics events to the host
+
+ struct sockaddr_un sun;
+
+ sun.sun_family = AF_UNIX;
+ strcpy(sun.sun_path, "/var/run/xen3dd-socket");
+
+ tr_scr->socketfd = socket(PF_UNIX, SOCK_STREAM, 0);
+ DBG("Socket fd is %d\n", tr_scr->socketfd);
+
+ if(tr_scr->socketfd == -1) {
+ printf("socket() failed creating a new screen\n");
+ exit(1);
+ }
+
+ if(connect(tr_scr->socketfd,
+ &sun,
+ sizeof(sun.sun_family) + strlen(sun.sun_path)) < 0) {
+ printf("Couldn't connect to /var/run/xen3dd-socket\n");
+ exit(1);
+ }
+
+ DBG("Successfully connected\n");
+
+ // Now create two initally-empty ring buffers, one for RX and one for TX.
+
+ struct {
+ uint32_t* grants;
+ void** map;
+ } togrant[2] = {
+ { .grants = tr_scr->rx_grants, .map = &(tr_scr->rx_buffer) },
+ { .grants = tr_scr->tx_grants, .map = &(tr_scr->tx_buffer) }
+ };
+
+ DBG("tr_scr->rx_grants is %p, tr_scr->tx_grants is %p\n", tr_scr->rx_grants, tr_scr->tx_grants);
+
+ for(int k = 0; k < 4; k++) {
+
+ DBG("RX grant %d is currently %u\n", k, tr_scr->rx_grants[k]);
+ DBG("TX grant %d is currently %u\n", k, tr_scr->tx_grants[k]);
+
+ }
+
+ for(int i = 0; i < 2; i++) {
+ int fd = open("/dev/gntmem", O_RDWR);
+ int ret;
+
+ DBG("Opened /dev/gntmem; got fd %d\n", fd);
+
+ if(fd == -1) {
+ printf("Failed to open /dev/gntmem\n");
+ exit(1);
+ }
+
+ ret = ioctl(fd, IOCTL_GNTMEM_SET_DOMAIN, 0);
+
+ DBG("set-domain 0 returned %d\n", ret);
+
+ if(ret == -1) {
+ printf("Failed to set gntmem's target domain\n");
+ exit(1);
+ }
+
+ ret = ioctl(fd, IOCTL_GNTMEM_SET_SIZE, 4);
+
+ DBG("set-size 4 returned %d\n", ret);
+
+ if(ret == -1) {
+ printf("Failed to create a shareable section of 4 pages\n");
+ exit(1);
+ }
+
+ DBG("Going to write grants starting at address %p\n", togrant[i].grants);
+
+ ret = ioctl(fd, IOCTL_GNTMEM_GET_GRANTS, togrant[i].grants);
+
+ DBG("get-grants returned %d\n", ret);
+ DBG("After get-grants, have address %p\n", togrant[i].grants);
+
+ for(int j = 0; j < 4; j++) {
+
+ DBG("Grant #%d is %u\n", j, (togrant[i].grants)[j]);
+
+ }
+
+ if(ret == -1) {
+ printf("Failed to get grants for shared section\n");
+ exit(1);
+ }
+
+ *(togrant[i].map) = (void*)-1;
+ *(togrant[i].map) = mmap(0, 4096 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ DBG("Mapped as a shared section: got address %p\n", *(togrant[i].map));
+
+ if(*(togrant[i].map) == (void*)-1) {
+ printf("Couldn't mmap our shared section\n");
+ exit(1);
+ }
+
+ close(fd);
+ // Will remain in existence until an munmap
+
+ // Now init the ring-buffer before we announce to the daemon
+ uint32_t* initdata = (uint32_t*)*(togrant[i].map);
+ DBG("Configuring initdata at %p\n", initdata);
+ uint32_t buffersize = (4096 * 4) - (sizeof(uint32_t) * 3);
+ initdata[0] = buffersize;
+ // total buffer size
+ initdata[1] = 0;
+ initdata[2] = 0;
+ // Next byte to read and next-to-write respectively.
+ // Equality signals the buffer is empty, write = read - 1 signals it is full
+ }
+
+ DBG("Successfully created ring buffers\n");
+ DBG("On exit have rx at %p, tx at %p\n", tr_scr->rx_buffer, tr_scr->tx_buffer);
+
+ // Okay, both ring buffers exist. Now send the grants to the daemon.
+ struct {
+ uint32_t rx_grants[4];
+ uint32_t tx_grants[4];
+ char is_x;
+ } tosend;
+
+ for(int i = 0; i < 4; i++) {
+ tosend.rx_grants[i] = tr_scr->rx_grants[i];
+ tosend.tx_grants[i] = tr_scr->tx_grants[i];
+ }
+
+ tosend.is_x = 0;
+
+ int bytessent = 0;
+
+ while(bytessent < sizeof(tosend)) {
+
+ DBG("Going around; bytessent = %d, about to try to to send %lu on fd %d\n", bytessent, sizeof(tosend) - bytessent, tr_scr->socketfd);
+
+ int sent = send(tr_scr->socketfd, ((char*)&tosend) + bytessent, sizeof(tosend) - bytessent, 0);
+
+ DBG("Just sent %d bytes\n", sent);
+
+ if(sent <= 0) {
+ printf("Failed to send init message to xen3dd: return %d with errno %d\n", sent, errno);
+ exit(1);
+ }
+ else {
+ bytessent += sent;
+ }
+
+ }
+
+ DBG("Successfully relayed that to the compositor\n");
+
+ return &(tr_scr->base);
+
+}
+
+int complete_screen_creation(struct remote_screen* screen) {
+
+ ALLOC_OUT_MESSAGE(create_screen, message);
+
+ message->base.opcode = REMREQ_CREATE_SCREEN;
+
+ DBG("WAIT: Screen creation\n");
+ QUEUE_AND_WAIT(message, create_screen, reply);
+
+ uint32_t handle = reply->handle;
+
+ free_message(reply);
+
+ if(!handle)
+ return 0;
+ else {
+ DBG("Got handle %u\n", handle);
+ screen->remote_handle = handle;
+ return 1;
+ }
+
+}
+
+
+struct remote_screen *
+remote_screen(struct pipe_screen *screen)
+{
+ assert(screen);
+ assert(screen->destroy == remote_screen_destroy);
+ return (struct remote_screen *)screen;
+}
+
+// Handle generation functions. Currently these just assign sequential numbers.
+// If a 32-bit space for e.g. buffers becomes a problem will need to expand that.
+
+uint32_t get_fresh_query_handle(struct pipe_screen* screen) {
+
+ struct remote_screen* remscr = (struct remote_screen*)screen;
+ return remscr->last_query_handle++;
+
+}
+
+uint32_t get_fresh_blend_handle(struct pipe_screen* screen) {
+
+ struct remote_screen* remscr = (struct remote_screen*)screen;
+ return remscr->last_blend_handle++;
+
+}
+
+uint32_t get_fresh_sampler_handle(struct pipe_screen* screen) {
+
+ struct remote_screen* remscr = (struct remote_screen*)screen;
+ return remscr->last_sampler_handle++;
+
+}
+
+uint32_t get_fresh_rast_handle(struct pipe_screen* screen) {
+
+ struct remote_screen* remscr = (struct remote_screen*)screen;
+ return remscr->last_rast_handle++;
+
+}
+
+uint32_t get_fresh_dsa_handle(struct pipe_screen* screen) {
+
+ struct remote_screen* remscr = (struct remote_screen*)screen;
+ return remscr->last_dsa_handle++;
+
+}
+
+uint32_t get_fresh_vs_handle(struct pipe_screen* screen) {
+
+ struct remote_screen* remscr = (struct remote_screen*)screen;
+ return remscr->last_vs_handle++;
+
+}
+
+uint32_t get_fresh_fs_handle(struct pipe_screen* screen) {
+
+ struct remote_screen* remscr = (struct remote_screen*)screen;
+ return remscr->last_fs_handle++;
+
+}
+
+uint32_t get_fresh_texture_handle(struct pipe_screen* screen) {
+
+ struct remote_screen* remscr = (struct remote_screen*)screen;
+ return remscr->last_texture_handle++;
+
+}
+
+uint32_t get_fresh_surface_handle(struct pipe_screen* screen) {
+
+ struct remote_screen* remscr = (struct remote_screen*)screen;
+ return remscr->last_surface_handle++;
+
+}
+
+uint32_t get_fresh_buffer_handle(struct pipe_screen* screen) {
+
+ struct remote_screen* remscr = (struct remote_screen*)screen;
+ return remscr->last_buffer_handle++;
+
+}
diff --git a/src/gallium/drivers/remote/tr_screen.h b/src/gallium/drivers/remote/tr_screen.h
new file mode 100644
index 0000000000..704312ad5b
--- /dev/null
+++ b/src/gallium/drivers/remote/tr_screen.h
@@ -0,0 +1,97 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef TR_SCREEN_H_
+#define TR_SCREEN_H_
+
+#include "pipe/p_screen.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PIPE_MAX_PARAMS 26
+
+struct remote_screen
+{
+
+ struct pipe_screen base;
+ uint32_t remote_handle;
+ int socketfd;
+ uint32_t tx_grants[4];
+ uint32_t rx_grants[4];
+
+ void* tx_buffer;
+ void* rx_buffer;
+
+ uint32_t last_query_handle;
+ uint32_t last_dsa_handle;
+ uint32_t last_rast_handle;
+ uint32_t last_blend_handle;
+ uint32_t last_sampler_handle;
+ uint32_t last_vs_handle;
+ uint32_t last_fs_handle;
+ uint32_t last_texture_handle;
+ uint32_t last_surface_handle;
+ uint32_t last_buffer_handle;
+
+ uint32_t last_window_handle;
+
+ int cached_int_params[PIPE_MAX_PARAMS];
+ boolean int_param_is_cached[PIPE_MAX_PARAMS];
+ float cached_float_params[PIPE_MAX_PARAMS];
+ boolean float_param_is_cached[PIPE_MAX_PARAMS];
+
+};
+
+
+struct remote_screen *
+remote_screen(struct pipe_screen *screen);
+
+struct remote_winsys;
+
+struct pipe_screen *
+remote_screen_create(struct pipe_winsys *winsys);
+
+int complete_screen_creation(struct remote_screen*);
+
+uint32_t get_fresh_query_handle(struct pipe_screen*);
+uint32_t get_fresh_blend_handle(struct pipe_screen*);
+uint32_t get_fresh_rast_handle(struct pipe_screen*);
+uint32_t get_fresh_dsa_handle(struct pipe_screen*);
+uint32_t get_fresh_vs_handle(struct pipe_screen*);
+uint32_t get_fresh_fs_handle(struct pipe_screen*);
+uint32_t get_fresh_sampler_handle(struct pipe_screen*);
+uint32_t get_fresh_buffer_handle(struct pipe_screen*);
+uint32_t get_fresh_texture_handle(struct pipe_screen*);
+uint32_t get_fresh_surface_handle(struct pipe_screen*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TR_SCREEN_H_ */
diff --git a/src/gallium/drivers/remote/winsys_bindings.h b/src/gallium/drivers/remote/winsys_bindings.h
new file mode 100644
index 0000000000..55405a429d
--- /dev/null
+++ b/src/gallium/drivers/remote/winsys_bindings.h
@@ -0,0 +1,10 @@
+
+#ifndef WINSYS_BINDINGS_H
+#define WINSYS_BINDINGS_H
+
+struct remote_winsys;
+
+extern struct remote_winsys* singleton_winsys;
+extern struct remote_screen* singleton_screen;
+
+#endif \ No newline at end of file