diff options
author | Alon Levy <alevy@redhat.com> | 2011-05-12 11:17:46 +0300 |
---|---|---|
committer | Alon Levy <alevy@redhat.com> | 2011-08-26 16:22:11 +0300 |
commit | 25036820ffd594bd5da4fe3586c463ab6e2ff8eb (patch) | |
tree | e9932f96834d5e9fb72350e8044673622df82913 /src | |
parent | 9765dede7556f7ccfef1d90bab14a2bfa03384e5 (diff) |
gallium/drivers/remote with s/uint64/uint64_t
Diffstat (limited to 'src')
-rw-r--r-- | src/gallium/drivers/remote/README | 64 | ||||
-rw-r--r-- | src/gallium/drivers/remote/debug.c | 330 | ||||
-rw-r--r-- | src/gallium/drivers/remote/remote_comms.c | 646 | ||||
-rw-r--r-- | src/gallium/drivers/remote/remote_comms.h | 17 | ||||
-rw-r--r-- | src/gallium/drivers/remote/remote_debug.h | 15 | ||||
-rw-r--r-- | src/gallium/drivers/remote/remote_messages.h | 861 | ||||
-rw-r--r-- | src/gallium/drivers/remote/remote_state.h | 47 | ||||
-rw-r--r-- | src/gallium/drivers/remote/remote_util.h | 30 | ||||
-rw-r--r-- | src/gallium/drivers/remote/tr_context.c | 1195 | ||||
-rw-r--r-- | src/gallium/drivers/remote/tr_context.h | 69 | ||||
-rw-r--r-- | src/gallium/drivers/remote/tr_screen.c | 848 | ||||
-rw-r--r-- | src/gallium/drivers/remote/tr_screen.h | 97 | ||||
-rw-r--r-- | src/gallium/drivers/remote/winsys_bindings.h | 10 |
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 |