diff options
author | marha <marha@users.sourceforge.net> | 2011-03-13 21:22:39 +0000 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-03-13 21:22:39 +0000 |
commit | 6a16283d10f9d0ade43528b537c8ac68ad571bc1 (patch) | |
tree | b5e0b46175a22bd690c180e27d8c37886d84b32f | |
parent | e0058f158bae56c5a10cad4f9ace808a27022a9d (diff) | |
parent | b5d1fd89898edb34f73679b542c754d837d44cf8 (diff) | |
download | vcxsrv-6a16283d10f9d0ade43528b537c8ac68ad571bc1.tar.gz vcxsrv-6a16283d10f9d0ade43528b537c8ac68ad571bc1.tar.bz2 vcxsrv-6a16283d10f9d0ade43528b537c8ac68ad571bc1.zip |
svn merge ^/branches/released .
26 files changed, 2260 insertions, 1970 deletions
diff --git a/libxcb/configure.ac b/libxcb/configure.ac index fc9f17ef6..362ba0535 100644 --- a/libxcb/configure.ac +++ b/libxcb/configure.ac @@ -259,6 +259,7 @@ echo " Xfixes..............: ${BUILD_XFIXES}" echo " Xfree86-dri.........: ${BUILD_XFREE86_DRI}"
echo " xinerama............: ${BUILD_XINERAMA}"
echo " xinput..............: ${BUILD_XINPUT}"
+echo " xkb.................: ${BUILD_XKB}"
echo " xprint..............: ${BUILD_XPRINT}"
echo " xtest...............: ${BUILD_XTEST}"
echo " xv..................: ${BUILD_XV}"
diff --git a/libxcb/src/xcb_in.c b/libxcb/src/xcb_in.c index 77278742d..ad3ae1044 100644 --- a/libxcb/src/xcb_in.c +++ b/libxcb/src/xcb_in.c @@ -81,7 +81,7 @@ typedef struct pending_reply { } pending_reply;
typedef struct reader_list {
- unsigned int request;
+ uint64_t request;
pthread_cond_t *data;
struct reader_list *next;
} reader_list;
@@ -214,10 +214,10 @@ static int read_packet(xcb_connection_t *c) c->in.current_reply_tail = &cur->next;
for(reader = c->in.readers;
reader &&
- XCB_SEQUENCE_COMPARE_32(reader->request, <=, c->in.request_read);
+ XCB_SEQUENCE_COMPARE(reader->request, <=, c->in.request_read);
reader = reader->next)
{
- if(XCB_SEQUENCE_COMPARE_32(reader->request, ==, c->in.request_read))
+ if(reader->request == c->in.request_read)
{
pthread_cond_signal(reader->data);
break;
@@ -307,7 +307,7 @@ static int read_block(const int fd, void *buf, const ssize_t len) return len;
}
-static int poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error)
+static int poll_for_reply(xcb_connection_t *c, uint64_t request, void **reply, xcb_generic_error_t **error)
{
struct reply_list *head;
@@ -316,7 +316,7 @@ static int poll_for_reply(xcb_connection_t *c, unsigned int request, void **repl head = 0;
/* We've read requests past the one we want, so if it has replies we have
* them all and they're in the replies map. */
- else if(XCB_SEQUENCE_COMPARE_32(request, <, c->in.request_read))
+ else if(XCB_SEQUENCE_COMPARE(request, <, c->in.request_read))
{
head = _xcb_map_remove(c->in.replies, request);
if(head && head->next)
@@ -324,7 +324,7 @@ static int poll_for_reply(xcb_connection_t *c, unsigned int request, void **repl }
/* We're currently processing the responses to the request we want, and we
* have a reply ready to return. So just return it without blocking. */
- else if(XCB_SEQUENCE_COMPARE_32(request, ==, c->in.request_read) && c->in.current_reply)
+ else if(request == c->in.request_read && c->in.current_reply)
{
head = c->in.current_reply;
c->in.current_reply = head->next;
@@ -333,7 +333,7 @@ static int poll_for_reply(xcb_connection_t *c, unsigned int request, void **repl }
/* We know this request can't have any more replies, and we've already
* established it doesn't have a reply now. Don't bother blocking. */
- else if(XCB_SEQUENCE_COMPARE_32(request, ==, c->in.request_completed))
+ else if(request == c->in.request_completed)
head = 0;
/* We may have more replies on the way for this request: block until we're
* sure. */
@@ -362,25 +362,12 @@ static int poll_for_reply(xcb_connection_t *c, unsigned int request, void **repl return 1;
}
-/* Public interface */
-
-void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e)
+static void *wait_for_reply(xcb_connection_t *c, uint64_t request, xcb_generic_error_t **e)
{
- uint64_t widened_request;
void *ret = 0;
- if(e)
- *e = 0;
- if(c->has_error)
- return 0;
-
- pthread_mutex_lock(&c->iolock);
-
- widened_request = (c->out.request & UINT64_C(0xffffffff00000000)) | request;
- if(widened_request > c->out.request)
- widened_request -= UINT64_C(1) << 32;
/* If this request has not been written yet, write it. */
- if(c->out.return_socket || _xcb_out_flush_to(c, widened_request))
+ if(c->out.return_socket || _xcb_out_flush_to(c, request))
{
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
reader_list reader;
@@ -388,7 +375,7 @@ void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_ for(prev_reader = &c->in.readers;
*prev_reader &&
- XCB_SEQUENCE_COMPARE_32((*prev_reader)->request, <=, request);
+ XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, request);
prev_reader = &(*prev_reader)->next)
{
/* empty */;
@@ -404,7 +391,7 @@ void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_ for(prev_reader = &c->in.readers;
*prev_reader &&
- XCB_SEQUENCE_COMPARE_32((*prev_reader)->request, <=, request);
+ XCB_SEQUENCE_COMPARE((*prev_reader)->request, <=, request);
prev_reader = &(*prev_reader)->next)
{
if(*prev_reader == &reader)
@@ -417,6 +404,29 @@ void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_ }
_xcb_in_wake_up_next_reader(c);
+ return ret;
+}
+
+static uint64_t widen(xcb_connection_t *c, unsigned int request)
+{
+ uint64_t widened_request = (c->out.request & UINT64_C(0xffffffff00000000)) | request;
+ if(widened_request > c->out.request)
+ widened_request -= UINT64_C(1) << 32;
+ return widened_request;
+}
+
+/* Public interface */
+
+void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e)
+{
+ void *ret;
+ if(e)
+ *e = 0;
+ if(c->has_error)
+ return 0;
+
+ pthread_mutex_lock(&c->iolock);
+ ret = wait_for_reply(c, widen(c, request), e);
pthread_mutex_unlock(&c->iolock);
return ret;
}
@@ -442,66 +452,27 @@ static void insert_pending_discard(xcb_connection_t *c, pending_reply **prev_nex c->in.pending_replies_tail = &pend->next;
}
-static void discard_reply(xcb_connection_t *c, unsigned int request)
+static void discard_reply(xcb_connection_t *c, uint64_t request)
{
- pending_reply *pend = 0;
+ void *reply;
pending_reply **prev_pend;
- uint64_t widened_request;
- /* We've read requests past the one we want, so if it has replies we have
- * them all and they're in the replies map. */
- if(XCB_SEQUENCE_COMPARE_32(request, <, c->in.request_read))
- {
- struct reply_list *head;
- head = _xcb_map_remove(c->in.replies, request);
- while (head)
- {
- struct reply_list *next = head->next;
- free(head->reply);
- free(head);
- head = next;
- }
- return;
- }
-
- /* We're currently processing the responses to the request we want, and we
- * have a reply ready to return. Free it, and mark the pend to free any further
- * replies. */
- if(XCB_SEQUENCE_COMPARE_32(request, ==, c->in.request_read) && c->in.current_reply)
- {
- struct reply_list *head;
- head = c->in.current_reply;
- c->in.current_reply = NULL;
- c->in.current_reply_tail = &c->in.current_reply;
- while (head)
- {
- struct reply_list *next = head->next;
- free(head->reply);
- free(head);
- head = next;
- }
-
- pend = c->in.pending_replies;
- if(pend &&
- !(XCB_SEQUENCE_COMPARE(pend->first_request, <=, c->in.request_read) &&
- (pend->workaround == WORKAROUND_EXTERNAL_SOCKET_OWNER ||
- XCB_SEQUENCE_COMPARE(c->in.request_read, <=, pend->last_request))))
- pend = 0;
- if(pend)
- pend->flags |= XCB_REQUEST_DISCARD_REPLY;
- else
- insert_pending_discard(c, &c->in.pending_replies, c->in.request_read);
+ /* Free any replies or errors that we've already read. Stop if
+ * xcb_wait_for_reply would block or we've run out of replies. */
+ while(poll_for_reply(c, request, &reply, 0) && reply)
+ free(reply);
+ /* If we've proven there are no more responses coming, we're done. */
+ if(XCB_SEQUENCE_COMPARE(request, <=, c->in.request_completed))
return;
- }
/* Walk the list of pending requests. Mark the first match for deletion. */
for(prev_pend = &c->in.pending_replies; *prev_pend; prev_pend = &(*prev_pend)->next)
{
- if(XCB_SEQUENCE_COMPARE_32((*prev_pend)->first_request, >, request))
+ if(XCB_SEQUENCE_COMPARE((*prev_pend)->first_request, >, request))
break;
- if(XCB_SEQUENCE_COMPARE_32((*prev_pend)->first_request, ==, request))
+ if((*prev_pend)->first_request == request)
{
/* Pending reply found. Mark for discard: */
(*prev_pend)->flags |= XCB_REQUEST_DISCARD_REPLY;
@@ -510,11 +481,7 @@ static void discard_reply(xcb_connection_t *c, unsigned int request) }
/* Pending reply not found (likely due to _unchecked request). Create one: */
- widened_request = (c->out.request & UINT64_C(0xffffffff00000000)) | request;
- if(widened_request > c->out.request)
- widened_request -= UINT64_C(1) << 32;
-
- insert_pending_discard(c, prev_pend, widened_request);
+ insert_pending_discard(c, prev_pend, request);
}
void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence)
@@ -527,7 +494,7 @@ void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence) return;
pthread_mutex_lock(&c->iolock);
- discard_reply(c, sequence);
+ discard_reply(c, widen(c, sequence));
pthread_mutex_unlock(&c->iolock);
}
@@ -543,7 +510,7 @@ int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, }
assert(reply != 0);
pthread_mutex_lock(&c->iolock);
- ret = poll_for_reply(c, request, reply, error);
+ ret = poll_for_reply(c, widen(c, request), reply, error);
pthread_mutex_unlock(&c->iolock);
return ret;
}
@@ -581,21 +548,22 @@ xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c) xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie)
{
- /* FIXME: this could hold the lock to avoid syncing unnecessarily, but
- * that would require factoring the locking out of xcb_get_input_focus,
- * xcb_get_input_focus_reply, and xcb_wait_for_reply. */
- xcb_generic_error_t *ret;
+ uint64_t request;
+ xcb_generic_error_t *ret = 0;
void *reply;
if(c->has_error)
return 0;
- if(XCB_SEQUENCE_COMPARE_32(cookie.sequence,>=,c->in.request_expected)
- && XCB_SEQUENCE_COMPARE_32(cookie.sequence,>,c->in.request_completed))
+ pthread_mutex_lock(&c->iolock);
+ request = widen(c, cookie.sequence);
+ if(XCB_SEQUENCE_COMPARE(request, >=, c->in.request_expected)
+ && XCB_SEQUENCE_COMPARE(request, >, c->in.request_completed))
{
- free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), &ret));
- assert(!ret);
+ _xcb_out_send_sync(c);
+ _xcb_out_flush_to(c, c->out.request);
}
- reply = xcb_wait_for_reply(c, cookie.sequence, &ret);
+ reply = wait_for_reply(c, request, &ret);
assert(!reply);
+ pthread_mutex_unlock(&c->iolock);
return ret;
}
diff --git a/libxcb/src/xcb_out.c b/libxcb/src/xcb_out.c index 8347c37cd..0e105fffe 100644 --- a/libxcb/src/xcb_out.c +++ b/libxcb/src/xcb_out.c @@ -1,363 +1,373 @@ -/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp. - * - * 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, sublicense, - * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS 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. - * - * Except as contained in this notice, the names of the authors or their - * institutions shall not be used in advertising or otherwise to promote the - * sale, use or other dealings in this Software without prior written - * authorization from the authors. - */ - -/* Stuff that sends stuff to the server. */ - -#include <assert.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <X11/Xtrans/Xtrans.h> - -#include "xcb.h" -#include "xcbext.h" -#include "xcbint.h" -#include "bigreq.h" - -static int write_block(xcb_connection_t *c, struct iovec *vector, int count) -{ - while(count && c->out.queue_len + vector[0].iov_len <= sizeof(c->out.queue)) - { - memcpy(c->out.queue + c->out.queue_len, vector[0].iov_base, vector[0].iov_len); - c->out.queue_len += vector[0].iov_len; - vector[0].iov_base = (char *) vector[0].iov_base + vector[0].iov_len; - vector[0].iov_len = 0; - ++vector, --count; - } - if(!count) - return 1; - - --vector, ++count; - vector[0].iov_base = c->out.queue; - vector[0].iov_len = c->out.queue_len; - c->out.queue_len = 0; - return _xcb_out_send(c, vector, count); -} - -static void get_socket_back(xcb_connection_t *c) -{ - while(c->out.return_socket && c->out.socket_moving) - pthread_cond_wait(&c->out.socket_cond, &c->iolock); - if(!c->out.return_socket) - return; - - c->out.socket_moving = 1; - pthread_mutex_unlock(&c->iolock); - c->out.return_socket(c->out.socket_closure); - pthread_mutex_lock(&c->iolock); - c->out.socket_moving = 0; - - pthread_cond_broadcast(&c->out.socket_cond); - c->out.return_socket = 0; - c->out.socket_closure = 0; - _xcb_in_replies_done(c); -} - -/* Public interface */ - -void xcb_prefetch_maximum_request_length(xcb_connection_t *c) -{ - if(c->has_error) - return; - pthread_mutex_lock(&c->out.reqlenlock); - if(c->out.maximum_request_length_tag == LAZY_NONE) - { - const xcb_query_extension_reply_t *ext; - ext = xcb_get_extension_data(c, &xcb_big_requests_id); - if(ext && ext->present) - { - c->out.maximum_request_length_tag = LAZY_COOKIE; - c->out.maximum_request_length.cookie = xcb_big_requests_enable(c); - } - else - { - c->out.maximum_request_length_tag = LAZY_FORCED; - c->out.maximum_request_length.value = c->setup->maximum_request_length; - } - } - pthread_mutex_unlock(&c->out.reqlenlock); -} - -uint32_t xcb_get_maximum_request_length(xcb_connection_t *c) -{ - if(c->has_error) - return 0; - xcb_prefetch_maximum_request_length(c); - pthread_mutex_lock(&c->out.reqlenlock); - if(c->out.maximum_request_length_tag == LAZY_COOKIE) - { - xcb_big_requests_enable_reply_t *r = xcb_big_requests_enable_reply(c, c->out.maximum_request_length.cookie, 0); - c->out.maximum_request_length_tag = LAZY_FORCED; - if(r) - { - c->out.maximum_request_length.value = r->maximum_request_length; - free(r); - } - else - c->out.maximum_request_length.value = c->setup->maximum_request_length; - } - pthread_mutex_unlock(&c->out.reqlenlock); - return c->out.maximum_request_length.value; -} - -unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *req) -{ - static const union { - struct { - uint8_t major; - uint8_t pad; - uint16_t len; - } fields; - uint32_t packet; - } sync_req = { { /* GetInputFocus */ 43, 0, 1 } }; - uint64_t request; - uint32_t prefix[3] = { 0 }; - int veclen = req->count; - enum workarounds workaround = WORKAROUND_NONE; - - if(c->has_error) - return 0; - - assert(c != 0); - assert(vector != 0); - assert(req->count > 0); - - if(!(flags & XCB_REQUEST_RAW)) - { - static const char pad[3]; - unsigned int i; - uint16_t shortlen = 0; - size_t longlen = 0; - assert(vector[0].iov_len >= 4); - /* set the major opcode, and the minor opcode for extensions */ - if(req->ext) - { - const xcb_query_extension_reply_t *extension = xcb_get_extension_data(c, req->ext); - if(!(extension && extension->present)) - { - _xcb_conn_shutdown(c); - return 0; - } - ((uint8_t *) vector[0].iov_base)[0] = extension->major_opcode; - ((uint8_t *) vector[0].iov_base)[1] = req->opcode; - } - else - ((uint8_t *) vector[0].iov_base)[0] = req->opcode; - - /* put together the length field, possibly using BIGREQUESTS */ - for(i = 0; i < req->count; ++i) - { - longlen += vector[i].iov_len; - if(!vector[i].iov_base) - { - vector[i].iov_base = (char *) pad; - assert(vector[i].iov_len <= sizeof(pad)); - } - } - assert((longlen & 3) == 0); - longlen >>= 2; - - if(longlen <= c->setup->maximum_request_length) - { - /* we don't need BIGREQUESTS. */ - shortlen = longlen; - longlen = 0; - } - else if(longlen > xcb_get_maximum_request_length(c)) - { - _xcb_conn_shutdown(c); - return 0; /* server can't take this; maybe need BIGREQUESTS? */ - } - - /* set the length field. */ - ((uint16_t *) vector[0].iov_base)[1] = shortlen; - if(!shortlen) - prefix[2] = ++longlen; - } - flags &= ~XCB_REQUEST_RAW; - - /* do we need to work around the X server bug described in glx.xml? */ - /* XXX: GetFBConfigs won't use BIG-REQUESTS in any sane - * configuration, but that should be handled here anyway. */ - if(req->ext && !req->isvoid && !strcmp(req->ext->name, "GLX") && - ((req->opcode == 17 && ((uint32_t *) vector[0].iov_base)[1] == 0x10004) || - req->opcode == 21)) - workaround = WORKAROUND_GLX_GET_FB_CONFIGS_BUG; - - /* get a sequence number and arrange for delivery. */ - pthread_mutex_lock(&c->iolock); - /* wait for other writing threads to get out of my way. */ - while(c->out.writing) - pthread_cond_wait(&c->out.cond, &c->iolock); - get_socket_back(c); - - request = ++c->out.request; - /* send GetInputFocus (sync_req) when 64k-2 requests have been sent without - * a reply. - * Also send sync_req (could use NoOp) at 32-bit wrap to avoid having - * applications see sequence 0 as that is used to indicate - * an error in sending the request */ - while((req->isvoid && - c->out.request == c->in.request_expected + (1 << 16) - 1) || - request == 0) - { - prefix[0] = sync_req.packet; - _xcb_in_expect_reply(c, request, WORKAROUND_NONE, XCB_REQUEST_DISCARD_REPLY); - c->in.request_expected = c->out.request; - request = ++c->out.request; - } - - if(workaround != WORKAROUND_NONE || flags != 0) - _xcb_in_expect_reply(c, request, workaround, flags); - if(!req->isvoid) - c->in.request_expected = c->out.request; - - if(prefix[0] || prefix[2]) - { - --vector, ++veclen; - if(prefix[2]) - { - prefix[1] = ((uint32_t *) vector[1].iov_base)[0]; - vector[1].iov_base = (caddr_t)((uint32_t *) vector[1].iov_base + 1); - vector[1].iov_len -= sizeof(uint32_t); - } - vector[0].iov_len = sizeof(uint32_t) * ((prefix[0] ? 1 : 0) + (prefix[2] ? 2 : 0)); - vector[0].iov_base = (caddr_t)(prefix + !prefix[0]); - } - - if(!write_block(c, vector, veclen)) - { - _xcb_conn_shutdown(c); - request = 0; - } - pthread_mutex_unlock(&c->iolock); - return request; -} - -int xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), void *closure, int flags, uint64_t *sent) -{ - int ret; - if(c->has_error) - return 0; - pthread_mutex_lock(&c->iolock); - get_socket_back(c); - ret = _xcb_out_flush_to(c, c->out.request); - if(ret) - { - c->out.return_socket = return_socket; - c->out.socket_closure = closure; - if(flags) - _xcb_in_expect_reply(c, c->out.request, WORKAROUND_EXTERNAL_SOCKET_OWNER, flags); - assert(c->out.request == c->out.request_written); - *sent = c->out.request; - } - pthread_mutex_unlock(&c->iolock); - return ret; -} - -int xcb_writev(xcb_connection_t *c, struct iovec *vector, int count, uint64_t requests) -{ - int ret; - if(c->has_error) - return 0; - pthread_mutex_lock(&c->iolock); - c->out.request += requests; - ret = _xcb_out_send(c, vector, count); - pthread_mutex_unlock(&c->iolock); - return ret; -} - -int xcb_flush(xcb_connection_t *c) -{ - int ret; - if(c->has_error) - return 0; - pthread_mutex_lock(&c->iolock); - ret = _xcb_out_flush_to(c, c->out.request); - pthread_mutex_unlock(&c->iolock); - return ret; -} - -/* Private interface */ - -int _xcb_out_init(_xcb_out *out) -{ - if(pthread_cond_init(&out->socket_cond, 0)) - return 0; - out->return_socket = 0; - out->socket_closure = 0; - out->socket_moving = 0; - - if(pthread_cond_init(&out->cond, 0)) - return 0; - out->writing = 0; - - out->queue_len = 0; - - out->request = 0; - out->request_written = 0; - - if(pthread_mutex_init(&out->reqlenlock, 0)) - return 0; - out->maximum_request_length_tag = LAZY_NONE; - - return 1; -} - -void _xcb_out_destroy(_xcb_out *out) -{ - pthread_cond_destroy(&out->cond); - pthread_mutex_destroy(&out->reqlenlock); -} - -int _xcb_out_send(xcb_connection_t *c, struct iovec *vector, int count) -{ - int ret = 1; - while(ret && count) - ret = _xcb_conn_wait(c, &c->out.cond, &vector, &count); - c->out.request_written = c->out.request; - pthread_cond_broadcast(&c->out.cond); - _xcb_in_wake_up_next_reader(c); - return ret; -} - -int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request) -{ - assert(XCB_SEQUENCE_COMPARE(request, <=, c->out.request)); - if(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request)) - return 1; - if(c->out.queue_len) - { - struct iovec vec; - vec.iov_base = c->out.queue; - vec.iov_len = c->out.queue_len; - c->out.queue_len = 0; - return _xcb_out_send(c, &vec, 1); - } - while(c->out.writing) - pthread_cond_wait(&c->out.cond, &c->iolock); - assert(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request)); - return 1; -} +/* Copyright (C) 2001-2004 Bart Massey and Jamey Sharp.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS 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.
+ *
+ * Except as contained in this notice, the names of the authors or their
+ * institutions shall not be used in advertising or otherwise to promote the
+ * sale, use or other dealings in this Software without prior written
+ * authorization from the authors.
+ */
+
+/* Stuff that sends stuff to the server. */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <X11/Xtrans/Xtrans.h>
+
+#include "xcb.h"
+#include "xcbext.h"
+#include "xcbint.h"
+#include "bigreq.h"
+
+static __inline void send_request(xcb_connection_t *c, int isvoid, enum workarounds workaround, int flags, struct iovec *vector, int count)
+{
+ if(c->has_error)
+ return;
+
+ ++c->out.request;
+ if(!isvoid)
+ c->in.request_expected = c->out.request;
+ if(workaround != WORKAROUND_NONE || flags != 0)
+ _xcb_in_expect_reply(c, c->out.request, workaround, flags);
+
+ while(count && c->out.queue_len + vector[0].iov_len <= sizeof(c->out.queue))
+ {
+ memcpy(c->out.queue + c->out.queue_len, vector[0].iov_base, vector[0].iov_len);
+ c->out.queue_len += vector[0].iov_len;
+ vector[0].iov_base = (char *) vector[0].iov_base + vector[0].iov_len;
+ vector[0].iov_len = 0;
+ ++vector, --count;
+ }
+ if(!count)
+ return;
+
+ --vector, ++count;
+ vector[0].iov_base = c->out.queue;
+ vector[0].iov_len = c->out.queue_len;
+ c->out.queue_len = 0;
+ _xcb_out_send(c, vector, count);
+}
+
+static void send_sync(xcb_connection_t *c)
+{
+ static const union {
+ struct {
+ uint8_t major;
+ uint8_t pad;
+ uint16_t len;
+ } fields;
+ uint32_t packet;
+ } sync_req = { { /* GetInputFocus */ 43, 0, 1 } };
+ struct iovec vector[2];
+ vector[1].iov_base = (char *) &sync_req;
+ vector[1].iov_len = sizeof(sync_req);
+ send_request(c, 0, WORKAROUND_NONE, XCB_REQUEST_DISCARD_REPLY, vector + 1, 1);
+}
+
+static void get_socket_back(xcb_connection_t *c)
+{
+ while(c->out.return_socket && c->out.socket_moving)
+ pthread_cond_wait(&c->out.socket_cond, &c->iolock);
+ if(!c->out.return_socket)
+ return;
+
+ c->out.socket_moving = 1;
+ pthread_mutex_unlock(&c->iolock);
+ c->out.return_socket(c->out.socket_closure);
+ pthread_mutex_lock(&c->iolock);
+ c->out.socket_moving = 0;
+
+ pthread_cond_broadcast(&c->out.socket_cond);
+ c->out.return_socket = 0;
+ c->out.socket_closure = 0;
+ _xcb_in_replies_done(c);
+}
+
+/* Public interface */
+
+void xcb_prefetch_maximum_request_length(xcb_connection_t *c)
+{
+ if(c->has_error)
+ return;
+ pthread_mutex_lock(&c->out.reqlenlock);
+ if(c->out.maximum_request_length_tag == LAZY_NONE)
+ {
+ const xcb_query_extension_reply_t *ext;
+ ext = xcb_get_extension_data(c, &xcb_big_requests_id);
+ if(ext && ext->present)
+ {
+ c->out.maximum_request_length_tag = LAZY_COOKIE;
+ c->out.maximum_request_length.cookie = xcb_big_requests_enable(c);
+ }
+ else
+ {
+ c->out.maximum_request_length_tag = LAZY_FORCED;
+ c->out.maximum_request_length.value = c->setup->maximum_request_length;
+ }
+ }
+ pthread_mutex_unlock(&c->out.reqlenlock);
+}
+
+uint32_t xcb_get_maximum_request_length(xcb_connection_t *c)
+{
+ if(c->has_error)
+ return 0;
+ xcb_prefetch_maximum_request_length(c);
+ pthread_mutex_lock(&c->out.reqlenlock);
+ if(c->out.maximum_request_length_tag == LAZY_COOKIE)
+ {
+ xcb_big_requests_enable_reply_t *r = xcb_big_requests_enable_reply(c, c->out.maximum_request_length.cookie, 0);
+ c->out.maximum_request_length_tag = LAZY_FORCED;
+ if(r)
+ {
+ c->out.maximum_request_length.value = r->maximum_request_length;
+ free(r);
+ }
+ else
+ c->out.maximum_request_length.value = c->setup->maximum_request_length;
+ }
+ pthread_mutex_unlock(&c->out.reqlenlock);
+ return c->out.maximum_request_length.value;
+}
+
+unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *req)
+{
+ uint64_t request;
+ uint32_t prefix[2];
+ int veclen = req->count;
+ enum workarounds workaround = WORKAROUND_NONE;
+
+ if(c->has_error)
+ return 0;
+
+ assert(c != 0);
+ assert(vector != 0);
+ assert(req->count > 0);
+
+ if(!(flags & XCB_REQUEST_RAW))
+ {
+ static const char pad[3];
+ unsigned int i;
+ uint16_t shortlen = 0;
+ size_t longlen = 0;
+ assert(vector[0].iov_len >= 4);
+ /* set the major opcode, and the minor opcode for extensions */
+ if(req->ext)
+ {
+ const xcb_query_extension_reply_t *extension = xcb_get_extension_data(c, req->ext);
+ if(!(extension && extension->present))
+ {
+ _xcb_conn_shutdown(c);
+ return 0;
+ }
+ ((uint8_t *) vector[0].iov_base)[0] = extension->major_opcode;
+ ((uint8_t *) vector[0].iov_base)[1] = req->opcode;
+ }
+ else
+ ((uint8_t *) vector[0].iov_base)[0] = req->opcode;
+
+ /* put together the length field, possibly using BIGREQUESTS */
+ for(i = 0; i < req->count; ++i)
+ {
+ longlen += vector[i].iov_len;
+ if(!vector[i].iov_base)
+ {
+ vector[i].iov_base = (char *) pad;
+ assert(vector[i].iov_len <= sizeof(pad));
+ }
+ }
+ assert((longlen & 3) == 0);
+ longlen >>= 2;
+
+ if(longlen <= c->setup->maximum_request_length)
+ {
+ /* we don't need BIGREQUESTS. */
+ shortlen = longlen;
+ longlen = 0;
+ }
+ else if(longlen > xcb_get_maximum_request_length(c))
+ {
+ _xcb_conn_shutdown(c);
+ return 0; /* server can't take this; maybe need BIGREQUESTS? */
+ }
+
+ /* set the length field. */
+ ((uint16_t *) vector[0].iov_base)[1] = shortlen;
+ if(!shortlen)
+ {
+ prefix[0] = ((uint32_t *) vector[0].iov_base)[0];
+ prefix[1] = ++longlen;
+ vector[0].iov_base = (caddr_t)((uint32_t *) vector[0].iov_base + 1);
+ vector[0].iov_len -= sizeof(uint32_t);
+ --vector, ++veclen;
+ vector[0].iov_base = (caddr_t)prefix;
+ vector[0].iov_len = sizeof(prefix);
+ }
+ }
+ flags &= ~XCB_REQUEST_RAW;
+
+ /* do we need to work around the X server bug described in glx.xml? */
+ /* XXX: GetFBConfigs won't use BIG-REQUESTS in any sane
+ * configuration, but that should be handled here anyway. */
+ if(req->ext && !req->isvoid && !strcmp(req->ext->name, "GLX") &&
+ ((req->opcode == 17 && ((uint32_t *) vector[0].iov_base)[1] == 0x10004) ||
+ req->opcode == 21))
+ workaround = WORKAROUND_GLX_GET_FB_CONFIGS_BUG;
+
+ /* get a sequence number and arrange for delivery. */
+ pthread_mutex_lock(&c->iolock);
+ /* wait for other writing threads to get out of my way. */
+ while(c->out.writing)
+ pthread_cond_wait(&c->out.cond, &c->iolock);
+ get_socket_back(c);
+
+ /* send GetInputFocus (sync_req) when 64k-2 requests have been sent without
+ * a reply. */
+ if(req->isvoid && c->out.request == c->in.request_expected + (1 << 16) - 2)
+ send_sync(c);
+ /* Also send sync_req (could use NoOp) at 32-bit wrap to avoid having
+ * applications see sequence 0 as that is used to indicate
+ * an error in sending the request */
+ if((unsigned int) (c->out.request + 1) == 0)
+ send_sync(c);
+
+ /* The above send_sync calls could drop the I/O lock, but this
+ * thread will still exclude any other thread that tries to write,
+ * so the sequence number postconditions still hold. */
+ send_request(c, req->isvoid, workaround, flags, vector, veclen);
+ request = c->has_error ? 0 : c->out.request;
+ pthread_mutex_unlock(&c->iolock);
+ return request;
+}
+
+int xcb_take_socket(xcb_connection_t *c, void (*return_socket)(void *closure), void *closure, int flags, uint64_t *sent)
+{
+ int ret;
+ if(c->has_error)
+ return 0;
+ pthread_mutex_lock(&c->iolock);
+ get_socket_back(c);
+ ret = _xcb_out_flush_to(c, c->out.request);
+ if(ret)
+ {
+ c->out.return_socket = return_socket;
+ c->out.socket_closure = closure;
+ if(flags)
+ _xcb_in_expect_reply(c, c->out.request, WORKAROUND_EXTERNAL_SOCKET_OWNER, flags);
+ assert(c->out.request == c->out.request_written);
+ *sent = c->out.request;
+ }
+ pthread_mutex_unlock(&c->iolock);
+ return ret;
+}
+
+int xcb_writev(xcb_connection_t *c, struct iovec *vector, int count, uint64_t requests)
+{
+ int ret;
+ if(c->has_error)
+ return 0;
+ pthread_mutex_lock(&c->iolock);
+ c->out.request += requests;
+ ret = _xcb_out_send(c, vector, count);
+ pthread_mutex_unlock(&c->iolock);
+ return ret;
+}
+
+int xcb_flush(xcb_connection_t *c)
+{
+ int ret;
+ if(c->has_error)
+ return 0;
+ pthread_mutex_lock(&c->iolock);
+ ret = _xcb_out_flush_to(c, c->out.request);
+ pthread_mutex_unlock(&c->iolock);
+ return ret;
+}
+
+/* Private interface */
+
+int _xcb_out_init(_xcb_out *out)
+{
+ if(pthread_cond_init(&out->socket_cond, 0))
+ return 0;
+ out->return_socket = 0;
+ out->socket_closure = 0;
+ out->socket_moving = 0;
+
+ if(pthread_cond_init(&out->cond, 0))
+ return 0;
+ out->writing = 0;
+
+ out->queue_len = 0;
+
+ out->request = 0;
+ out->request_written = 0;
+
+ if(pthread_mutex_init(&out->reqlenlock, 0))
+ return 0;
+ out->maximum_request_length_tag = LAZY_NONE;
+
+ return 1;
+}
+
+void _xcb_out_destroy(_xcb_out *out)
+{
+ pthread_cond_destroy(&out->cond);
+ pthread_mutex_destroy(&out->reqlenlock);
+}
+
+int _xcb_out_send(xcb_connection_t *c, struct iovec *vector, int count)
+{
+ int ret = 1;
+ while(ret && count)
+ ret = _xcb_conn_wait(c, &c->out.cond, &vector, &count);
+ c->out.request_written = c->out.request;
+ pthread_cond_broadcast(&c->out.cond);
+ _xcb_in_wake_up_next_reader(c);
+ return ret;
+}
+
+void _xcb_out_send_sync(xcb_connection_t *c)
+{
+ /* wait for other writing threads to get out of my way. */
+ while(c->out.writing)
+ pthread_cond_wait(&c->out.cond, &c->iolock);
+ get_socket_back(c);
+ send_sync(c);
+}
+
+int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request)
+{
+ assert(XCB_SEQUENCE_COMPARE(request, <=, c->out.request));
+ if(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request))
+ return 1;
+ if(c->out.queue_len)
+ {
+ struct iovec vec;
+ vec.iov_base = c->out.queue;
+ vec.iov_len = c->out.queue_len;
+ c->out.queue_len = 0;
+ return _xcb_out_send(c, &vec, 1);
+ }
+ while(c->out.writing)
+ pthread_cond_wait(&c->out.cond, &c->iolock);
+ assert(XCB_SEQUENCE_COMPARE(c->out.request_written, >=, request));
+ return 1;
+}
diff --git a/libxcb/src/xcbint.h b/libxcb/src/xcbint.h index 6613433ce..5950823f0 100644 --- a/libxcb/src/xcbint.h +++ b/libxcb/src/xcbint.h @@ -54,7 +54,6 @@ enum lazy_reply_tag #define XCB_PAD(i) (-(i) & 3)
#define XCB_SEQUENCE_COMPARE(a,op,b) ((int64_t) ((a) - (b)) op 0)
-#define XCB_SEQUENCE_COMPARE_32(a,op,b) (((int) (a) - (int) (b)) op 0)
#ifndef offsetof
#define offsetof(type,member) ((size_t) &((type *)0)->member)
@@ -107,6 +106,7 @@ int _xcb_out_init(_xcb_out *out); void _xcb_out_destroy(_xcb_out *out);
int _xcb_out_send(xcb_connection_t *c, struct iovec *vector, int count);
+void _xcb_out_send_sync(xcb_connection_t *c);
int _xcb_out_flush_to(xcb_connection_t *c, uint64_t request);
diff --git a/mesalib/configs/linux-llvm b/mesalib/configs/linux-llvm index e6999539a..cd4730d67 100644 --- a/mesalib/configs/linux-llvm +++ b/mesalib/configs/linux-llvm @@ -1,44 +1,44 @@ -# -*-makefile-*- -# Configuration for Linux and LLVM with optimizations -# Builds the llvmpipe gallium driver - -include $(TOP)/configs/linux - -CONFIG_NAME = linux-llvm - -# Add llvmpipe driver -GALLIUM_DRIVERS_DIRS += llvmpipe - -OPT_FLAGS = -O3 -ansi -pedantic -ARCH_FLAGS = -mmmx -msse -msse2 -mstackrealign - -DEFINES += -DNDEBUG -DGALLIUM_LLVMPIPE -DHAVE_UDIS86 - -# override -std=c99 -CFLAGS += -std=gnu99 - -LLVM_VERSION := $(shell llvm-config --version) - -ifeq ($(LLVM_VERSION),) - $(warning Could not find LLVM! Make Sure 'llvm-config' is in the path) - MESA_LLVM=0 -else - MESA_LLVM=1 - HAVE_LLVM := 0x0$(subst .,0,$(LLVM_VERSION:svn=)) - DEFINES += -DHAVE_LLVM=$(HAVE_LLVM) -# $(info Using LLVM version: $(LLVM_VERSION)) -endif - -ifeq ($(MESA_LLVM),1) - LLVM_CFLAGS=`llvm-config --cppflags` - LLVM_CXXFLAGS=`llvm-config --cxxflags backend bitreader engine ipo interpreter instrumentation` -Wno-long-long - LLVM_LDFLAGS = $(shell llvm-config --ldflags backend bitreader engine ipo interpreter instrumentation) - LLVM_LIBS = $(shell llvm-config --libs backend bitwriter bitreader engine ipo interpreter instrumentation) - MKLIB_OPTIONS=-cplusplus -else - LLVM_CFLAGS= - LLVM_CXXFLAGS= -endif - -LD = g++ -GL_LIB_DEPS = $(LLVM_LDFLAGS) $(LLVM_LIBS) $(EXTRA_LIB_PATH) -lX11 -lXext -lm -lpthread -lstdc++ -ludis86 +# -*-makefile-*-
+# Configuration for Linux and LLVM with optimizations
+# Builds the llvmpipe gallium driver
+
+include $(TOP)/configs/linux
+
+CONFIG_NAME = linux-llvm
+
+# Add llvmpipe driver
+GALLIUM_DRIVERS_DIRS += llvmpipe
+
+OPT_FLAGS = -O3 -ansi -pedantic
+ARCH_FLAGS = -mmmx -msse -msse2 -mstackrealign
+
+DEFINES += -DNDEBUG -DGALLIUM_LLVMPIPE
+
+# override -std=c99
+CFLAGS += -std=gnu99
+
+LLVM_VERSION := $(shell llvm-config --version)
+
+ifeq ($(LLVM_VERSION),)
+ $(warning Could not find LLVM! Make Sure 'llvm-config' is in the path)
+ MESA_LLVM=0
+else
+ MESA_LLVM=1
+ HAVE_LLVM := 0x0$(subst .,0,$(LLVM_VERSION:svn=))
+ DEFINES += -DHAVE_LLVM=$(HAVE_LLVM)
+# $(info Using LLVM version: $(LLVM_VERSION))
+endif
+
+ifeq ($(MESA_LLVM),1)
+ LLVM_CFLAGS=`llvm-config --cppflags`
+ LLVM_CXXFLAGS=`llvm-config --cxxflags backend bitreader engine ipo interpreter instrumentation` -Wno-long-long
+ LLVM_LDFLAGS = $(shell llvm-config --ldflags backend bitreader engine ipo interpreter instrumentation)
+ LLVM_LIBS = $(shell llvm-config --libs backend bitwriter bitreader engine ipo interpreter instrumentation)
+ MKLIB_OPTIONS=-cplusplus
+else
+ LLVM_CFLAGS=
+ LLVM_CXXFLAGS=
+endif
+
+LD = g++
+GL_LIB_DEPS = $(LLVM_LDFLAGS) $(LLVM_LIBS) $(EXTRA_LIB_PATH) -lX11 -lXext -lm -lpthread -lstdc++
diff --git a/mesalib/configure.ac b/mesalib/configure.ac index 4c278eef5..7b8010a76 100644 --- a/mesalib/configure.ac +++ b/mesalib/configure.ac @@ -1400,8 +1400,6 @@ if test "x$enable_gallium" = xno -a "x$enable_openvg" = xyes; then fi
if test "x$enable_gallium" = xyes; then
SRC_DIRS="$SRC_DIRS gallium gallium/winsys gallium/targets"
- AC_CHECK_HEADER([udis86.h], [HAS_UDIS86="yes"],
- [HAS_UDIS86="no"])
AC_PATH_PROG([LLVM_CONFIG], [llvm-config], [no])
fi
@@ -1653,10 +1651,6 @@ if test "x$enable_gallium_llvm" = xyes; then LLVM_CFLAGS=`$LLVM_CONFIG --cppflags`
LLVM_LIBS="`$LLVM_CONFIG --libs jit interpreter nativecodegen bitwriter` -lstdc++"
- if test "x$HAS_UDIS86" != xno; then
- LLVM_LIBS="$LLVM_LIBS -ludis86"
- DEFINES="$DEFINES -DHAVE_UDIS86"
- fi
LLVM_LDFLAGS=`$LLVM_CONFIG --ldflags`
GALLIUM_DRIVERS_DIRS="$GALLIUM_DRIVERS_DIRS llvmpipe"
DEFINES="$DEFINES -DGALLIUM_LLVMPIPE -D__STDC_CONSTANT_MACROS"
diff --git a/mesalib/scons/gallium.py b/mesalib/scons/gallium.py index a0c458683..a61a9af8c 100644 --- a/mesalib/scons/gallium.py +++ b/mesalib/scons/gallium.py @@ -602,7 +602,6 @@ def generate(env): env.Tool('yacc')
if env['llvm']:
env.Tool('llvm')
- env.Tool('udis86')
pkg_config_modules(env, 'x11', ['x11', 'xext'])
pkg_config_modules(env, 'drm', ['libdrm'])
diff --git a/mesalib/scons/llvm.py b/mesalib/scons/llvm.py index 3fef9e090..364cfe366 100644 --- a/mesalib/scons/llvm.py +++ b/mesalib/scons/llvm.py @@ -1,166 +1,166 @@ -"""llvm - -Tool-specific initialization for LLVM - -""" - -# -# Copyright (c) 2009 VMware, Inc. -# -# 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, sublicense, 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 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 -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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. -# - -import os -import os.path -import re -import sys -import distutils.version - -import SCons.Errors -import SCons.Util - - -def generate(env): - env['llvm'] = False - - try: - llvm_dir = os.environ['LLVM'] - except KeyError: - # Do nothing -- use the system headers/libs - llvm_dir = None - else: - if not os.path.isdir(llvm_dir): - raise SCons.Errors.InternalError, "Specified LLVM directory not found" - - if env['debug']: - llvm_subdir = 'Debug' - else: - llvm_subdir = 'Release' - - llvm_bin_dir = os.path.join(llvm_dir, llvm_subdir, 'bin') - if not os.path.isdir(llvm_bin_dir): - llvm_bin_dir = os.path.join(llvm_dir, 'bin') - if not os.path.isdir(llvm_bin_dir): - raise SCons.Errors.InternalError, "LLVM binary directory not found" - - env.PrependENVPath('PATH', llvm_bin_dir) - - if env['platform'] == 'windows': - # XXX: There is no llvm-config on Windows, so assume a standard layout - if llvm_dir is None: - print 'scons: LLVM environment variable must be specified when building for windows' - return - - # Try to determine the LLVM version from llvm/Config/config.h - llvm_config = os.path.join(llvm_dir, 'include/llvm/Config/config.h') - if not os.path.exists(llvm_config): - print 'scons: could not find %s' % llvm_config - return - llvm_version_re = re.compile(r'^#define PACKAGE_VERSION "([^"]*)"') - llvm_version = None - for line in open(llvm_config, 'rt'): - mo = llvm_version_re.match(line) - if mo: - llvm_version = mo.group(1) - llvm_version = distutils.version.LooseVersion(llvm_version) - break - if llvm_version is None: - print 'scons: could not determine the LLVM version from %s' % llvm_config - return - - env.Prepend(CPPPATH = [os.path.join(llvm_dir, 'include')]) - env.AppendUnique(CPPDEFINES = [ - '__STDC_LIMIT_MACROS', - '__STDC_CONSTANT_MACROS', - 'HAVE_STDINT_H', - ]) - env.Prepend(LIBPATH = [os.path.join(llvm_dir, 'lib')]) - if llvm_version >= distutils.version.LooseVersion('2.7'): - # 2.7 - env.Prepend(LIBS = [ - 'LLVMLinker', 'LLVMipo', 'LLVMInterpreter', - 'LLVMInstrumentation', 'LLVMJIT', 'LLVMExecutionEngine', - 'LLVMBitWriter', 'LLVMX86Disassembler', 'LLVMX86AsmParser', - 'LLVMMCParser', 'LLVMX86AsmPrinter', 'LLVMX86CodeGen', - 'LLVMSelectionDAG', 'LLVMX86Info', 'LLVMAsmPrinter', - 'LLVMCodeGen', 'LLVMScalarOpts', 'LLVMInstCombine', - 'LLVMTransformUtils', 'LLVMipa', 'LLVMAsmParser', - 'LLVMArchive', 'LLVMBitReader', 'LLVMAnalysis', 'LLVMTarget', - 'LLVMMC', 'LLVMCore', 'LLVMSupport', 'LLVMSystem', - ]) - else: - # 2.6 - env.Prepend(LIBS = [ - 'LLVMX86AsmParser', 'LLVMX86AsmPrinter', 'LLVMX86CodeGen', - 'LLVMX86Info', 'LLVMLinker', 'LLVMipo', 'LLVMInterpreter', - 'LLVMInstrumentation', 'LLVMJIT', 'LLVMExecutionEngine', - 'LLVMDebugger', 'LLVMBitWriter', 'LLVMAsmParser', - 'LLVMArchive', 'LLVMBitReader', 'LLVMSelectionDAG', - 'LLVMAsmPrinter', 'LLVMCodeGen', 'LLVMScalarOpts', - 'LLVMTransformUtils', 'LLVMipa', 'LLVMAnalysis', - 'LLVMTarget', 'LLVMMC', 'LLVMCore', 'LLVMSupport', - 'LLVMSystem', - ]) - env.Append(LIBS = [ - 'imagehlp', - 'psapi', - ]) - if env['msvc']: - # Some of the LLVM C headers use the inline keyword without - # defining it. - env.Append(CPPDEFINES = [('inline', '__inline')]) - if env['build'] in ('debug', 'checked'): - # LLVM libraries are static, build with /MT, and they - # automatically link agains LIBCMT. When we're doing a - # debug build we'll be linking against LIBCMTD, so disable - # that. - env.Append(LINKFLAGS = ['/nodefaultlib:LIBCMT']) - else: - if not env.Detect('llvm-config'): - print 'scons: llvm-config script not found' % llvm_version - return - - llvm_version = env.backtick('llvm-config --version').rstrip() - llvm_version = distutils.version.LooseVersion(llvm_version) - - try: - env.ParseConfig('llvm-config --cppflags') - env.ParseConfig('llvm-config --libs jit interpreter nativecodegen bitwriter') - env.ParseConfig('llvm-config --ldflags') - except OSError: - print 'scons: llvm-config version %s failed' % llvm_version - return - - assert llvm_version is not None - env['llvm'] = True - - print 'scons: Found LLVM version %s' % llvm_version - env['LLVM_VERSION'] = llvm_version - - # Define HAVE_LLVM macro with the major/minor version number (e.g., 0x0206 for 2.6) - llvm_version_major = int(llvm_version.version[0]) - llvm_version_minor = int(llvm_version.version[1]) - llvm_version_hex = '0x%02x%02x' % (llvm_version_major, llvm_version_minor) - env.Prepend(CPPDEFINES = [('HAVE_LLVM', llvm_version_hex)]) - -def exists(env): - return True - -# vim:set ts=4 sw=4 et: +"""llvm
+
+Tool-specific initialization for LLVM
+
+"""
+
+#
+# Copyright (c) 2009 VMware, Inc.
+#
+# 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, sublicense, 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 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
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
+#
+
+import os
+import os.path
+import re
+import sys
+import distutils.version
+
+import SCons.Errors
+import SCons.Util
+
+
+def generate(env):
+ env['llvm'] = False
+
+ try:
+ llvm_dir = os.environ['LLVM']
+ except KeyError:
+ # Do nothing -- use the system headers/libs
+ llvm_dir = None
+ else:
+ if not os.path.isdir(llvm_dir):
+ raise SCons.Errors.InternalError, "Specified LLVM directory not found"
+
+ if env['debug']:
+ llvm_subdir = 'Debug'
+ else:
+ llvm_subdir = 'Release'
+
+ llvm_bin_dir = os.path.join(llvm_dir, llvm_subdir, 'bin')
+ if not os.path.isdir(llvm_bin_dir):
+ llvm_bin_dir = os.path.join(llvm_dir, 'bin')
+ if not os.path.isdir(llvm_bin_dir):
+ raise SCons.Errors.InternalError, "LLVM binary directory not found"
+
+ env.PrependENVPath('PATH', llvm_bin_dir)
+
+ if env['platform'] == 'windows':
+ # XXX: There is no llvm-config on Windows, so assume a standard layout
+ if llvm_dir is None:
+ print 'scons: LLVM environment variable must be specified when building for windows'
+ return
+
+ # Try to determine the LLVM version from llvm/Config/config.h
+ llvm_config = os.path.join(llvm_dir, 'include/llvm/Config/config.h')
+ if not os.path.exists(llvm_config):
+ print 'scons: could not find %s' % llvm_config
+ return
+ llvm_version_re = re.compile(r'^#define PACKAGE_VERSION "([^"]*)"')
+ llvm_version = None
+ for line in open(llvm_config, 'rt'):
+ mo = llvm_version_re.match(line)
+ if mo:
+ llvm_version = mo.group(1)
+ llvm_version = distutils.version.LooseVersion(llvm_version)
+ break
+ if llvm_version is None:
+ print 'scons: could not determine the LLVM version from %s' % llvm_config
+ return
+
+ env.Prepend(CPPPATH = [os.path.join(llvm_dir, 'include')])
+ env.AppendUnique(CPPDEFINES = [
+ '__STDC_LIMIT_MACROS',
+ '__STDC_CONSTANT_MACROS',
+ 'HAVE_STDINT_H',
+ ])
+ env.Prepend(LIBPATH = [os.path.join(llvm_dir, 'lib')])
+ if llvm_version >= distutils.version.LooseVersion('2.7'):
+ # 2.7
+ env.Prepend(LIBS = [
+ 'LLVMLinker', 'LLVMipo', 'LLVMInterpreter',
+ 'LLVMInstrumentation', 'LLVMJIT', 'LLVMExecutionEngine',
+ 'LLVMBitWriter', 'LLVMX86Disassembler', 'LLVMX86AsmParser',
+ 'LLVMMCParser', 'LLVMX86AsmPrinter', 'LLVMX86CodeGen',
+ 'LLVMSelectionDAG', 'LLVMX86Info', 'LLVMAsmPrinter',
+ 'LLVMCodeGen', 'LLVMScalarOpts', 'LLVMInstCombine',
+ 'LLVMTransformUtils', 'LLVMipa', 'LLVMAsmParser',
+ 'LLVMArchive', 'LLVMBitReader', 'LLVMAnalysis', 'LLVMTarget',
+ 'LLVMMC', 'LLVMCore', 'LLVMSupport', 'LLVMSystem',
+ ])
+ else:
+ # 2.6
+ env.Prepend(LIBS = [
+ 'LLVMX86AsmParser', 'LLVMX86AsmPrinter', 'LLVMX86CodeGen',
+ 'LLVMX86Info', 'LLVMLinker', 'LLVMipo', 'LLVMInterpreter',
+ 'LLVMInstrumentation', 'LLVMJIT', 'LLVMExecutionEngine',
+ 'LLVMDebugger', 'LLVMBitWriter', 'LLVMAsmParser',
+ 'LLVMArchive', 'LLVMBitReader', 'LLVMSelectionDAG',
+ 'LLVMAsmPrinter', 'LLVMCodeGen', 'LLVMScalarOpts',
+ 'LLVMTransformUtils', 'LLVMipa', 'LLVMAnalysis',
+ 'LLVMTarget', 'LLVMMC', 'LLVMCore', 'LLVMSupport',
+ 'LLVMSystem',
+ ])
+ env.Append(LIBS = [
+ 'imagehlp',
+ 'psapi',
+ ])
+ if env['msvc']:
+ # Some of the LLVM C headers use the inline keyword without
+ # defining it.
+ env.Append(CPPDEFINES = [('inline', '__inline')])
+ if env['build'] in ('debug', 'checked'):
+ # LLVM libraries are static, build with /MT, and they
+ # automatically link agains LIBCMT. When we're doing a
+ # debug build we'll be linking against LIBCMTD, so disable
+ # that.
+ env.Append(LINKFLAGS = ['/nodefaultlib:LIBCMT'])
+ else:
+ if not env.Detect('llvm-config'):
+ print 'scons: llvm-config script not found' % llvm_version
+ return
+
+ llvm_version = env.backtick('llvm-config --version').rstrip()
+ llvm_version = distutils.version.LooseVersion(llvm_version)
+
+ try:
+ env.ParseConfig('llvm-config --cppflags')
+ env.ParseConfig('llvm-config --libs')
+ env.ParseConfig('llvm-config --ldflags')
+ except OSError:
+ print 'scons: llvm-config version %s failed' % llvm_version
+ return
+
+ assert llvm_version is not None
+ env['llvm'] = True
+
+ print 'scons: Found LLVM version %s' % llvm_version
+ env['LLVM_VERSION'] = llvm_version
+
+ # Define HAVE_LLVM macro with the major/minor version number (e.g., 0x0206 for 2.6)
+ llvm_version_major = int(llvm_version.version[0])
+ llvm_version_minor = int(llvm_version.version[1])
+ llvm_version_hex = '0x%02x%02x' % (llvm_version_major, llvm_version_minor)
+ env.Prepend(CPPDEFINES = [('HAVE_LLVM', llvm_version_hex)])
+
+def exists(env):
+ return True
+
+# vim:set ts=4 sw=4 et:
diff --git a/mesalib/scons/udis86.py b/mesalib/scons/udis86.py deleted file mode 100644 index 82dd01a8f..000000000 --- a/mesalib/scons/udis86.py +++ /dev/null @@ -1,44 +0,0 @@ -"""udis86
-
-Tool-specific initialization for udis86
-
-"""
-
-#
-# Copyright (c) 2009 VMware, Inc.
-#
-# 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, sublicense, 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 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
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
-#
-
-def generate(env):
- conf = env.Configure()
-
- if conf.CheckHeader('udis86.h'): # and conf.CheckLib('udis86'):
- env['UDIS86'] = True
- env.Prepend(LIBS = ['udis86'])
- else:
- env['UDIS86'] = False
-
- conf.Finish()
-
-def exists(env):
- return True
-
-# vim:set ts=4 sw=4 et:
diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h index 8efe12a00..e4c84c953 100644 --- a/mesalib/src/glsl/glsl_types.h +++ b/mesalib/src/glsl/glsl_types.h @@ -70,7 +70,7 @@ struct glsl_type { GLenum gl_type;
glsl_base_type base_type;
- unsigned sampler_dimensionality:3;
+ unsigned sampler_dimensionality:3; /**< \see glsl_sampler_dim */
unsigned sampler_shadow:1;
unsigned sampler_array:1;
unsigned sampler_type:2; /**< Type of data returned using this sampler.
diff --git a/mesalib/src/mesa/main/ff_fragment_shader.cpp b/mesalib/src/mesa/main/ff_fragment_shader.cpp index ed513397a..0bc534df5 100644 --- a/mesalib/src/mesa/main/ff_fragment_shader.cpp +++ b/mesalib/src/mesa/main/ff_fragment_shader.cpp @@ -3,7 +3,6 @@ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
* Copyright 2009 VMware, Inc. All Rights Reserved.
- * Copyright © 2010 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -31,8 +30,6 @@ extern "C" { #include "glheader.h"
#include "imports.h"
#include "mtypes.h"
-#include "main/uniforms.h"
-#include "main/macros.h"
#include "program/program.h"
#include "program/prog_parameter.h"
#include "program/prog_cache.h"
@@ -42,13 +39,6 @@ extern "C" { #include "program/programopt.h"
#include "texenvprogram.h"
}
-#include "../glsl/glsl_types.h"
-#include "../glsl/ir.h"
-#include "../glsl/glsl_symbol_table.h"
-#include "../glsl/glsl_parser_extras.h"
-#include "../glsl/ir_optimization.h"
-#include "../glsl/ir_print_visitor.h"
-#include "../program/ir_to_mesa.h"
/*
* Note on texture units:
@@ -69,7 +59,7 @@ struct texenvprog_cache_item {
GLuint hash;
void *key;
- struct gl_shader_program *data;
+ struct gl_fragment_program *data;
struct texenvprog_cache_item *next;
};
@@ -86,6 +76,13 @@ texenv_doing_secondary_color(struct gl_context *ctx) return GL_FALSE;
}
+/**
+ * Up to nine instructions per tex unit, plus fog, specular color.
+ */
+#define MAX_INSTRUCTIONS ((MAX_TEXTURE_COORD_UNITS * 9) + 12)
+
+#define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM)
+
struct mode_opt {
#ifdef __GNUC__
__extension__ GLubyte Source:4; /**< SRC_x */
@@ -119,6 +116,8 @@ struct state_key { GLuint NumArgsA:3; /**< up to MAX_COMBINER_TERMS */
GLuint ModeA:5; /**< MODE_x */
+ GLuint texture_cyl_wrap:1; /**< For gallium test/debug only */
+
struct mode_opt OptRGB[MAX_COMBINER_TERMS];
struct mode_opt OptA[MAX_COMBINER_TERMS];
} unit[MAX_TEXTURE_UNITS];
@@ -471,6 +470,10 @@ static GLuint make_state_key( struct gl_context *ctx, struct state_key *key ) key->unit[i].OptRGB[1].Operand = OPR_SRC_COLOR;
key->unit[i].OptRGB[1].Source = texUnit->BumpTarget - GL_TEXTURE0 + SRC_TEXTURE0;
}
+
+ /* this is a back-door for enabling cylindrical texture wrap mode */
+ if (texObj->Priority == 0.125)
+ key->unit[i].texture_cyl_wrap = 1;
}
/* _NEW_LIGHT | _NEW_FOG */
@@ -499,15 +502,40 @@ static GLuint make_state_key( struct gl_context *ctx, struct state_key *key ) }
+/**
+ * Use uregs to represent registers internally, translate to Mesa's
+ * expected formats on emit.
+ *
+ * NOTE: These are passed by value extensively in this file rather
+ * than as usual by pointer reference. If this disturbs you, try
+ * remembering they are just 32bits in size.
+ *
+ * GCC is smart enough to deal with these dword-sized structures in
+ * much the same way as if I had defined them as dwords and was using
+ * macros to access and set the fields. This is much nicer and easier
+ * to evolve.
+ */
+struct ureg {
+ GLuint file:4;
+ GLuint idx:8;
+ GLuint negatebase:1;
+ GLuint swz:12;
+ GLuint pad:7;
+};
+
+static const struct ureg undef = {
+ PROGRAM_UNDEFINED,
+ 255,
+ 0,
+ 0,
+ 0
+};
+
+
/** State used to build the fragment program:
*/
struct texenv_fragment_program {
- struct gl_shader_program *shader_program;
- struct gl_shader *shader;
struct gl_fragment_program *program;
- exec_list *instructions;
- exec_list *top_instructions;
- void *mem_ctx;
struct state_key *state;
GLbitfield alu_temps; /**< Track texture indirections, see spec. */
@@ -515,35 +543,385 @@ struct texenv_fragment_program { GLbitfield temp_in_use; /**< Tracks temporary regs which are in use. */
GLboolean error;
- ir_variable *src_texture[MAX_TEXTURE_COORD_UNITS];
+ struct ureg src_texture[MAX_TEXTURE_COORD_UNITS];
/* Reg containing each texture unit's sampled texture color,
* else undef.
*/
- /* Texcoord override from bumpmapping. */
- struct ir_variable *texcoord_tex[MAX_TEXTURE_COORD_UNITS];
-
+ struct ureg texcoord_tex[MAX_TEXTURE_COORD_UNITS];
/* Reg containing texcoord for a texture unit,
* needed for bump mapping, else undef.
*/
- ir_rvalue *src_previous; /**< Reg containing color from previous
+ struct ureg src_previous; /**< Reg containing color from previous
* stage. May need to be decl'd.
*/
GLuint last_tex_stage; /**< Number of last enabled texture unit */
+
+ struct ureg half;
+ struct ureg one;
+ struct ureg zero;
};
-static ir_rvalue *
-get_source(struct texenv_fragment_program *p,
- GLuint src, GLuint unit)
+
+
+static struct ureg make_ureg(GLuint file, GLuint idx)
+{
+ struct ureg reg;
+ reg.file = file;
+ reg.idx = idx;
+ reg.negatebase = 0;
+ reg.swz = SWIZZLE_NOOP;
+ reg.pad = 0;
+ return reg;
+}
+
+static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w )
+{
+ reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x),
+ GET_SWZ(reg.swz, y),
+ GET_SWZ(reg.swz, z),
+ GET_SWZ(reg.swz, w));
+
+ return reg;
+}
+
+static struct ureg swizzle1( struct ureg reg, int x )
+{
+ return swizzle(reg, x, x, x, x);
+}
+
+static struct ureg negate( struct ureg reg )
+{
+ reg.negatebase ^= 1;
+ return reg;
+}
+
+static GLboolean is_undef( struct ureg reg )
+{
+ return reg.file == PROGRAM_UNDEFINED;
+}
+
+
+static struct ureg get_temp( struct texenv_fragment_program *p )
+{
+ GLint bit;
+
+ /* First try and reuse temps which have been used already:
+ */
+ bit = _mesa_ffs( ~p->temp_in_use & p->alu_temps );
+
+ /* Then any unused temporary:
+ */
+ if (!bit)
+ bit = _mesa_ffs( ~p->temp_in_use );
+
+ if (!bit) {
+ _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__);
+ exit(1);
+ }
+
+ if ((GLuint) bit > p->program->Base.NumTemporaries)
+ p->program->Base.NumTemporaries = bit;
+
+ p->temp_in_use |= 1<<(bit-1);
+ return make_ureg(PROGRAM_TEMPORARY, (bit-1));
+}
+
+static struct ureg get_tex_temp( struct texenv_fragment_program *p )
+{
+ int bit;
+
+ /* First try to find available temp not previously used (to avoid
+ * starting a new texture indirection). According to the spec, the
+ * ~p->temps_output isn't necessary, but will keep it there for
+ * now:
+ */
+ bit = _mesa_ffs( ~p->temp_in_use & ~p->alu_temps & ~p->temps_output );
+
+ /* Then any unused temporary:
+ */
+ if (!bit)
+ bit = _mesa_ffs( ~p->temp_in_use );
+
+ if (!bit) {
+ _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__);
+ exit(1);
+ }
+
+ if ((GLuint) bit > p->program->Base.NumTemporaries)
+ p->program->Base.NumTemporaries = bit;
+
+ p->temp_in_use |= 1<<(bit-1);
+ return make_ureg(PROGRAM_TEMPORARY, (bit-1));
+}
+
+
+/** Mark a temp reg as being no longer allocatable. */
+static void reserve_temp( struct texenv_fragment_program *p, struct ureg r )
+{
+ if (r.file == PROGRAM_TEMPORARY)
+ p->temps_output |= (1 << r.idx);
+}
+
+
+static void release_temps(struct gl_context *ctx, struct texenv_fragment_program *p )
+{
+ GLuint max_temp = ctx->Const.FragmentProgram.MaxTemps;
+
+ /* KW: To support tex_env_crossbar, don't release the registers in
+ * temps_output.
+ */
+ if (max_temp >= sizeof(int) * 8)
+ p->temp_in_use = p->temps_output;
+ else
+ p->temp_in_use = ~((1<<max_temp)-1) | p->temps_output;
+}
+
+
+static struct ureg register_param5( struct texenv_fragment_program *p,
+ GLint s0,
+ GLint s1,
+ GLint s2,
+ GLint s3,
+ GLint s4)
+{
+ int tokens[STATE_LENGTH];
+ GLuint idx;
+ tokens[0] = s0;
+ tokens[1] = s1;
+ tokens[2] = s2;
+ tokens[3] = s3;
+ tokens[4] = s4;
+ idx = _mesa_add_state_reference(p->program->Base.Parameters,
+ (gl_state_index *)tokens);
+ return make_ureg(PROGRAM_STATE_VAR, idx);
+}
+
+
+#define register_param1(p,s0) register_param5(p,s0,0,0,0,0)
+#define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0)
+#define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0)
+#define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0)
+
+static GLuint frag_to_vert_attrib( GLuint attrib )
+{
+ switch (attrib) {
+ case FRAG_ATTRIB_COL0: return VERT_ATTRIB_COLOR0;
+ case FRAG_ATTRIB_COL1: return VERT_ATTRIB_COLOR1;
+ default:
+ assert(attrib >= FRAG_ATTRIB_TEX0);
+ assert(attrib <= FRAG_ATTRIB_TEX7);
+ return attrib - FRAG_ATTRIB_TEX0 + VERT_ATTRIB_TEX0;
+ }
+}
+
+
+static struct ureg register_input( struct texenv_fragment_program *p, GLuint input )
+{
+ if (p->state->inputs_available & (1<<input)) {
+ p->program->Base.InputsRead |= (1 << input);
+ return make_ureg(PROGRAM_INPUT, input);
+ }
+ else {
+ GLuint idx = frag_to_vert_attrib( input );
+ return register_param3( p, STATE_INTERNAL, STATE_CURRENT_ATTRIB, idx );
+ }
+}
+
+
+static void emit_arg( struct prog_src_register *reg,
+ struct ureg ureg )
+{
+ reg->File = ureg.file;
+ reg->Index = ureg.idx;
+ reg->Swizzle = ureg.swz;
+ reg->Negate = ureg.negatebase ? NEGATE_XYZW : NEGATE_NONE;
+ reg->Abs = GL_FALSE;
+}
+
+static void emit_dst( struct prog_dst_register *dst,
+ struct ureg ureg, GLuint mask )
+{
+ dst->File = ureg.file;
+ dst->Index = ureg.idx;
+ dst->WriteMask = mask;
+ dst->CondMask = COND_TR; /* always pass cond test */
+ dst->CondSwizzle = SWIZZLE_NOOP;
+}
+
+static struct prog_instruction *
+emit_op(struct texenv_fragment_program *p,
+ enum prog_opcode op,
+ struct ureg dest,
+ GLuint mask,
+ GLboolean saturate,
+ struct ureg src0,
+ struct ureg src1,
+ struct ureg src2 )
+{
+ const GLuint nr = p->program->Base.NumInstructions++;
+ struct prog_instruction *inst = &p->program->Base.Instructions[nr];
+
+ assert(nr < MAX_INSTRUCTIONS);
+
+ _mesa_init_instructions(inst, 1);
+ inst->Opcode = op;
+
+ emit_arg( &inst->SrcReg[0], src0 );
+ emit_arg( &inst->SrcReg[1], src1 );
+ emit_arg( &inst->SrcReg[2], src2 );
+
+ inst->SaturateMode = saturate ? SATURATE_ZERO_ONE : SATURATE_OFF;
+
+ emit_dst( &inst->DstReg, dest, mask );
+
+#if 0
+ /* Accounting for indirection tracking:
+ */
+ if (dest.file == PROGRAM_TEMPORARY)
+ p->temps_output |= 1 << dest.idx;
+#endif
+
+ return inst;
+}
+
+
+static struct ureg emit_arith( struct texenv_fragment_program *p,
+ enum prog_opcode op,
+ struct ureg dest,
+ GLuint mask,
+ GLboolean saturate,
+ struct ureg src0,
+ struct ureg src1,
+ struct ureg src2 )
+{
+ emit_op(p, op, dest, mask, saturate, src0, src1, src2);
+
+ /* Accounting for indirection tracking:
+ */
+ if (src0.file == PROGRAM_TEMPORARY)
+ p->alu_temps |= 1 << src0.idx;
+
+ if (!is_undef(src1) && src1.file == PROGRAM_TEMPORARY)
+ p->alu_temps |= 1 << src1.idx;
+
+ if (!is_undef(src2) && src2.file == PROGRAM_TEMPORARY)
+ p->alu_temps |= 1 << src2.idx;
+
+ if (dest.file == PROGRAM_TEMPORARY)
+ p->alu_temps |= 1 << dest.idx;
+
+ p->program->Base.NumAluInstructions++;
+ return dest;
+}
+
+static struct ureg emit_texld( struct texenv_fragment_program *p,
+ enum prog_opcode op,
+ struct ureg dest,
+ GLuint destmask,
+ GLuint tex_unit,
+ GLuint tex_idx,
+ GLuint tex_shadow,
+ struct ureg coord )
+{
+ struct prog_instruction *inst = emit_op( p, op,
+ dest, destmask,
+ GL_FALSE, /* don't saturate? */
+ coord, /* arg 0? */
+ undef,
+ undef);
+
+ inst->TexSrcTarget = tex_idx;
+ inst->TexSrcUnit = tex_unit;
+ inst->TexShadow = tex_shadow;
+
+ p->program->Base.NumTexInstructions++;
+
+ /* Accounting for indirection tracking:
+ */
+ reserve_temp(p, dest);
+
+#if 0
+ /* Is this a texture indirection?
+ */
+ if ((coord.file == PROGRAM_TEMPORARY &&
+ (p->temps_output & (1<<coord.idx))) ||
+ (dest.file == PROGRAM_TEMPORARY &&
+ (p->alu_temps & (1<<dest.idx)))) {
+ p->program->Base.NumTexIndirections++;
+ p->temps_output = 1<<coord.idx;
+ p->alu_temps = 0;
+ assert(0); /* KW: texture env crossbar */
+ }
+#endif
+
+ return dest;
+}
+
+
+static struct ureg register_const4f( struct texenv_fragment_program *p,
+ GLfloat s0,
+ GLfloat s1,
+ GLfloat s2,
+ GLfloat s3)
+{
+ GLfloat values[4];
+ GLuint idx, swizzle;
+ struct ureg r;
+ values[0] = s0;
+ values[1] = s1;
+ values[2] = s2;
+ values[3] = s3;
+ idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4,
+ &swizzle );
+ r = make_ureg(PROGRAM_CONSTANT, idx);
+ r.swz = swizzle;
+ return r;
+}
+
+#define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0)
+#define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1)
+#define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1)
+#define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1)
+
+
+static struct ureg get_one( struct texenv_fragment_program *p )
+{
+ if (is_undef(p->one))
+ p->one = register_scalar_const(p, 1.0);
+ return p->one;
+}
+
+static struct ureg get_half( struct texenv_fragment_program *p )
{
- ir_variable *var;
- ir_dereference *deref;
+ if (is_undef(p->half))
+ p->half = register_scalar_const(p, 0.5);
+ return p->half;
+}
+
+static struct ureg get_zero( struct texenv_fragment_program *p )
+{
+ if (is_undef(p->zero))
+ p->zero = register_scalar_const(p, 0.0);
+ return p->zero;
+}
+
+
+static void program_error( struct texenv_fragment_program *p, const char *msg )
+{
+ _mesa_problem(NULL, "%s", msg);
+ p->error = 1;
+}
+static struct ureg get_source( struct texenv_fragment_program *p,
+ GLuint src, GLuint unit )
+{
switch (src) {
case SRC_TEXTURE:
- return new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]);
+ assert(!is_undef(p->src_texture[unit]));
+ return p->src_texture[unit];
case SRC_TEXTURE0:
case SRC_TEXTURE1:
@@ -553,69 +931,66 @@ get_source(struct texenv_fragment_program *p, case SRC_TEXTURE5:
case SRC_TEXTURE6:
case SRC_TEXTURE7:
- return new(p->mem_ctx)
- ir_dereference_variable(p->src_texture[src - SRC_TEXTURE0]);
+ assert(!is_undef(p->src_texture[src - SRC_TEXTURE0]));
+ return p->src_texture[src - SRC_TEXTURE0];
case SRC_CONSTANT:
- var = p->shader->symbols->get_variable("gl_TextureEnvColor");
- assert(var);
- deref = new(p->mem_ctx) ir_dereference_variable(var);
- var->max_array_access = MAX2(var->max_array_access, unit);
- return new(p->mem_ctx) ir_dereference_array(deref,
- new(p->mem_ctx) ir_constant(unit));
+ return register_param2(p, STATE_TEXENV_COLOR, unit);
case SRC_PRIMARY_COLOR:
- var = p->shader->symbols->get_variable("gl_Color");
- assert(var);
- return new(p->mem_ctx) ir_dereference_variable(var);
+ return register_input(p, FRAG_ATTRIB_COL0);
case SRC_ZERO:
- return new(p->mem_ctx) ir_constant(0.0f);
+ return get_zero(p);
case SRC_PREVIOUS:
- if (!p->src_previous) {
- var = p->shader->symbols->get_variable("gl_Color");
- assert(var);
- return new(p->mem_ctx) ir_dereference_variable(var);
- } else {
- return p->src_previous->clone(p->mem_ctx, NULL);
- }
+ if (is_undef(p->src_previous))
+ return register_input(p, FRAG_ATTRIB_COL0);
+ else
+ return p->src_previous;
default:
assert(0);
- return NULL;
+ return undef;
}
}
-static ir_rvalue *
-emit_combine_source(struct texenv_fragment_program *p,
- GLuint unit,
- GLuint source,
- GLuint operand)
+static struct ureg emit_combine_source( struct texenv_fragment_program *p,
+ GLuint mask,
+ GLuint unit,
+ GLuint source,
+ GLuint operand )
{
- ir_rvalue *src;
+ struct ureg arg, src, one;
src = get_source(p, source, unit);
switch (operand) {
case OPR_ONE_MINUS_SRC_COLOR:
- return new(p->mem_ctx) ir_expression(ir_binop_sub,
- new(p->mem_ctx) ir_constant(1.0f),
- src);
+ /* Get unused tmp,
+ * Emit tmp = 1.0 - arg.xyzw
+ */
+ arg = get_temp( p );
+ one = get_one( p );
+ return emit_arith( p, OPCODE_SUB, arg, mask, 0, one, src, undef);
case OPR_SRC_ALPHA:
- return new(p->mem_ctx) ir_swizzle(src, 3, 3, 3, 3, 1);
-
+ if (mask == WRITEMASK_W)
+ return src;
+ else
+ return swizzle1( src, SWIZZLE_W );
case OPR_ONE_MINUS_SRC_ALPHA:
- return new(p->mem_ctx) ir_expression(ir_binop_sub,
- new(p->mem_ctx) ir_constant(1.0f),
- new(p->mem_ctx) ir_swizzle(src,
- 3, 3,
- 3, 3, 1));
+ /* Get unused tmp,
+ * Emit tmp = 1.0 - arg.wwww
+ */
+ arg = get_temp(p);
+ one = get_one(p);
+ return emit_arith(p, OPCODE_SUB, arg, mask, 0,
+ one, swizzle1(src, SWIZZLE_W), undef);
case OPR_ZERO:
- return new(p->mem_ctx) ir_constant(0.0f);
+ return get_zero(p);
case OPR_ONE:
- return new(p->mem_ctx) ir_constant(1.0f);
+ return get_one(p);
case OPR_SRC_COLOR:
return src;
default:
@@ -664,104 +1039,112 @@ static GLboolean args_match( const struct state_key *key, GLuint unit ) return GL_TRUE;
}
-static ir_rvalue *
-smear(struct texenv_fragment_program *p, ir_rvalue *val)
-{
- if (!val->type->is_scalar())
- return val;
-
- return new(p->mem_ctx) ir_swizzle(val, 0, 0, 0, 0, 4);
-}
-
-static ir_rvalue *
-emit_combine(struct texenv_fragment_program *p,
- GLuint unit,
- GLuint nr,
- GLuint mode,
- const struct mode_opt *opt)
+static struct ureg emit_combine( struct texenv_fragment_program *p,
+ struct ureg dest,
+ GLuint mask,
+ GLboolean saturate,
+ GLuint unit,
+ GLuint nr,
+ GLuint mode,
+ const struct mode_opt *opt)
{
- ir_rvalue *src[MAX_COMBINER_TERMS];
- ir_rvalue *tmp0, *tmp1;
+ struct ureg src[MAX_COMBINER_TERMS];
+ struct ureg tmp, half;
GLuint i;
assert(nr <= MAX_COMBINER_TERMS);
for (i = 0; i < nr; i++)
- src[i] = emit_combine_source( p, unit, opt[i].Source, opt[i].Operand );
+ src[i] = emit_combine_source( p, mask, unit, opt[i].Source, opt[i].Operand );
switch (mode) {
case MODE_REPLACE:
- return src[0];
-
+ if (mask == WRITEMASK_XYZW && !saturate)
+ return src[0];
+ else
+ return emit_arith( p, OPCODE_MOV, dest, mask, saturate, src[0], undef, undef );
case MODE_MODULATE:
- return new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]);
-
+ return emit_arith( p, OPCODE_MUL, dest, mask, saturate,
+ src[0], src[1], undef );
case MODE_ADD:
- return new(p->mem_ctx) ir_expression(ir_binop_add, src[0], src[1]);
-
+ return emit_arith( p, OPCODE_ADD, dest, mask, saturate,
+ src[0], src[1], undef );
case MODE_ADD_SIGNED:
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, src[0], src[1]);
- return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
- new(p->mem_ctx) ir_constant(-0.5f));
-
+ /* tmp = arg0 + arg1
+ * result = tmp - .5
+ */
+ half = get_half(p);
+ tmp = get_temp( p );
+ emit_arith( p, OPCODE_ADD, tmp, mask, 0, src[0], src[1], undef );
+ emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp, half, undef );
+ return dest;
case MODE_INTERPOLATE:
- /* Arg0 * (Arg2) + Arg1 * (1-Arg2) */
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
-
- tmp1 = new(p->mem_ctx) ir_expression(ir_binop_sub,
- new(p->mem_ctx) ir_constant(1.0f),
- src[2]->clone(p->mem_ctx, NULL));
- tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[1], tmp1);
-
- return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1);
+ /* Arg0 * (Arg2) + Arg1 * (1-Arg2) -- note arguments are reordered:
+ */
+ return emit_arith( p, OPCODE_LRP, dest, mask, saturate, src[2], src[0], src[1] );
case MODE_SUBTRACT:
- return new(p->mem_ctx) ir_expression(ir_binop_sub, src[0], src[1]);
+ return emit_arith( p, OPCODE_SUB, dest, mask, saturate, src[0], src[1], undef );
case MODE_DOT3_RGBA:
case MODE_DOT3_RGBA_EXT:
case MODE_DOT3_RGB_EXT:
case MODE_DOT3_RGB: {
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0],
- new(p->mem_ctx) ir_constant(2.0f));
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
- new(p->mem_ctx) ir_constant(-1.0f));
- tmp0 = new(p->mem_ctx) ir_swizzle(smear(p, tmp0), 0, 1, 2, 3, 3);
-
- tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[1],
- new(p->mem_ctx) ir_constant(2.0f));
- tmp1 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp1,
- new(p->mem_ctx) ir_constant(-1.0f));
- tmp1 = new(p->mem_ctx) ir_swizzle(smear(p, tmp1), 0, 1, 2, 3, 3);
-
- return new(p->mem_ctx) ir_expression(ir_binop_dot, tmp0, tmp1);
- }
- case MODE_MODULATE_ADD_ATI:
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
- return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, src[1]);
+ struct ureg tmp0 = get_temp( p );
+ struct ureg tmp1 = get_temp( p );
+ struct ureg neg1 = register_scalar_const(p, -1);
+ struct ureg two = register_scalar_const(p, 2);
- case MODE_MODULATE_SIGNED_ADD_ATI:
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, src[1]);
- return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
- new(p->mem_ctx) ir_constant(-0.5f));
+ /* tmp0 = 2*src0 - 1
+ * tmp1 = 2*src1 - 1
+ *
+ * dst = tmp0 dot3 tmp1
+ */
+ emit_arith( p, OPCODE_MAD, tmp0, WRITEMASK_XYZW, 0,
+ two, src[0], neg1);
+ if (memcmp(&src[0], &src[1], sizeof(struct ureg)) == 0)
+ tmp1 = tmp0;
+ else
+ emit_arith( p, OPCODE_MAD, tmp1, WRITEMASK_XYZW, 0,
+ two, src[1], neg1);
+ emit_arith( p, OPCODE_DP3, dest, mask, saturate, tmp0, tmp1, undef);
+ return dest;
+ }
+ case MODE_MODULATE_ADD_ATI:
+ /* Arg0 * Arg2 + Arg1 */
+ return emit_arith( p, OPCODE_MAD, dest, mask, saturate,
+ src[0], src[2], src[1] );
+ case MODE_MODULATE_SIGNED_ADD_ATI: {
+ /* Arg0 * Arg2 + Arg1 - 0.5 */
+ struct ureg tmp0 = get_temp(p);
+ half = get_half(p);
+ emit_arith( p, OPCODE_MAD, tmp0, mask, 0, src[0], src[2], src[1] );
+ emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp0, half, undef );
+ return dest;
+ }
case MODE_MODULATE_SUBTRACT_ATI:
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
- return new(p->mem_ctx) ir_expression(ir_binop_sub, tmp0, src[1]);
-
+ /* Arg0 * Arg2 - Arg1 */
+ emit_arith( p, OPCODE_MAD, dest, mask, 0, src[0], src[2], negate(src[1]) );
+ return dest;
case MODE_ADD_PRODUCTS:
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]);
- tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[2], src[3]);
- return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1);
-
+ /* Arg0 * Arg1 + Arg2 * Arg3 */
+ {
+ struct ureg tmp0 = get_temp(p);
+ emit_arith( p, OPCODE_MUL, tmp0, mask, 0, src[0], src[1], undef );
+ emit_arith( p, OPCODE_MAD, dest, mask, saturate, src[2], src[3], tmp0 );
+ }
+ return dest;
case MODE_ADD_PRODUCTS_SIGNED:
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]);
- tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[2], src[3]);
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1);
- return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
- new(p->mem_ctx) ir_constant(-0.5f));
-
+ /* Arg0 * Arg1 + Arg2 * Arg3 - 0.5 */
+ {
+ struct ureg tmp0 = get_temp(p);
+ half = get_half(p);
+ emit_arith( p, OPCODE_MUL, tmp0, mask, 0, src[0], src[1], undef );
+ emit_arith( p, OPCODE_MAD, tmp0, mask, 0, src[2], src[3], tmp0 );
+ emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp0, half, undef );
+ }
+ return dest;
case MODE_BUMP_ENVMAP_ATI:
/* special - not handled here */
assert(0);
@@ -772,24 +1155,17 @@ emit_combine(struct texenv_fragment_program *p, }
}
-static ir_rvalue *
-saturate(struct texenv_fragment_program *p, ir_rvalue *val)
-{
- val = new(p->mem_ctx) ir_expression(ir_binop_min, val,
- new(p->mem_ctx) ir_constant(1.0f));
- return new(p->mem_ctx) ir_expression(ir_binop_max, val,
- new(p->mem_ctx) ir_constant(0.0f));
-}
/**
* Generate instructions for one texture unit's env/combiner mode.
*/
-static ir_rvalue *
+static struct ureg
emit_texenv(struct texenv_fragment_program *p, GLuint unit)
{
const struct state_key *key = p->state;
GLboolean rgb_saturate, alpha_saturate;
GLuint rgb_shift, alpha_shift;
+ struct ureg out, dest;
if (!key->unit[unit].enabled) {
return get_source(p, SRC_PREVIOUS, 0);
@@ -831,232 +1207,129 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit) else
alpha_saturate = GL_FALSE;
- ir_variable *temp_var = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
- "texenv_combine",
- ir_var_temporary);
- p->instructions->push_tail(temp_var);
-
- ir_dereference *deref;
- ir_assignment *assign;
- ir_rvalue *val;
+ /* If this is the very last calculation (and various other conditions
+ * are met), emit directly to the color output register. Otherwise,
+ * emit to a temporary register.
+ */
+ if (key->separate_specular ||
+ unit != p->last_tex_stage ||
+ alpha_shift ||
+ key->num_draw_buffers != 1 ||
+ rgb_shift)
+ dest = get_temp( p );
+ else
+ dest = make_ureg(PROGRAM_OUTPUT, FRAG_RESULT_COLOR);
/* Emit the RGB and A combine ops
*/
if (key->unit[unit].ModeRGB == key->unit[unit].ModeA &&
args_match(key, unit)) {
- val = emit_combine(p, unit,
- key->unit[unit].NumArgsRGB,
- key->unit[unit].ModeRGB,
- key->unit[unit].OptRGB);
- val = smear(p, val);
- if (rgb_saturate)
- val = saturate(p, val);
-
- deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
- assign = new(p->mem_ctx) ir_assignment(deref, val, NULL);
- p->instructions->push_tail(assign);
+ out = emit_combine( p, dest, WRITEMASK_XYZW, rgb_saturate,
+ unit,
+ key->unit[unit].NumArgsRGB,
+ key->unit[unit].ModeRGB,
+ key->unit[unit].OptRGB);
}
else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT ||
key->unit[unit].ModeRGB == MODE_DOT3_RGBA) {
- ir_rvalue *val = emit_combine(p, unit,
- key->unit[unit].NumArgsRGB,
- key->unit[unit].ModeRGB,
- key->unit[unit].OptRGB);
- val = smear(p, val);
- if (rgb_saturate)
- val = saturate(p, val);
- deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
- assign = new(p->mem_ctx) ir_assignment(deref, val, NULL);
- p->instructions->push_tail(assign);
+ out = emit_combine( p, dest, WRITEMASK_XYZW, rgb_saturate,
+ unit,
+ key->unit[unit].NumArgsRGB,
+ key->unit[unit].ModeRGB,
+ key->unit[unit].OptRGB);
}
else {
/* Need to do something to stop from re-emitting identical
* argument calculations here:
*/
- val = emit_combine(p, unit,
- key->unit[unit].NumArgsRGB,
- key->unit[unit].ModeRGB,
- key->unit[unit].OptRGB);
- val = smear(p, val);
- val = new(p->mem_ctx) ir_swizzle(val, 0, 1, 2, 3, 3);
- if (rgb_saturate)
- val = saturate(p, val);
- deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
- assign = new(p->mem_ctx) ir_assignment(deref, val, NULL, WRITEMASK_XYZ);
- p->instructions->push_tail(assign);
-
- val = emit_combine(p, unit,
- key->unit[unit].NumArgsA,
- key->unit[unit].ModeA,
- key->unit[unit].OptA);
- val = smear(p, val);
- val = new(p->mem_ctx) ir_swizzle(val, 3, 3, 3, 3, 1);
- if (alpha_saturate)
- val = saturate(p, val);
- deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
- assign = new(p->mem_ctx) ir_assignment(deref, val, NULL, WRITEMASK_W);
- p->instructions->push_tail(assign);
+ out = emit_combine( p, dest, WRITEMASK_XYZ, rgb_saturate,
+ unit,
+ key->unit[unit].NumArgsRGB,
+ key->unit[unit].ModeRGB,
+ key->unit[unit].OptRGB);
+ out = emit_combine( p, dest, WRITEMASK_W, alpha_saturate,
+ unit,
+ key->unit[unit].NumArgsA,
+ key->unit[unit].ModeA,
+ key->unit[unit].OptA);
}
- deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
-
/* Deal with the final shift:
*/
if (alpha_shift || rgb_shift) {
- ir_constant *shift;
+ struct ureg shift;
+ GLboolean saturate = GL_TRUE; /* always saturate at this point */
if (rgb_shift == alpha_shift) {
- shift = new(p->mem_ctx) ir_constant((float)(1 << rgb_shift));
+ shift = register_scalar_const(p, (GLfloat)(1<<rgb_shift));
}
else {
- float const_data[4] = {
- 1 << rgb_shift,
- 1 << rgb_shift,
- 1 << rgb_shift,
- 1 << alpha_shift
- };
- shift = new(p->mem_ctx) ir_constant(glsl_type::vec4_type,
- (ir_constant_data *)const_data);
+ shift = register_const4f(p,
+ (GLfloat)(1<<rgb_shift),
+ (GLfloat)(1<<rgb_shift),
+ (GLfloat)(1<<rgb_shift),
+ (GLfloat)(1<<alpha_shift));
}
-
- return saturate(p, new(p->mem_ctx) ir_expression(ir_binop_mul,
- deref, shift));
+ return emit_arith( p, OPCODE_MUL, dest, WRITEMASK_XYZW,
+ saturate, out, shift, undef );
}
else
- return deref;
+ return out;
}
/**
* Generate instruction for getting a texture source term.
*/
- static void load_texture( struct texenv_fragment_program *p, GLuint unit )
- {
- ir_dereference *deref;
- ir_assignment *assign;
-
- if (p->src_texture[unit])
- return;
-
- const GLuint texTarget = p->state->unit[unit].source_index;
- ir_rvalue *texcoord;
-
- if (p->texcoord_tex[unit]) {
- texcoord = new(p->mem_ctx) ir_dereference_variable(p->texcoord_tex[unit]);
- }
- else {
- ir_variable *tc_array = p->shader->symbols->get_variable("gl_TexCoord");
- assert(tc_array);
- texcoord = new(p->mem_ctx) ir_dereference_variable(tc_array);
- ir_rvalue *index = new(p->mem_ctx) ir_constant(unit);
- texcoord = new(p->mem_ctx) ir_dereference_array(texcoord, index);
- tc_array->max_array_access = MAX2(tc_array->max_array_access, unit);
- }
-
- if (!p->state->unit[unit].enabled) {
- p->src_texture[unit] = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
- "dummy_tex",
- ir_var_temporary);
- p->instructions->push_tail(p->src_texture[unit]);
-
- deref = new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]);
- assign = new(p->mem_ctx) ir_assignment(deref,
- new(p->mem_ctx) ir_constant(0.0f),
- NULL);
- p->instructions->push_tail(assign);
- return ;
- }
-
- const glsl_type *sampler_type = NULL;
- int coords = 0;
-
- switch (texTarget) {
- case TEXTURE_1D_INDEX:
- if (p->state->unit[unit].shadow)
- sampler_type = p->shader->symbols->get_type("sampler1DShadow");
- else
- sampler_type = p->shader->symbols->get_type("sampler1D");
- coords = 1;
- break;
- case TEXTURE_1D_ARRAY_INDEX:
- if (p->state->unit[unit].shadow)
- sampler_type = p->shader->symbols->get_type("sampler1DArrayShadow");
- else
- sampler_type = p->shader->symbols->get_type("sampler1DArray");
- coords = 2;
- break;
- case TEXTURE_2D_INDEX:
- if (p->state->unit[unit].shadow)
- sampler_type = p->shader->symbols->get_type("sampler2DShadow");
- else
- sampler_type = p->shader->symbols->get_type("sampler2D");
- coords = 2;
- break;
- case TEXTURE_2D_ARRAY_INDEX:
- if (p->state->unit[unit].shadow)
- sampler_type = p->shader->symbols->get_type("sampler2DArrayShadow");
- else
- sampler_type = p->shader->symbols->get_type("sampler2DArray");
- coords = 3;
- break;
- case TEXTURE_RECT_INDEX:
- if (p->state->unit[unit].shadow)
- sampler_type = p->shader->symbols->get_type("sampler2DRectShadow");
- else
- sampler_type = p->shader->symbols->get_type("sampler2DRect");
- coords = 2;
- break;
- case TEXTURE_3D_INDEX:
- assert(!p->state->unit[unit].shadow);
- sampler_type = p->shader->symbols->get_type("sampler3D");
- coords = 3;
- break;
- case TEXTURE_CUBE_INDEX:
- if (p->state->unit[unit].shadow)
- sampler_type = p->shader->symbols->get_type("samplerCubeShadow");
- else
- sampler_type = p->shader->symbols->get_type("samplerCube");
- coords = 3;
- break;
- }
-
- p->src_texture[unit] = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
- "tex",
- ir_var_temporary);
- p->instructions->push_tail(p->src_texture[unit]);
-
- ir_texture *tex = new(p->mem_ctx) ir_texture(ir_tex);
-
-
- char *sampler_name = ralloc_asprintf(p->mem_ctx, "sampler_%d", unit);
- ir_variable *sampler = new(p->mem_ctx) ir_variable(sampler_type,
- sampler_name,
- ir_var_uniform);
- p->top_instructions->push_head(sampler);
- deref = new(p->mem_ctx) ir_dereference_variable(sampler);
- tex->set_sampler(deref);
-
- tex->coordinate = new(p->mem_ctx) ir_swizzle(texcoord, 0, 1, 2, 3, coords);
-
- if (p->state->unit[unit].shadow) {
- texcoord = texcoord->clone(p->mem_ctx, NULL);
- tex->shadow_comparitor = new(p->mem_ctx) ir_swizzle(texcoord,
- coords, 0, 0, 0,
- 1);
- coords++;
- }
-
- texcoord = texcoord->clone(p->mem_ctx, NULL);
- tex->projector = new(p->mem_ctx) ir_swizzle(texcoord, 3, 0, 0, 0, 1);
-
- deref = new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]);
- assign = new(p->mem_ctx) ir_assignment(deref, tex, NULL);
- p->instructions->push_tail(assign);
- }
+static void load_texture( struct texenv_fragment_program *p, GLuint unit )
+{
+ if (is_undef(p->src_texture[unit])) {
+ const GLuint texTarget = p->state->unit[unit].source_index;
+ struct ureg texcoord;
+ struct ureg tmp = get_tex_temp( p );
-static void
-load_texenv_source(struct texenv_fragment_program *p,
- GLuint src, GLuint unit)
+ if (is_undef(p->texcoord_tex[unit])) {
+ texcoord = register_input(p, FRAG_ATTRIB_TEX0+unit);
+ }
+ else {
+ /* might want to reuse this reg for tex output actually */
+ texcoord = p->texcoord_tex[unit];
+ }
+
+ /* TODO: Use D0_MASK_XY where possible.
+ */
+ if (p->state->unit[unit].enabled) {
+ GLboolean shadow = GL_FALSE;
+
+ if (p->state->unit[unit].shadow) {
+ p->program->Base.ShadowSamplers |= 1 << unit;
+ shadow = GL_TRUE;
+ }
+
+ p->src_texture[unit] = emit_texld( p, OPCODE_TXP,
+ tmp, WRITEMASK_XYZW,
+ unit, texTarget, shadow,
+ texcoord );
+
+ p->program->Base.SamplersUsed |= (1 << unit);
+ /* This identity mapping should already be in place
+ * (see _mesa_init_program_struct()) but let's be safe.
+ */
+ p->program->Base.SamplerUnits[unit] = unit;
+ }
+ else
+ p->src_texture[unit] = get_zero(p);
+
+ if (p->state->unit[unit].texture_cyl_wrap) {
+ /* set flag which is checked by Mesa->Gallium program translation */
+ p->program->Base.InputFlags[0] |= PROG_PARAM_BIT_CYL_WRAP;
+ }
+
+ }
+}
+
+static GLboolean load_texenv_source( struct texenv_fragment_program *p,
+ GLuint src, GLuint unit )
{
switch (src) {
case SRC_TEXTURE:
@@ -1078,6 +1351,8 @@ load_texenv_source(struct texenv_fragment_program *p, /* not a texture src - do nothing */
break;
}
+
+ return GL_TRUE;
}
@@ -1104,214 +1379,108 @@ load_texunit_sources( struct texenv_fragment_program *p, GLuint unit ) /**
* Generate instructions for loading bump map textures.
*/
-static void
+static GLboolean
load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit )
{
const struct state_key *key = p->state;
GLuint bumpedUnitNr = key->unit[unit].OptRGB[1].Source - SRC_TEXTURE0;
- ir_rvalue *bump;
- ir_rvalue *texcoord;
- ir_variable *rot_mat_0_var, *rot_mat_1_var;
- ir_dereference_variable *rot_mat_0, *rot_mat_1;
-
- rot_mat_0_var = p->shader->symbols->get_variable("gl_MESABumpRotMatrix0");
- rot_mat_1_var = p->shader->symbols->get_variable("gl_MESABumpRotMatrix1");
- rot_mat_0 = new(p->mem_ctx) ir_dereference_variable(rot_mat_0_var);
- rot_mat_1 = new(p->mem_ctx) ir_dereference_variable(rot_mat_1_var);
-
- ir_variable *tc_array = p->shader->symbols->get_variable("gl_TexCoord");
- assert(tc_array);
- texcoord = new(p->mem_ctx) ir_dereference_variable(tc_array);
- ir_rvalue *index = new(p->mem_ctx) ir_constant(bumpedUnitNr);
- texcoord = new(p->mem_ctx) ir_dereference_array(texcoord, index);
- tc_array->max_array_access = MAX2(tc_array->max_array_access, unit);
+ struct ureg texcDst, bumpMapRes;
+ struct ureg constdudvcolor = register_const4f(p, 0.0, 0.0, 0.0, 1.0);
+ struct ureg texcSrc = register_input(p, FRAG_ATTRIB_TEX0 + bumpedUnitNr);
+ struct ureg rotMat0 = register_param3( p, STATE_INTERNAL, STATE_ROT_MATRIX_0, unit );
+ struct ureg rotMat1 = register_param3( p, STATE_INTERNAL, STATE_ROT_MATRIX_1, unit );
load_texenv_source( p, unit + SRC_TEXTURE0, unit );
+ bumpMapRes = get_source(p, key->unit[unit].OptRGB[0].Source, unit);
+ texcDst = get_tex_temp( p );
+ p->texcoord_tex[bumpedUnitNr] = texcDst;
+
/* Apply rot matrix and add coords to be available in next phase.
- * dest = Arg1 + (Arg0.xx * rotMat0) + (Arg0.yy * rotMat1)
+ * dest = (Arg0.xxxx * rotMat0 + Arg1) + (Arg0.yyyy * rotMat1)
* note only 2 coords are affected the rest are left unchanged (mul by 0)
*/
- ir_dereference *deref;
- ir_assignment *assign;
- ir_rvalue *bump_x, *bump_y;
-
- texcoord = smear(p, texcoord);
-
- /* bump_texcoord = texcoord */
- ir_variable *bumped = new(p->mem_ctx) ir_variable(texcoord->type,
- "bump_texcoord",
- ir_var_temporary);
- p->instructions->push_tail(bumped);
-
- deref = new(p->mem_ctx) ir_dereference_variable(bumped);
- assign = new(p->mem_ctx) ir_assignment(deref, texcoord, NULL);
- p->instructions->push_tail(assign);
-
- /* bump_texcoord.xy += arg0.x * rotmat0 + arg0.y * rotmat1 */
- bump = get_source(p, key->unit[unit].OptRGB[0].Source, unit);
- bump_x = new(p->mem_ctx) ir_swizzle(bump, 0, 0, 0, 0, 1);
- bump = bump->clone(p->mem_ctx, NULL);
- bump_y = new(p->mem_ctx) ir_swizzle(bump, 1, 0, 0, 0, 1);
-
- bump_x = new(p->mem_ctx) ir_expression(ir_binop_mul, bump_x, rot_mat_0);
- bump_y = new(p->mem_ctx) ir_expression(ir_binop_mul, bump_y, rot_mat_1);
-
- ir_expression *expr;
- expr = new(p->mem_ctx) ir_expression(ir_binop_add, bump_x, bump_y);
-
- deref = new(p->mem_ctx) ir_dereference_variable(bumped);
- expr = new(p->mem_ctx) ir_expression(ir_binop_add,
- new(p->mem_ctx) ir_swizzle(deref,
- 0, 1, 1, 1,
- 2),
- expr);
-
- deref = new(p->mem_ctx) ir_dereference_variable(bumped);
- assign = new(p->mem_ctx) ir_assignment(deref, expr, NULL, WRITEMASK_XY);
- p->instructions->push_tail(assign);
-
- p->texcoord_tex[bumpedUnitNr] = bumped;
+ emit_arith( p, OPCODE_MAD, texcDst, WRITEMASK_XYZW, 0,
+ swizzle1(bumpMapRes, SWIZZLE_X), rotMat0, texcSrc );
+ emit_arith( p, OPCODE_MAD, texcDst, WRITEMASK_XYZW, 0,
+ swizzle1(bumpMapRes, SWIZZLE_Y), rotMat1, texcDst );
+
+ /* Move 0,0,0,1 into bumpmap src if someone (crossbar) is foolish
+ * enough to access this later, should optimize away.
+ */
+ emit_arith( p, OPCODE_MOV, bumpMapRes, WRITEMASK_XYZW, 0,
+ constdudvcolor, undef, undef );
+
+ return GL_TRUE;
}
/**
- * Applies the fog calculations.
- *
- * This is basically like the ARB_fragment_prorgam fog options. Note
- * that ffvertex_prog.c produces fogcoord for us when
- * GL_FOG_COORDINATE_EXT is set to GL_FRAGMENT_DEPTH_EXT.
+ * Generate a new fragment program which implements the context's
+ * current texture env/combine mode.
*/
-static ir_rvalue *
-emit_fog_instructions(struct texenv_fragment_program *p,
- ir_rvalue *fragcolor)
+static void
+create_new_program(struct gl_context *ctx, struct state_key *key,
+ struct gl_fragment_program *program)
{
- struct state_key *key = p->state;
- ir_rvalue *f, *temp;
- ir_variable *params, *oparams;
- ir_variable *fogcoord;
- ir_assignment *assign;
-
- /* Temporary storage for the whole fog result. Fog calculations
- * only affect rgb so we're hanging on to the .a value of fragcolor
- * this way.
- */
- ir_variable *fog_result = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
- "fog_result",
- ir_var_auto);
- p->instructions->push_tail(fog_result);
- temp = new(p->mem_ctx) ir_dereference_variable(fog_result);
- assign = new(p->mem_ctx) ir_assignment(temp, fragcolor, NULL);
- p->instructions->push_tail(assign);
-
- temp = new(p->mem_ctx) ir_dereference_variable(fog_result);
- fragcolor = new(p->mem_ctx) ir_swizzle(temp, 0, 1, 2, 3, 3);
-
- oparams = p->shader->symbols->get_variable("gl_MESAFogParamsOptimized");
- fogcoord = p->shader->symbols->get_variable("gl_FogFragCoord");
- params = p->shader->symbols->get_variable("gl_Fog");
- f = new(p->mem_ctx) ir_dereference_variable(fogcoord);
-
- ir_variable *f_var = new(p->mem_ctx) ir_variable(glsl_type::float_type,
- "fog_factor", ir_var_auto);
- p->instructions->push_tail(f_var);
-
- switch (key->fog_mode) {
- case FOG_LINEAR:
- /* f = (end - z) / (end - start)
- *
- * gl_MesaFogParamsOptimized gives us (-1 / (end - start)) and
- * (end / (end - start)) so we can generate a single MAD.
- */
- temp = new(p->mem_ctx) ir_dereference_variable(oparams);
- temp = new(p->mem_ctx) ir_swizzle(temp, 0, 0, 0, 0, 1);
- f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp);
-
- temp = new(p->mem_ctx) ir_dereference_variable(oparams);
- temp = new(p->mem_ctx) ir_swizzle(temp, 1, 0, 0, 0, 1);
- f = new(p->mem_ctx) ir_expression(ir_binop_add, f, temp);
- break;
- case FOG_EXP:
- /* f = e^(-(density * fogcoord))
- *
- * gl_MesaFogParamsOptimized gives us density/ln(2) so we can
- * use EXP2 which is generally the native instruction without
- * having to do any further math on the fog density uniform.
- */
- temp = new(p->mem_ctx) ir_dereference_variable(oparams);
- temp = new(p->mem_ctx) ir_swizzle(temp, 2, 0, 0, 0, 1);
- f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp);
- f = new(p->mem_ctx) ir_expression(ir_unop_neg, f);
- f = new(p->mem_ctx) ir_expression(ir_unop_exp2, f);
- break;
- case FOG_EXP2:
- /* f = e^(-(density * fogcoord)^2)
- *
- * gl_MesaFogParamsOptimized gives us density/sqrt(ln(2)) so we
- * can do this like FOG_EXP but with a squaring after the
- * multiply by density.
- */
- ir_variable *temp_var = new(p->mem_ctx) ir_variable(glsl_type::float_type,
- "fog_temp",
- ir_var_auto);
- p->instructions->push_tail(temp_var);
-
- temp = new(p->mem_ctx) ir_dereference_variable(oparams);
- temp = new(p->mem_ctx) ir_swizzle(temp, 3, 0, 0, 0, 1);
- f = new(p->mem_ctx) ir_expression(ir_binop_mul,
- f, temp);
-
- temp = new(p->mem_ctx) ir_dereference_variable(temp_var);
- ir_assignment *assign = new(p->mem_ctx) ir_assignment(temp, f, NULL);
- p->instructions->push_tail(assign);
-
- f = new(p->mem_ctx) ir_dereference_variable(temp_var);
- temp = new(p->mem_ctx) ir_dereference_variable(temp_var);
- f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp);
- f = new(p->mem_ctx) ir_expression(ir_unop_neg, f);
- f = new(p->mem_ctx) ir_expression(ir_unop_exp2, f);
- break;
- }
-
- f = saturate(p, f);
+ struct prog_instruction instBuffer[MAX_INSTRUCTIONS];
+ struct texenv_fragment_program p;
+ GLuint unit;
+ struct ureg cf, out;
+ int i;
- temp = new(p->mem_ctx) ir_dereference_variable(f_var);
- assign = new(p->mem_ctx) ir_assignment(temp, f, NULL);
- p->instructions->push_tail(assign);
+ memset(&p, 0, sizeof(p));
+ p.state = key;
+ p.program = program;
- f = new(p->mem_ctx) ir_dereference_variable(f_var);
- f = new(p->mem_ctx) ir_expression(ir_binop_sub,
- new(p->mem_ctx) ir_constant(1.0f),
- f);
- temp = new(p->mem_ctx) ir_dereference_variable(params);
- temp = new(p->mem_ctx) ir_dereference_record(temp, "color");
- temp = new(p->mem_ctx) ir_swizzle(temp, 0, 1, 2, 3, 3);
- temp = new(p->mem_ctx) ir_expression(ir_binop_mul, temp, f);
+ /* During code generation, use locally-allocated instruction buffer,
+ * then alloc dynamic storage below.
+ */
+ p.program->Base.Instructions = instBuffer;
+ p.program->Base.Target = GL_FRAGMENT_PROGRAM_ARB;
+ p.program->Base.String = NULL;
+ p.program->Base.NumTexIndirections = 1; /* is this right? */
+ p.program->Base.NumTexInstructions = 0;
+ p.program->Base.NumAluInstructions = 0;
+ p.program->Base.NumInstructions = 0;
+ p.program->Base.NumTemporaries = 0;
+ p.program->Base.NumParameters = 0;
+ p.program->Base.NumAttributes = 0;
+ p.program->Base.NumAddressRegs = 0;
+ p.program->Base.Parameters = _mesa_new_parameter_list();
+ p.program->Base.InputsRead = 0x0;
+
+ if (key->num_draw_buffers == 1)
+ p.program->Base.OutputsWritten = 1 << FRAG_RESULT_COLOR;
+ else {
+ for (i = 0; i < key->num_draw_buffers; i++)
+ p.program->Base.OutputsWritten |= (1 << (FRAG_RESULT_DATA0 + i));
+ }
- f = new(p->mem_ctx) ir_dereference_variable(f_var);
- f = new(p->mem_ctx) ir_expression(ir_binop_mul, fragcolor, f);
- f = new(p->mem_ctx) ir_expression(ir_binop_add, temp, f);
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+ p.src_texture[unit] = undef;
+ p.texcoord_tex[unit] = undef;
+ }
- ir_dereference *deref = new(p->mem_ctx) ir_dereference_variable(fog_result);
- assign = new(p->mem_ctx) ir_assignment(deref, f, NULL, WRITEMASK_XYZ);
- p->instructions->push_tail(assign);
+ p.src_previous = undef;
+ p.half = undef;
+ p.zero = undef;
+ p.one = undef;
- return new(p->mem_ctx) ir_dereference_variable(fog_result);
-}
+ p.last_tex_stage = 0;
+ release_temps(ctx, &p);
-static void
-emit_instructions(struct texenv_fragment_program *p)
-{
- struct state_key *key = p->state;
- GLuint unit;
+ if (key->enabled_units && key->num_draw_buffers) {
+ GLboolean needbumpstage = GL_FALSE;
- if (key->enabled_units) {
/* Zeroth pass - bump map textures first */
- for (unit = 0; unit < key->nr_enabled_units; unit++) {
+ for (unit = 0; unit < key->nr_enabled_units; unit++)
if (key->unit[unit].enabled &&
key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) {
- load_texunit_bumpmap(p, unit);
+ needbumpstage = GL_TRUE;
+ load_texunit_bumpmap( &p, unit );
}
- }
+ if (needbumpstage)
+ p.program->Base.NumTexIndirections++;
/* First pass - to support texture_env_crossbar, first identify
* all referenced texture sources and emit texld instructions
@@ -1319,157 +1488,104 @@ emit_instructions(struct texenv_fragment_program *p) */
for (unit = 0; unit < key->nr_enabled_units; unit++)
if (key->unit[unit].enabled) {
- load_texunit_sources(p, unit);
- p->last_tex_stage = unit;
+ load_texunit_sources( &p, unit );
+ p.last_tex_stage = unit;
}
/* Second pass - emit combine instructions to build final color:
*/
- for (unit = 0; unit < key->nr_enabled_units; unit++) {
+ for (unit = 0; unit < key->nr_enabled_units; unit++)
if (key->unit[unit].enabled) {
- p->src_previous = emit_texenv(p, unit);
+ p.src_previous = emit_texenv( &p, unit );
+ reserve_temp(&p, p.src_previous); /* don't re-use this temp reg */
+ release_temps(ctx, &p); /* release all temps */
}
- }
}
- ir_rvalue *cf = get_source(p, SRC_PREVIOUS, 0);
- ir_dereference_variable *deref;
- ir_assignment *assign;
-
- if (key->separate_specular) {
- ir_rvalue *tmp0, *tmp1;
- ir_variable *spec_result = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
- "specular_add",
- ir_var_temporary);
-
- p->instructions->push_tail(spec_result);
-
- deref = new(p->mem_ctx) ir_dereference_variable(spec_result);
- assign = new(p->mem_ctx) ir_assignment(deref, cf, NULL);
- p->instructions->push_tail(assign);
-
- deref = new(p->mem_ctx) ir_dereference_variable(spec_result);
- tmp0 = new(p->mem_ctx) ir_swizzle(deref, 0, 1, 2, 3, 3);
+ cf = get_source( &p, SRC_PREVIOUS, 0 );
- ir_variable *secondary =
- p->shader->symbols->get_variable("gl_SecondaryColor");
- assert(secondary);
- deref = new(p->mem_ctx) ir_dereference_variable(secondary);
- tmp1 = new(p->mem_ctx) ir_swizzle(deref, 0, 1, 2, 3, 3);
-
- tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add,
- tmp0, tmp1);
-
- deref = new(p->mem_ctx) ir_dereference_variable(spec_result);
- assign = new(p->mem_ctx) ir_assignment(deref, tmp0, NULL, WRITEMASK_XYZ);
- p->instructions->push_tail(assign);
+ for (i = 0; i < key->num_draw_buffers; i++) {
+ if (key->num_draw_buffers == 1)
+ out = make_ureg( PROGRAM_OUTPUT, FRAG_RESULT_COLOR );
+ else {
+ out = make_ureg( PROGRAM_OUTPUT, FRAG_RESULT_DATA0 + i );
+ }
- cf = new(p->mem_ctx) ir_dereference_variable(spec_result);
+ if (key->separate_specular) {
+ /* Emit specular add.
+ */
+ struct ureg s = register_input(&p, FRAG_ATTRIB_COL1);
+ emit_arith( &p, OPCODE_ADD, out, WRITEMASK_XYZ, 0, cf, s, undef );
+ emit_arith( &p, OPCODE_MOV, out, WRITEMASK_W, 0, cf, undef, undef );
+ }
+ else if (memcmp(&cf, &out, sizeof(cf)) != 0) {
+ /* Will wind up in here if no texture enabled or a couple of
+ * other scenarios (GL_REPLACE for instance).
+ */
+ emit_arith( &p, OPCODE_MOV, out, WRITEMASK_XYZW, 0, cf, undef, undef );
+ }
}
+ /* Finish up:
+ */
+ emit_arith( &p, OPCODE_END, undef, WRITEMASK_XYZW, 0, undef, undef, undef);
if (key->fog_enabled) {
- cf = emit_fog_instructions(p, cf);
+ /* Pull fog mode from struct gl_context, the value in the state key is
+ * a reduced value and not what is expected in FogOption
+ */
+ p.program->FogOption = ctx->Fog.Mode;
+ p.program->Base.InputsRead |= FRAG_BIT_FOGC;
}
-
- ir_variable *frag_color = p->shader->symbols->get_variable("gl_FragColor");
- assert(frag_color);
- deref = new(p->mem_ctx) ir_dereference_variable(frag_color);
- assign = new(p->mem_ctx) ir_assignment(deref, cf, NULL);
- p->instructions->push_tail(assign);
-}
-
-/**
- * Generate a new fragment program which implements the context's
- * current texture env/combine mode.
- */
-static struct gl_shader_program *
-create_new_program(struct gl_context *ctx, struct state_key *key)
-{
- struct texenv_fragment_program p;
- unsigned int unit;
- _mesa_glsl_parse_state *state;
-
- memset(&p, 0, sizeof(p));
- p.mem_ctx = ralloc_context(NULL);
- p.shader = ctx->Driver.NewShader(ctx, 0, GL_FRAGMENT_SHADER);
- p.shader->ir = new(p.shader) exec_list;
- state = new(p.shader) _mesa_glsl_parse_state(ctx, GL_FRAGMENT_SHADER,
- p.shader);
- p.shader->symbols = state->symbols;
- p.top_instructions = p.shader->ir;
- p.instructions = p.shader->ir;
- p.state = key;
- p.shader_program = ctx->Driver.NewShaderProgram(ctx, 0);
-
- state->language_version = 120;
- _mesa_glsl_initialize_types(state);
- _mesa_glsl_initialize_variables(p.instructions, state);
-
- for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
- p.src_texture[unit] = NULL;
- p.texcoord_tex[unit] = NULL;
+ else {
+ p.program->FogOption = GL_NONE;
}
- p.src_previous = NULL;
+ if (p.program->Base.NumTexIndirections > ctx->Const.FragmentProgram.MaxTexIndirections)
+ program_error(&p, "Exceeded max nr indirect texture lookups");
- p.last_tex_stage = 0;
+ if (p.program->Base.NumTexInstructions > ctx->Const.FragmentProgram.MaxTexInstructions)
+ program_error(&p, "Exceeded max TEX instructions");
- ir_function *main_f = new(p.mem_ctx) ir_function("main");
- p.instructions->push_tail(main_f);
- state->symbols->add_function(main_f);
+ if (p.program->Base.NumAluInstructions > ctx->Const.FragmentProgram.MaxAluInstructions)
+ program_error(&p, "Exceeded max ALU instructions");
- ir_function_signature *main_sig =
- new(p.mem_ctx) ir_function_signature(p.shader->symbols->get_type("void"));
- main_sig->is_defined = true;
- main_f->add_signature(main_sig);
+ ASSERT(p.program->Base.NumInstructions <= MAX_INSTRUCTIONS);
- p.instructions = &main_sig->body;
- if (key->num_draw_buffers)
- emit_instructions(&p);
-
- validate_ir_tree(p.shader->ir);
-
- while (do_common_optimization(p.shader->ir, false, 32))
- ;
- reparent_ir(p.shader->ir, p.shader->ir);
+ /* Allocate final instruction array */
+ p.program->Base.Instructions
+ = _mesa_alloc_instructions(p.program->Base.NumInstructions);
+ if (!p.program->Base.Instructions) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "generating tex env program");
+ return;
+ }
+ _mesa_copy_instructions(p.program->Base.Instructions, instBuffer,
+ p.program->Base.NumInstructions);
- p.shader->CompileStatus = true;
- p.shader->Version = state->language_version;
- p.shader->num_builtins_to_link = state->num_builtins_to_link;
- p.shader_program->Shaders =
- (gl_shader **)malloc(sizeof(*p.shader_program->Shaders));
- p.shader_program->Shaders[0] = p.shader;
- p.shader_program->NumShaders = 1;
+ if (key->num_draw_buffers && p.program->FogOption) {
+ _mesa_append_fog_code(ctx, p.program);
+ p.program->FogOption = GL_NONE;
+ }
- _mesa_glsl_link_shader(ctx, p.shader_program);
- /* Set the sampler uniforms, and relink to get them into the linked
- * program.
+ /* Notify driver the fragment program has (actually) changed.
*/
- struct gl_fragment_program *fp = p.shader_program->FragmentProgram;
- for (unsigned int i = 0; i < MAX_TEXTURE_UNITS; i++) {
- char *name = ralloc_asprintf(p.mem_ctx, "sampler_%d", i);
- int loc = _mesa_get_uniform_location(ctx, p.shader_program, name);
- if (loc != -1) {
- /* Avoid using _mesa_uniform() because it flags state
- * updates, so if we're generating this shader_program in a
- * state update, we end up recursing. Instead, just set the
- * value, which is picked up at re-link.
- */
- loc = (loc & 0xffff) + (loc >> 16);
- int sampler = fp->Base.Parameters->ParameterValues[loc][0];
- fp->Base.SamplerUnits[sampler] = i;
- }
+ if (ctx->Driver.ProgramStringNotify) {
+ GLboolean ok = ctx->Driver.ProgramStringNotify(ctx,
+ GL_FRAGMENT_PROGRAM_ARB,
+ &p.program->Base);
+ /* Driver should be able to handle any texenv programs as long as
+ * the driver correctly reported max number of texture units correctly,
+ * etc.
+ */
+ ASSERT(ok);
+ (void) ok; /* silence unused var warning */
}
- _mesa_update_shader_textures_used(&fp->Base);
- (void) ctx->Driver.ProgramStringNotify(ctx, fp->Base.Target, &fp->Base);
- if (!p.shader_program->LinkStatus)
- _mesa_problem(ctx, "Failed to link fixed function fragment shader: %s\n",
- p.shader_program->InfoLog);
-
- ralloc_free(p.mem_ctx);
- return p.shader_program;
+ if (DISASSEM) {
+ _mesa_print_program(&p.program->Base);
+ printf("\n");
+ }
}
extern "C" {
@@ -1478,27 +1594,30 @@ extern "C" { * Return a fragment program which implements the current
* fixed-function texture, fog and color-sum operations.
*/
-struct gl_shader_program *
+struct gl_fragment_program *
_mesa_get_fixed_func_fragment_program(struct gl_context *ctx)
{
- struct gl_shader_program *shader_program;
+ struct gl_fragment_program *prog;
struct state_key key;
GLuint keySize;
-
+
keySize = make_state_key(ctx, &key);
-
- shader_program = (struct gl_shader_program *)
+
+ prog = (struct gl_fragment_program *)
_mesa_search_program_cache(ctx->FragmentProgram.Cache,
&key, keySize);
- if (!shader_program) {
- shader_program = create_new_program(ctx, &key);
+ if (!prog) {
+ prog = (struct gl_fragment_program *)
+ ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
+
+ create_new_program(ctx, &key, prog);
- _mesa_shader_cache_insert(ctx, ctx->FragmentProgram.Cache,
- &key, keySize, shader_program);
+ _mesa_program_cache_insert(ctx, ctx->FragmentProgram.Cache,
+ &key, keySize, &prog->Base);
}
- return shader_program;
+ return prog;
}
}
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index 520d96689..39b6f72cc 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -2191,7 +2191,6 @@ struct gl_shader_state struct gl_shader_program *CurrentVertexProgram;
struct gl_shader_program *CurrentGeometryProgram;
struct gl_shader_program *CurrentFragmentProgram;
- struct gl_shader_program *_CurrentFragmentProgram;
/**
* Program used by glUniform calls.
diff --git a/mesalib/src/mesa/main/state.c b/mesalib/src/mesa/main/state.c index 5651e3263..f50f2af1e 100644 --- a/mesalib/src/mesa/main/state.c +++ b/mesalib/src/mesa/main/state.c @@ -43,7 +43,6 @@ #include "pixel.h"
#include "program/program.h"
#include "program/prog_parameter.h"
-#include "shaderobj.h"
#include "state.h"
#include "stencil.h"
#include "texenvprogram.h"
@@ -250,7 +249,7 @@ update_program(struct gl_context *ctx) {
const struct gl_shader_program *vsProg = ctx->Shader.CurrentVertexProgram;
const struct gl_shader_program *gsProg = ctx->Shader.CurrentGeometryProgram;
- struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram;
+ const struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram;
const struct gl_vertex_program *prevVP = ctx->VertexProgram._Current;
const struct gl_fragment_program *prevFP = ctx->FragmentProgram._Current;
const struct gl_geometry_program *prevGP = ctx->GeometryProgram._Current;
@@ -276,31 +275,23 @@ update_program(struct gl_context *ctx) /* Use shader programs */
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
fsProg->FragmentProgram);
- _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
- fsProg);
}
else if (ctx->FragmentProgram._Enabled) {
- /* use user-defined fragment program */
+ /* use user-defined vertex program */
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
ctx->FragmentProgram.Current);
- _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
- NULL);
}
else if (ctx->FragmentProgram._MaintainTexEnvProgram) {
/* Use fragment program generated from fixed-function state.
*/
- struct gl_shader_program *f = _mesa_get_fixed_func_fragment_program(ctx);
- _mesa_reference_shader_program(ctx,
- &ctx->Shader._CurrentFragmentProgram, f);
-
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
- f->FragmentProgram);
+ _mesa_get_fixed_func_fragment_program(ctx));
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram,
+ ctx->FragmentProgram._Current);
}
else {
/* no fragment program */
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
- _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
- NULL);
}
if (gsProg && gsProg->LinkStatus && gsProg->GeometryProgram) {
diff --git a/mesalib/src/mesa/main/texenvprogram.h b/mesalib/src/mesa/main/texenvprogram.h index dba775feb..0895ebacb 100644 --- a/mesalib/src/mesa/main/texenvprogram.h +++ b/mesalib/src/mesa/main/texenvprogram.h @@ -29,7 +29,7 @@ struct gl_context;
-extern struct gl_shader_program *
+extern struct gl_fragment_program *
_mesa_get_fixed_func_fragment_program(struct gl_context *ctx);
#endif
diff --git a/mesalib/src/mesa/program/program.c b/mesalib/src/mesa/program/program.c index 43f894a9b..6c97787e8 100644 --- a/mesalib/src/mesa/program/program.c +++ b/mesalib/src/mesa/program/program.c @@ -140,7 +140,7 @@ _mesa_free_program_data(struct gl_context *ctx) #endif
#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
- _mesa_delete_shader_cache(ctx, ctx->FragmentProgram.Cache);
+ _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache);
#endif
#if FEATURE_ARB_geometry_shader4
_mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL);
diff --git a/mesalib/src/mesa/state_tracker/st_cb_clear.c b/mesalib/src/mesa/state_tracker/st_cb_clear.c index 79e58182f..0130c7a5a 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_clear.c +++ b/mesalib/src/mesa/state_tracker/st_cb_clear.c @@ -63,26 +63,12 @@ void
st_init_clear(struct st_context *st)
{
- struct pipe_context *pipe = st->pipe;
struct pipe_screen *pscreen = st->pipe->screen;
memset(&st->clear, 0, sizeof(st->clear));
st->clear.raster.gl_rasterization_rules = 1;
st->clear.enable_ds_separate = pscreen->get_param(pscreen, PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE);
-
- /* fragment shader state: color pass-through program */
- st->clear.fs = util_make_fragment_passthrough_shader(pipe);
-
- /* vertex shader state: color/position pass-through */
- {
- const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
- TGSI_SEMANTIC_COLOR };
- const uint semantic_indexes[] = { 0, 0 };
- st->clear.vs = util_make_vertex_passthrough_shader(pipe, 2,
- semantic_names,
- semantic_indexes);
- }
}
@@ -108,6 +94,42 @@ st_destroy_clear(struct st_context *st) /**
+ * Helper function to set the fragment shaders.
+ */
+static INLINE void
+set_fragment_shader(struct st_context *st)
+{
+ if (!st->clear.fs)
+ st->clear.fs = util_make_fragment_passthrough_shader(st->pipe);
+
+ cso_set_fragment_shader_handle(st->cso_context, st->clear.fs);
+}
+
+
+/**
+ * Helper function to set the vertex shader.
+ */
+static INLINE void
+set_vertex_shader(struct st_context *st)
+{
+ /* vertex shader - still required to provide the linkage between
+ * fragment shader input semantics and vertex_element/buffers.
+ */
+ if (!st->clear.vs)
+ {
+ const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
+ TGSI_SEMANTIC_COLOR };
+ const uint semantic_indexes[] = { 0, 0 };
+ st->clear.vs = util_make_vertex_passthrough_shader(st->pipe, 2,
+ semantic_names,
+ semantic_indexes);
+ }
+
+ cso_set_vertex_shader_handle(st->cso_context, st->clear.vs);
+}
+
+
+/**
* Draw a screen-aligned quadrilateral.
* Coords are clip coords with y=0=bottom.
*/
@@ -297,8 +319,8 @@ clear_with_quad(struct gl_context *ctx, }
cso_set_clip(st->cso_context, &st->clear.clip);
- cso_set_fragment_shader_handle(st->cso_context, st->clear.fs);
- cso_set_vertex_shader_handle(st->cso_context, st->clear.vs);
+ set_fragment_shader(st);
+ set_vertex_shader(st);
if (ctx->DrawBuffer->_ColorDrawBuffers[0]) {
st_translate_color(ctx->Color.ClearColor,
diff --git a/mesalib/src/mesa/state_tracker/st_cb_texture.c b/mesalib/src/mesa/state_tracker/st_cb_texture.c index 8bdb3c801..1b824c0de 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_texture.c +++ b/mesalib/src/mesa/state_tracker/st_cb_texture.c @@ -1530,7 +1530,7 @@ st_copy_texsubimage(struct gl_context *ctx, GLint srcY0, srcY1;
struct pipe_surface surf_tmpl;
memset(&surf_tmpl, 0, sizeof(surf_tmpl));
- surf_tmpl.format = stImage->pt->format;
+ surf_tmpl.format = util_format_linear(stImage->pt->format);
surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
surf_tmpl.u.tex.level = stImage->level;
surf_tmpl.u.tex.first_layer = stImage->face + destZ;
diff --git a/pixman/pixman/pixman-arm-common.h b/pixman/pixman/pixman-arm-common.h index 7420d9305..2c435041a 100644 --- a/pixman/pixman/pixman-arm-common.h +++ b/pixman/pixman/pixman-arm-common.h @@ -361,4 +361,49 @@ FAST_NEAREST_MAINLOOP_COMMON (cputype##_##name##_pad_##op, \ SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE (op,s,d,func), \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD (op,s,d,func)
+/*****************************************************************************/
+
+#define PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST(flags, cputype, name, op, \
+ src_type, dst_type) \
+void \
+pixman_scaled_bilinear_scanline_##name##_##op##_asm_##cputype ( \
+ dst_type * dst, \
+ const src_type * top, \
+ const src_type * bottom, \
+ int wt, \
+ int wb, \
+ pixman_fixed_t x, \
+ pixman_fixed_t ux, \
+ int width); \
+ \
+static force_inline void \
+scaled_bilinear_scanline_##cputype##_##name##_##op ( \
+ dst_type * dst, \
+ const uint32_t * mask, \
+ const src_type * src_top, \
+ const src_type * src_bottom, \
+ int32_t w, \
+ int wt, \
+ int wb, \
+ pixman_fixed_t vx, \
+ pixman_fixed_t unit_x, \
+ pixman_fixed_t max_vx, \
+ pixman_bool_t zero_src) \
+{ \
+ if ((flags & SKIP_ZERO_SRC) && zero_src) \
+ return; \
+ pixman_scaled_bilinear_scanline_##name##_##op##_asm_##cputype ( \
+ dst, src_top, src_bottom, wt, wb, vx, unit_x, w); \
+} \
+ \
+FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_cover_##op, \
+ scaled_bilinear_scanline_##cputype##_##name##_##op, \
+ src_type, uint32_t, dst_type, COVER, FALSE, FALSE) \
+FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_none_##op, \
+ scaled_bilinear_scanline_##cputype##_##name##_##op, \
+ src_type, uint32_t, dst_type, NONE, FALSE, FALSE) \
+FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_pad_##op, \
+ scaled_bilinear_scanline_##cputype##_##name##_##op, \
+ src_type, uint32_t, dst_type, PAD, FALSE, FALSE)
+
#endif
diff --git a/pixman/pixman/pixman-arm-neon-asm.S b/pixman/pixman/pixman-arm-neon-asm.S index 5804396a4..6cca0f2cc 100644 --- a/pixman/pixman/pixman-arm-neon-asm.S +++ b/pixman/pixman/pixman-arm-neon-asm.S @@ -2405,17 +2405,161 @@ generate_composite_function_nearest_scanline \ fname:
.endm
-.macro bilinear_interpolate_last_pixel
- mov TMP1, X, asr #16
+/*
+ * Bilinear scaling support code which tries to provide pixel fetching, color
+ * format conversion, and interpolation as separate macros which can be used
+ * as the basic building blocks for constructing bilinear scanline functions.
+ */
+
+.macro bilinear_load_8888 reg1, reg2, tmp
mov TMP2, X, asr #16
- add TMP1, TOP, TMP1, asl #2
+ add X, X, UX
+ add TMP1, TOP, TMP2, asl #2
add TMP2, BOTTOM, TMP2, asl #2
- vld1.32 {d0}, [TMP1]
- vshr.u16 d30, d24, #8
- vld1.32 {d1}, [TMP2]
+ vld1.32 {reg1}, [TMP1]
+ vld1.32 {reg2}, [TMP2]
+.endm
+
+.macro bilinear_load_0565 reg1, reg2, tmp
+ mov TMP2, X, asr #16
+ add X, X, UX
+ add TMP1, TOP, TMP2, asl #1
+ add TMP2, BOTTOM, TMP2, asl #1
+ vld1.32 {reg2[0]}, [TMP1]
+ vld1.32 {reg2[1]}, [TMP2]
+ convert_four_0565_to_x888_packed reg2, reg1, reg2, tmp
+.endm
+
+.macro bilinear_load_and_vertical_interpolate_two_8888 \
+ acc1, acc2, reg1, reg2, reg3, reg4, tmp1, tmp2
+
+ bilinear_load_8888 reg1, reg2, tmp1
+ vmull.u8 acc1, reg1, d28
+ vmlal.u8 acc1, reg2, d29
+ bilinear_load_8888 reg3, reg4, tmp2
+ vmull.u8 acc2, reg3, d28
+ vmlal.u8 acc2, reg4, d29
+.endm
+
+.macro bilinear_load_and_vertical_interpolate_four_8888 \
+ xacc1, xacc2, xreg1, xreg2, xreg3, xreg4, xacc2lo, xacc2hi \
+ yacc1, yacc2, yreg1, yreg2, yreg3, yreg4, yacc2lo, yacc2hi
+
+ bilinear_load_and_vertical_interpolate_two_8888 \
+ xacc1, xacc2, xreg1, xreg2, xreg3, xreg4, xacc2lo, xacc2hi
+ bilinear_load_and_vertical_interpolate_two_8888 \
+ yacc1, yacc2, yreg1, yreg2, yreg3, yreg4, yacc2lo, yacc2hi
+.endm
+
+.macro bilinear_load_and_vertical_interpolate_two_0565 \
+ acc1, acc2, reg1, reg2, reg3, reg4, acc2lo, acc2hi
+
+ mov TMP2, X, asr #16
+ add X, X, UX
+ mov TMP4, X, asr #16
+ add X, X, UX
+ add TMP1, TOP, TMP2, asl #1
+ add TMP2, BOTTOM, TMP2, asl #1
+ add TMP3, TOP, TMP4, asl #1
+ add TMP4, BOTTOM, TMP4, asl #1
+ vld1.32 {acc2lo[0]}, [TMP1]
+ vld1.32 {acc2hi[0]}, [TMP3]
+ vld1.32 {acc2lo[1]}, [TMP2]
+ vld1.32 {acc2hi[1]}, [TMP4]
+ convert_0565_to_x888 acc2, reg3, reg2, reg1
+ vzip.u8 reg1, reg3
+ vzip.u8 reg2, reg4
+ vzip.u8 reg3, reg4
+ vzip.u8 reg1, reg2
+ vmull.u8 acc1, reg1, d28
+ vmlal.u8 acc1, reg2, d29
+ vmull.u8 acc2, reg3, d28
+ vmlal.u8 acc2, reg4, d29
+.endm
+
+.macro bilinear_load_and_vertical_interpolate_four_0565 \
+ xacc1, xacc2, xreg1, xreg2, xreg3, xreg4, xacc2lo, xacc2hi \
+ yacc1, yacc2, yreg1, yreg2, yreg3, yreg4, yacc2lo, yacc2hi
+
+ mov TMP2, X, asr #16
+ add X, X, UX
+ mov TMP4, X, asr #16
+ add X, X, UX
+ add TMP1, TOP, TMP2, asl #1
+ add TMP2, BOTTOM, TMP2, asl #1
+ add TMP3, TOP, TMP4, asl #1
+ add TMP4, BOTTOM, TMP4, asl #1
+ vld1.32 {xacc2lo[0]}, [TMP1]
+ vld1.32 {xacc2hi[0]}, [TMP3]
+ vld1.32 {xacc2lo[1]}, [TMP2]
+ vld1.32 {xacc2hi[1]}, [TMP4]
+ convert_0565_to_x888 xacc2, xreg3, xreg2, xreg1
+ mov TMP2, X, asr #16
+ add X, X, UX
+ mov TMP4, X, asr #16
+ add X, X, UX
+ add TMP1, TOP, TMP2, asl #1
+ add TMP2, BOTTOM, TMP2, asl #1
+ add TMP3, TOP, TMP4, asl #1
+ add TMP4, BOTTOM, TMP4, asl #1
+ vld1.32 {yacc2lo[0]}, [TMP1]
+ vzip.u8 xreg1, xreg3
+ vld1.32 {yacc2hi[0]}, [TMP3]
+ vzip.u8 xreg2, xreg4
+ vld1.32 {yacc2lo[1]}, [TMP2]
+ vzip.u8 xreg3, xreg4
+ vld1.32 {yacc2hi[1]}, [TMP4]
+ vzip.u8 xreg1, xreg2
+ convert_0565_to_x888 yacc2, yreg3, yreg2, yreg1
+ vmull.u8 xacc1, xreg1, d28
+ vzip.u8 yreg1, yreg3
+ vmlal.u8 xacc1, xreg2, d29
+ vzip.u8 yreg2, yreg4
+ vmull.u8 xacc2, xreg3, d28
+ vzip.u8 yreg3, yreg4
+ vmlal.u8 xacc2, xreg4, d29
+ vzip.u8 yreg1, yreg2
+ vmull.u8 yacc1, yreg1, d28
+ vmlal.u8 yacc1, yreg2, d29
+ vmull.u8 yacc2, yreg3, d28
+ vmlal.u8 yacc2, yreg4, d29
+.endm
+
+.macro bilinear_store_8888 numpix, tmp1, tmp2
+.if numpix == 4
+ vst1.32 {d0, d1}, [OUT]!
+.elseif numpix == 2
+ vst1.32 {d0}, [OUT]!
+.elseif numpix == 1
+ vst1.32 {d0[0]}, [OUT, :32]!
+.else
+ .error bilinear_store_8888 numpix is unsupported
+.endif
+.endm
+
+.macro bilinear_store_0565 numpix, tmp1, tmp2
+ vuzp.u8 d0, d1
+ vuzp.u8 d2, d3
+ vuzp.u8 d1, d3
+ vuzp.u8 d0, d2
+ convert_8888_to_0565 d2, d1, d0, q1, tmp1, tmp2
+.if numpix == 4
+ vst1.16 {d2}, [OUT]!
+.elseif numpix == 2
+ vst1.32 {d2[0]}, [OUT]!
+.elseif numpix == 1
+ vst1.16 {d2[0]}, [OUT]!
+.else
+ .error bilinear_store_0565 numpix is unsupported
+.endif
+.endm
+
+.macro bilinear_interpolate_last_pixel src_fmt, dst_fmt
+ bilinear_load_&src_fmt d0, d1, d2
vmull.u8 q1, d0, d28
vmlal.u8 q1, d1, d29
- /* 5 cycles bubble */
+ vshr.u16 d30, d24, #8
+ /* 4 cycles bubble */
vshll.u16 q0, d2, #8
vmlsl.u16 q0, d2, d30
vmlal.u16 q0, d3, d30
@@ -2424,28 +2568,12 @@ fname: /* 3 cycles bubble */
vmovn.u16 d0, q0
/* 1 cycle bubble */
- vst1.32 {d0[0]}, [OUT, :32]!
+ bilinear_store_&dst_fmt 1, q2, q3
.endm
-.macro bilinear_interpolate_two_pixels
- mov TMP1, X, asr #16
- mov TMP2, X, asr #16
- add X, X, UX
- add TMP1, TOP, TMP1, asl #2
- add TMP2, BOTTOM, TMP2, asl #2
- vld1.32 {d0}, [TMP1]
- vld1.32 {d1}, [TMP2]
- vmull.u8 q1, d0, d28
- vmlal.u8 q1, d1, d29
- mov TMP1, X, asr #16
- mov TMP2, X, asr #16
- add X, X, UX
- add TMP1, TOP, TMP1, asl #2
- add TMP2, BOTTOM, TMP2, asl #2
- vld1.32 {d20}, [TMP1]
- vld1.32 {d21}, [TMP2]
- vmull.u8 q11, d20, d28
- vmlal.u8 q11, d21, d29
+.macro bilinear_interpolate_two_pixels src_fmt, dst_fmt
+ bilinear_load_and_vertical_interpolate_two_&src_fmt \
+ q1, q11, d0, d1, d20, d21, d22, d23
vshr.u16 q15, q12, #8
vadd.u16 q12, q12, q13
vshll.u16 q0, d2, #8
@@ -2457,28 +2585,14 @@ fname: vshrn.u32 d30, q0, #16
vshrn.u32 d31, q10, #16
vmovn.u16 d0, q15
- vst1.32 {d0}, [OUT]!
+ bilinear_store_&dst_fmt 2, q2, q3
.endm
-.macro bilinear_interpolate_four_pixels
- mov TMP1, X, asr #16
- mov TMP2, X, asr #16
- add X, X, UX
- add TMP1, TOP, TMP1, asl #2
- add TMP2, BOTTOM, TMP2, asl #2
- vld1.32 {d0}, [TMP1]
- vld1.32 {d1}, [TMP2]
- vmull.u8 q1, d0, d28
- vmlal.u8 q1, d1, d29
- mov TMP1, X, asr #16
- mov TMP2, X, asr #16
- add X, X, UX
- add TMP1, TOP, TMP1, asl #2
- add TMP2, BOTTOM, TMP2, asl #2
- vld1.32 {d20}, [TMP1]
- vld1.32 {d21}, [TMP2]
- vmull.u8 q11, d20, d28
- vmlal.u8 q11, d21, d29
+.macro bilinear_interpolate_four_pixels src_fmt, dst_fmt
+ bilinear_load_and_vertical_interpolate_four_&src_fmt \
+ q1, q11, d0, d1, d20, d21, d22, d23 \
+ q3, q9, d4, d5, d16, d17, d18, d19
+ pld [TMP1, PF_OFFS]
vshr.u16 q15, q12, #8
vadd.u16 q12, q12, q13
vshll.u16 q0, d2, #8
@@ -2487,54 +2601,44 @@ fname: vshll.u16 q10, d22, #8
vmlsl.u16 q10, d22, d31
vmlal.u16 q10, d23, d31
- mov TMP1, X, asr #16
- mov TMP2, X, asr #16
- add X, X, UX
- add TMP1, TOP, TMP1, asl #2
- add TMP2, BOTTOM, TMP2, asl #2
- vld1.32 {d4}, [TMP1]
- vld1.32 {d5}, [TMP2]
- vmull.u8 q3, d4, d28
- vmlal.u8 q3, d5, d29
- mov TMP1, X, asr #16
- mov TMP2, X, asr #16
- add X, X, UX
- add TMP1, TOP, TMP1, asl #2
- add TMP2, BOTTOM, TMP2, asl #2
- vld1.32 {d16}, [TMP1]
- vld1.32 {d17}, [TMP2]
- vmull.u8 q9, d16, d28
- vmlal.u8 q9, d17, d29
vshr.u16 q15, q12, #8
- vadd.u16 q12, q12, q13
vshll.u16 q2, d6, #8
vmlsl.u16 q2, d6, d30
vmlal.u16 q2, d7, d30
vshll.u16 q8, d18, #8
+ pld [TMP2, PF_OFFS]
vmlsl.u16 q8, d18, d31
vmlal.u16 q8, d19, d31
+ vadd.u16 q12, q12, q13
vshrn.u32 d0, q0, #16
vshrn.u32 d1, q10, #16
vshrn.u32 d4, q2, #16
vshrn.u32 d5, q8, #16
vmovn.u16 d0, q0
vmovn.u16 d1, q2
- vst1.32 {d0, d1}, [OUT]!
+ bilinear_store_&dst_fmt 4, q2, q3
.endm
-
/*
- * pixman_scaled_bilinear_scanline_8888_8888_SRC (uint32_t * out,
- * const uint32_t * top,
- * const uint32_t * bottom,
- * int wt,
- * int wb,
- * pixman_fixed_t x,
- * pixman_fixed_t ux,
- * int width)
+ * Main template macro for generating NEON optimized bilinear scanline
+ * functions.
+ *
+ * TODO: use software pipelining and aligned writes to the destination buffer
+ * in order to improve performance
+ *
+ * Bilinear scanline scaler macro template uses the following arguments:
+ * fname - name of the function to generate
+ * src_fmt - source color format (8888 or 0565)
+ * dst_fmt - destination color format (8888 or 0565)
+ * bpp_shift - (1 << bpp_shift) is the size of source pixel in bytes
+ * prefetch_distance - prefetch in the source image by that many
+ * pixels ahead
*/
-pixman_asm_function pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon
+.macro generate_bilinear_scanline_func fname, src_fmt, dst_fmt, \
+ bpp_shift, prefetch_distance
+
+pixman_asm_function fname
OUT .req r0
TOP .req r1
BOTTOM .req r2
@@ -2545,13 +2649,19 @@ pixman_asm_function pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon WIDTH .req ip
TMP1 .req r3
TMP2 .req r4
+ PF_OFFS .req r7
+ TMP3 .req r8
+ TMP4 .req r9
mov ip, sp
- push {r4, r5, r6, r7}
+ push {r4, r5, r6, r7, r8, r9}
+ mov PF_OFFS, #prefetch_distance
ldmia ip, {WB, X, UX, WIDTH}
+ mul PF_OFFS, PF_OFFS, UX
cmp WIDTH, #0
ble 3f
+
vdup.u16 q12, X
vdup.u16 q13, UX
vdup.u8 d28, WT
@@ -2561,20 +2671,21 @@ pixman_asm_function pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon subs WIDTH, WIDTH, #4
blt 1f
+ mov PF_OFFS, PF_OFFS, asr #(16 - bpp_shift)
0:
- bilinear_interpolate_four_pixels
+ bilinear_interpolate_four_pixels src_fmt, dst_fmt
subs WIDTH, WIDTH, #4
bge 0b
1:
tst WIDTH, #2
beq 2f
- bilinear_interpolate_two_pixels
+ bilinear_interpolate_two_pixels src_fmt, dst_fmt
2:
tst WIDTH, #1
beq 3f
- bilinear_interpolate_last_pixel
+ bilinear_interpolate_last_pixel src_fmt, dst_fmt
3:
- pop {r4, r5, r6, r7}
+ pop {r4, r5, r6, r7, r8, r9}
bx lr
.unreq OUT
@@ -2587,4 +2698,21 @@ pixman_asm_function pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon .unreq WIDTH
.unreq TMP1
.unreq TMP2
+ .unreq PF_OFFS
+ .unreq TMP3
+ .unreq TMP4
.endfunc
+
+.endm
+
+generate_bilinear_scanline_func \
+ pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon, 8888, 8888, 2, 28
+
+generate_bilinear_scanline_func \
+ pixman_scaled_bilinear_scanline_8888_0565_SRC_asm_neon, 8888, 0565, 2, 28
+
+generate_bilinear_scanline_func \
+ pixman_scaled_bilinear_scanline_0565_x888_SRC_asm_neon, 0565, 8888, 1, 28
+
+generate_bilinear_scanline_func \
+ pixman_scaled_bilinear_scanline_0565_0565_SRC_asm_neon, 0565, 0565, 1, 28
diff --git a/pixman/pixman/pixman-arm-neon-asm.h b/pixman/pixman/pixman-arm-neon-asm.h index 6e3d583f5..0ba67d05f 100644 --- a/pixman/pixman/pixman-arm-neon-asm.h +++ b/pixman/pixman/pixman-arm-neon-asm.h @@ -1158,3 +1158,20 @@ fname: vsri.u16 out, tmp1, #5
vsri.u16 out, tmp2, #11
.endm
+
+/*
+ * Conversion of four r5g6b5 pixels (in) to four x8r8g8b8 pixels
+ * returned in (out0, out1) registers pair. Requires one temporary
+ * 64-bit register (tmp). 'out1' and 'in' may overlap, the original
+ * value from 'in' is lost
+ */
+.macro convert_four_0565_to_x888_packed in, out0, out1, tmp
+ vshl.u16 out0, in, #5 /* G top 6 bits */
+ vshl.u16 tmp, in, #11 /* B top 5 bits */
+ vsri.u16 in, in, #5 /* R is ready in top bits */
+ vsri.u16 out0, out0, #6 /* G is ready in top bits */
+ vsri.u16 tmp, tmp, #5 /* B is ready in top bits */
+ vshr.u16 out1, in, #8 /* R is in place */
+ vsri.u16 out0, tmp, #8 /* G & B is in place */
+ vzip.u16 out0, out1 /* everything is in place */
+.endm
diff --git a/pixman/pixman/pixman-arm-neon.c b/pixman/pixman/pixman-arm-neon.c index f86a49c53..5213a2007 100644 --- a/pixman/pixman/pixman-arm-neon.c +++ b/pixman/pixman/pixman-arm-neon.c @@ -127,6 +127,15 @@ PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_A8_DST (SKIP_ZERO_SRC, neon, 8888_8_0565, PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_A8_DST (SKIP_ZERO_SRC, neon, 0565_8_0565,
OVER, uint16_t, uint16_t)
+PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (0, neon, 8888_8888, SRC,
+ uint32_t, uint32_t)
+PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (0, neon, 8888_0565, SRC,
+ uint32_t, uint16_t)
+PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (0, neon, 0565_x888, SRC,
+ uint16_t, uint32_t)
+PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (0, neon, 0565_0565, SRC,
+ uint16_t, uint16_t)
+
void
pixman_composite_src_n_8_asm_neon (int32_t w,
int32_t h,
@@ -232,47 +241,6 @@ pixman_blt_neon (uint32_t *src_bits, }
}
-void
-pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon (uint32_t * out,
- const uint32_t * top,
- const uint32_t * bottom,
- int wt,
- int wb,
- pixman_fixed_t x,
- pixman_fixed_t ux,
- int width);
-
-static force_inline void
-scaled_bilinear_scanline_neon_8888_8888_SRC (uint32_t * dst,
- const uint32_t * mask,
- const uint32_t * src_top,
- const uint32_t * src_bottom,
- int32_t w,
- int wt,
- int wb,
- pixman_fixed_t vx,
- pixman_fixed_t unit_x,
- pixman_fixed_t max_vx,
- pixman_bool_t zero_src)
-{
- pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon (dst, src_top,
- src_bottom, wt, wb,
- vx, unit_x, w);
-}
-
-FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_8888_cover_SRC,
- scaled_bilinear_scanline_neon_8888_8888_SRC,
- uint32_t, uint32_t, uint32_t,
- COVER, FALSE, FALSE)
-FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_8888_pad_SRC,
- scaled_bilinear_scanline_neon_8888_8888_SRC,
- uint32_t, uint32_t, uint32_t,
- PAD, FALSE, FALSE)
-FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_8888_none_SRC,
- scaled_bilinear_scanline_neon_8888_8888_SRC,
- uint32_t, uint32_t, uint32_t,
- NONE, FALSE, FALSE)
-
static const pixman_fast_path_t arm_neon_fast_paths[] =
{
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, r5g6b5, neon_composite_src_0565_0565),
@@ -388,6 +356,12 @@ static const pixman_fast_path_t arm_neon_fast_paths[] = SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, neon_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, neon_8888_8888),
+ SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, r5g6b5, neon_8888_0565),
+ SIMPLE_BILINEAR_FAST_PATH (SRC, x8r8g8b8, r5g6b5, neon_8888_0565),
+
+ SIMPLE_BILINEAR_FAST_PATH (SRC, r5g6b5, x8r8g8b8, neon_0565_x888),
+ SIMPLE_BILINEAR_FAST_PATH (SRC, r5g6b5, r5g6b5, neon_0565_0565),
+
{ PIXMAN_OP_NONE },
};
diff --git a/pixman/pixman/pixman-arm-simd-asm.S b/pixman/pixman/pixman-arm-simd-asm.S index d97545c1b..e00836b6c 100644 --- a/pixman/pixman/pixman-arm-simd-asm.S +++ b/pixman/pixman/pixman-arm-simd-asm.S @@ -331,15 +331,29 @@ pixman_asm_function pixman_composite_over_n_8_8888_asm_armv6 .endfunc
/*
- * Note: This function is only using armv4t instructions (not even armv6),
+ * Note: This code is only using armv5te instructions (not even armv6),
* but is scheduled for ARM Cortex-A8 pipeline. So it might need to
* be split into a few variants, tuned for each microarchitecture.
*
* TODO: In order to get good performance on ARM9/ARM11 cores (which don't
* have efficient write combining), it needs to be changed to use 16-byte
* aligned writes using STM instruction.
+ *
+ * Nearest scanline scaler macro template uses the following arguments:
+ * fname - name of the function to generate
+ * bpp_shift - (1 << bpp_shift) is the size of pixel in bytes
+ * t - type suffix for LDR/STR instructions
+ * prefetch_distance - prefetch in the source image by that many
+ * pixels ahead
+ * prefetch_braking_distance - stop prefetching when that many pixels are
+ * remaining before the end of scanline
*/
-pixman_asm_function pixman_scaled_nearest_scanline_0565_0565_SRC_asm_armv6
+
+.macro generate_nearest_scanline_func fname, bpp_shift, t, \
+ prefetch_distance, \
+ prefetch_braking_distance
+
+pixman_asm_function fname
W .req r0
DST .req r1
SRC .req r2
@@ -348,30 +362,46 @@ pixman_asm_function pixman_scaled_nearest_scanline_0565_0565_SRC_asm_armv6 TMP1 .req r4
TMP2 .req r5
VXMASK .req r6
+ PF_OFFS .req r7
ldr UNIT_X, [sp]
push {r4, r5, r6, r7}
- mvn VXMASK, #1
+ mvn VXMASK, #((1 << bpp_shift) - 1)
/* define helper macro */
.macro scale_2_pixels
- ldrh TMP1, [SRC, TMP1]
- and TMP2, VXMASK, VX, lsr #15
+ ldr&t TMP1, [SRC, TMP1]
+ and TMP2, VXMASK, VX, lsr #(16 - bpp_shift)
add VX, VX, UNIT_X
- strh TMP1, [DST], #2
+ str&t TMP1, [DST], #(1 << bpp_shift)
- ldrh TMP2, [SRC, TMP2]
- and TMP1, VXMASK, VX, lsr #15
+ ldr&t TMP2, [SRC, TMP2]
+ and TMP1, VXMASK, VX, lsr #(16 - bpp_shift)
add VX, VX, UNIT_X
- strh TMP2, [DST], #2
+ str&t TMP2, [DST], #(1 << bpp_shift)
.endm
/* now do the scaling */
- and TMP1, VXMASK, VX, lsr #15
+ and TMP1, VXMASK, VX, lsr #(16 - bpp_shift)
add VX, VX, UNIT_X
- subs W, #4
+ subs W, W, #(8 + prefetch_braking_distance)
blt 2f
-1: /* main loop, process 4 pixels per iteration */
+ /* calculate prefetch offset */
+ mov PF_OFFS, #prefetch_distance
+ mla PF_OFFS, UNIT_X, PF_OFFS, VX
+1: /* main loop, process 8 pixels per iteration with prefetch */
+ subs W, W, #8
+ add PF_OFFS, UNIT_X, lsl #3
+ scale_2_pixels
+ scale_2_pixels
+ scale_2_pixels
+ scale_2_pixels
+ pld [SRC, PF_OFFS, lsr #(16 - bpp_shift)]
+ bge 1b
+2:
+ subs W, W, #(4 - 8 - prefetch_braking_distance)
+ blt 2f
+1: /* process the remaining pixels */
scale_2_pixels
scale_2_pixels
subs W, W, #4
@@ -382,8 +412,8 @@ pixman_asm_function pixman_scaled_nearest_scanline_0565_0565_SRC_asm_armv6 scale_2_pixels
2:
tst W, #1
- ldrneh TMP1, [SRC, TMP1]
- strneh TMP1, [DST], #2
+ ldrne&t TMP1, [SRC, TMP1]
+ strne&t TMP1, [DST]
/* cleanup helper macro */
.purgem scale_2_pixels
.unreq DST
@@ -394,7 +424,15 @@ pixman_asm_function pixman_scaled_nearest_scanline_0565_0565_SRC_asm_armv6 .unreq TMP1
.unreq TMP2
.unreq VXMASK
+ .unreq PF_OFFS
/* return */
pop {r4, r5, r6, r7}
bx lr
.endfunc
+.endm
+
+generate_nearest_scanline_func \
+ pixman_scaled_nearest_scanline_0565_0565_SRC_asm_armv6, 1, h, 80, 32
+
+generate_nearest_scanline_func \
+ pixman_scaled_nearest_scanline_8888_8888_SRC_asm_armv6, 2, , 48, 32
diff --git a/pixman/pixman/pixman-arm-simd.c b/pixman/pixman/pixman-arm-simd.c index 6bbc1094d..45981a6b0 100644 --- a/pixman/pixman/pixman-arm-simd.c +++ b/pixman/pixman/pixman-arm-simd.c @@ -1,423 +1,432 @@ -/* - * Copyright © 2008 Mozilla Corporation - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Mozilla Corporation not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Mozilla Corporation makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * - * Author: Jeff Muizelaar (jeff@infidigm.net) - * - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "pixman-private.h" -#include "pixman-arm-common.h" -#include "pixman-fast-path.h" - -#if 0 /* This code was moved to 'pixman-arm-simd-asm.S' */ - -void -pixman_composite_add_8_8_asm_armv6 (int32_t width, - int32_t height, - uint8_t *dst_line, - int32_t dst_stride, - uint8_t *src_line, - int32_t src_stride) -{ - uint8_t *dst, *src; - int32_t w; - uint8_t s, d; - - while (height--) - { - dst = dst_line; - dst_line += dst_stride; - src = src_line; - src_line += src_stride; - w = width; - - /* ensure both src and dst are properly aligned before doing 32 bit reads - * we'll stay in this loop if src and dst have differing alignments - */ - while (w && (((unsigned long)dst & 3) || ((unsigned long)src & 3))) - { - s = *src; - d = *dst; - asm ("uqadd8 %0, %1, %2" : "+r" (d) : "r" (s)); - *dst = d; - - dst++; - src++; - w--; - } - - while (w >= 4) - { - asm ("uqadd8 %0, %1, %2" - : "=r" (*(uint32_t*)dst) - : "r" (*(uint32_t*)src), "r" (*(uint32_t*)dst)); - dst += 4; - src += 4; - w -= 4; - } - - while (w) - { - s = *src; - d = *dst; - asm ("uqadd8 %0, %1, %2" : "+r" (d) : "r" (s)); - *dst = d; - - dst++; - src++; - w--; - } - } - -} - -void -pixman_composite_over_8888_8888_asm_armv6 (int32_t width, - int32_t height, - uint32_t *dst_line, - int32_t dst_stride, - uint32_t *src_line, - int32_t src_stride) -{ - uint32_t *dst; - uint32_t *src; - int32_t w; - uint32_t component_half = 0x800080; - uint32_t upper_component_mask = 0xff00ff00; - uint32_t alpha_mask = 0xff; - - while (height--) - { - dst = dst_line; - dst_line += dst_stride; - src = src_line; - src_line += src_stride; - w = width; - -/* #define inner_branch */ - asm volatile ( - "cmp %[w], #0\n\t" - "beq 2f\n\t" - "1:\n\t" - /* load src */ - "ldr r5, [%[src]], #4\n\t" -#ifdef inner_branch - /* We can avoid doing the multiplication in two cases: 0x0 or 0xff. - * The 0x0 case also allows us to avoid doing an unecessary data - * write which is more valuable so we only check for that - */ - "cmp r5, #0\n\t" - "beq 3f\n\t" - - /* = 255 - alpha */ - "sub r8, %[alpha_mask], r5, lsr #24\n\t" - - "ldr r4, [%[dest]] \n\t" - -#else - "ldr r4, [%[dest]] \n\t" - - /* = 255 - alpha */ - "sub r8, %[alpha_mask], r5, lsr #24\n\t" -#endif - "uxtb16 r6, r4\n\t" - "uxtb16 r7, r4, ror #8\n\t" - - /* multiply by 257 and divide by 65536 */ - "mla r6, r6, r8, %[component_half]\n\t" - "mla r7, r7, r8, %[component_half]\n\t" - - "uxtab16 r6, r6, r6, ror #8\n\t" - "uxtab16 r7, r7, r7, ror #8\n\t" - - /* recombine the 0xff00ff00 bytes of r6 and r7 */ - "and r7, r7, %[upper_component_mask]\n\t" - "uxtab16 r6, r7, r6, ror #8\n\t" - - "uqadd8 r5, r6, r5\n\t" - -#ifdef inner_branch - "3:\n\t" - -#endif - "str r5, [%[dest]], #4\n\t" - /* increment counter and jmp to top */ - "subs %[w], %[w], #1\n\t" - "bne 1b\n\t" - "2:\n\t" - : [w] "+r" (w), [dest] "+r" (dst), [src] "+r" (src) - : [component_half] "r" (component_half), [upper_component_mask] "r" (upper_component_mask), - [alpha_mask] "r" (alpha_mask) - : "r4", "r5", "r6", "r7", "r8", "cc", "memory" - ); - } -} - -void -pixman_composite_over_8888_n_8888_asm_armv6 (int32_t width, - int32_t height, - uint32_t *dst_line, - int32_t dst_stride, - uint32_t *src_line, - int32_t src_stride, - uint32_t mask) -{ - uint32_t *dst; - uint32_t *src; - int32_t w; - uint32_t component_half = 0x800080; - uint32_t alpha_mask = 0xff; - - mask = (mask) >> 24; - - while (height--) - { - dst = dst_line; - dst_line += dst_stride; - src = src_line; - src_line += src_stride; - w = width; - -/* #define inner_branch */ - asm volatile ( - "cmp %[w], #0\n\t" - "beq 2f\n\t" - "1:\n\t" - /* load src */ - "ldr r5, [%[src]], #4\n\t" -#ifdef inner_branch - /* We can avoid doing the multiplication in two cases: 0x0 or 0xff. - * The 0x0 case also allows us to avoid doing an unecessary data - * write which is more valuable so we only check for that - */ - "cmp r5, #0\n\t" - "beq 3f\n\t" - -#endif - "ldr r4, [%[dest]] \n\t" - - "uxtb16 r6, r5\n\t" - "uxtb16 r7, r5, ror #8\n\t" - - /* multiply by alpha (r8) then by 257 and divide by 65536 */ - "mla r6, r6, %[mask_alpha], %[component_half]\n\t" - "mla r7, r7, %[mask_alpha], %[component_half]\n\t" - - "uxtab16 r6, r6, r6, ror #8\n\t" - "uxtab16 r7, r7, r7, ror #8\n\t" - - "uxtb16 r6, r6, ror #8\n\t" - "uxtb16 r7, r7, ror #8\n\t" - - /* recombine */ - "orr r5, r6, r7, lsl #8\n\t" - - "uxtb16 r6, r4\n\t" - "uxtb16 r7, r4, ror #8\n\t" - - /* 255 - alpha */ - "sub r8, %[alpha_mask], r5, lsr #24\n\t" - - /* multiply by alpha (r8) then by 257 and divide by 65536 */ - "mla r6, r6, r8, %[component_half]\n\t" - "mla r7, r7, r8, %[component_half]\n\t" - - "uxtab16 r6, r6, r6, ror #8\n\t" - "uxtab16 r7, r7, r7, ror #8\n\t" - - "uxtb16 r6, r6, ror #8\n\t" - "uxtb16 r7, r7, ror #8\n\t" - - /* recombine */ - "orr r6, r6, r7, lsl #8\n\t" - - "uqadd8 r5, r6, r5\n\t" - -#ifdef inner_branch - "3:\n\t" - -#endif - "str r5, [%[dest]], #4\n\t" - /* increment counter and jmp to top */ - "subs %[w], %[w], #1\n\t" - "bne 1b\n\t" - "2:\n\t" - : [w] "+r" (w), [dest] "+r" (dst), [src] "+r" (src) - : [component_half] "r" (component_half), [mask_alpha] "r" (mask), - [alpha_mask] "r" (alpha_mask) - : "r4", "r5", "r6", "r7", "r8", "r9", "cc", "memory" - ); - } -} - -void -pixman_composite_over_n_8_8888_asm_armv6 (int32_t width, - int32_t height, - uint32_t *dst_line, - int32_t dst_stride, - uint32_t src, - int32_t unused, - uint8_t *mask_line, - int32_t mask_stride) -{ - uint32_t srca; - uint32_t *dst; - uint8_t *mask; - int32_t w; - - srca = src >> 24; - - uint32_t component_mask = 0xff00ff; - uint32_t component_half = 0x800080; - - uint32_t src_hi = (src >> 8) & component_mask; - uint32_t src_lo = src & component_mask; - - while (height--) - { - dst = dst_line; - dst_line += dst_stride; - mask = mask_line; - mask_line += mask_stride; - w = width; - -/* #define inner_branch */ - asm volatile ( - "cmp %[w], #0\n\t" - "beq 2f\n\t" - "1:\n\t" - /* load mask */ - "ldrb r5, [%[mask]], #1\n\t" -#ifdef inner_branch - /* We can avoid doing the multiplication in two cases: 0x0 or 0xff. - * The 0x0 case also allows us to avoid doing an unecessary data - * write which is more valuable so we only check for that - */ - "cmp r5, #0\n\t" - "beq 3f\n\t" - -#endif - "ldr r4, [%[dest]] \n\t" - - /* multiply by alpha (r8) then by 257 and divide by 65536 */ - "mla r6, %[src_lo], r5, %[component_half]\n\t" - "mla r7, %[src_hi], r5, %[component_half]\n\t" - - "uxtab16 r6, r6, r6, ror #8\n\t" - "uxtab16 r7, r7, r7, ror #8\n\t" - - "uxtb16 r6, r6, ror #8\n\t" - "uxtb16 r7, r7, ror #8\n\t" - - /* recombine */ - "orr r5, r6, r7, lsl #8\n\t" - - "uxtb16 r6, r4\n\t" - "uxtb16 r7, r4, ror #8\n\t" - - /* we could simplify this to use 'sub' if we were - * willing to give up a register for alpha_mask - */ - "mvn r8, r5\n\t" - "mov r8, r8, lsr #24\n\t" - - /* multiply by alpha (r8) then by 257 and divide by 65536 */ - "mla r6, r6, r8, %[component_half]\n\t" - "mla r7, r7, r8, %[component_half]\n\t" - - "uxtab16 r6, r6, r6, ror #8\n\t" - "uxtab16 r7, r7, r7, ror #8\n\t" - - "uxtb16 r6, r6, ror #8\n\t" - "uxtb16 r7, r7, ror #8\n\t" - - /* recombine */ - "orr r6, r6, r7, lsl #8\n\t" - - "uqadd8 r5, r6, r5\n\t" - -#ifdef inner_branch - "3:\n\t" - -#endif - "str r5, [%[dest]], #4\n\t" - /* increment counter and jmp to top */ - "subs %[w], %[w], #1\n\t" - "bne 1b\n\t" - "2:\n\t" - : [w] "+r" (w), [dest] "+r" (dst), [src] "+r" (src), [mask] "+r" (mask) - : [component_half] "r" (component_half), - [src_hi] "r" (src_hi), [src_lo] "r" (src_lo) - : "r4", "r5", "r6", "r7", "r8", "cc", "memory"); - } -} - -#endif - -PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, add_8_8, - uint8_t, 1, uint8_t, 1) -PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, over_8888_8888, - uint32_t, 1, uint32_t, 1) - -PIXMAN_ARM_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, armv6, over_8888_n_8888, - uint32_t, 1, uint32_t, 1) - -PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, armv6, over_n_8_8888, - uint8_t, 1, uint32_t, 1) - -PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (armv6, 0565_0565, SRC, - uint16_t, uint16_t) - -static const pixman_fast_path_t arm_simd_fast_paths[] = -{ - PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, a8r8g8b8, armv6_composite_over_8888_8888), - PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, armv6_composite_over_8888_8888), - PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, armv6_composite_over_8888_8888), - PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, x8b8g8r8, armv6_composite_over_8888_8888), - PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, a8r8g8b8, armv6_composite_over_8888_n_8888), - PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, x8r8g8b8, armv6_composite_over_8888_n_8888), - PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, a8b8g8r8, armv6_composite_over_8888_n_8888), - PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, x8b8g8r8, armv6_composite_over_8888_n_8888), - - PIXMAN_STD_FAST_PATH (ADD, a8, null, a8, armv6_composite_add_8_8), - - PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, armv6_composite_over_n_8_8888), - PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8r8g8b8, armv6_composite_over_n_8_8888), - PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, armv6_composite_over_n_8_8888), - PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8b8g8r8, armv6_composite_over_n_8_8888), - - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, r5g6b5, r5g6b5, armv6_0565_0565), - PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, b5g6r5, b5g6r5, armv6_0565_0565), - - { PIXMAN_OP_NONE }, -}; - -pixman_implementation_t * -_pixman_implementation_create_arm_simd (pixman_implementation_t *fallback) -{ - pixman_implementation_t *imp = _pixman_implementation_create (fallback, arm_simd_fast_paths); - - return imp; -} +/*
+ * Copyright © 2008 Mozilla Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Mozilla Corporation not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Mozilla Corporation makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Author: Jeff Muizelaar (jeff@infidigm.net)
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pixman-private.h"
+#include "pixman-arm-common.h"
+#include "pixman-fast-path.h"
+
+#if 0 /* This code was moved to 'pixman-arm-simd-asm.S' */
+
+void
+pixman_composite_add_8_8_asm_armv6 (int32_t width,
+ int32_t height,
+ uint8_t *dst_line,
+ int32_t dst_stride,
+ uint8_t *src_line,
+ int32_t src_stride)
+{
+ uint8_t *dst, *src;
+ int32_t w;
+ uint8_t s, d;
+
+ while (height--)
+ {
+ dst = dst_line;
+ dst_line += dst_stride;
+ src = src_line;
+ src_line += src_stride;
+ w = width;
+
+ /* ensure both src and dst are properly aligned before doing 32 bit reads
+ * we'll stay in this loop if src and dst have differing alignments
+ */
+ while (w && (((unsigned long)dst & 3) || ((unsigned long)src & 3)))
+ {
+ s = *src;
+ d = *dst;
+ asm ("uqadd8 %0, %1, %2" : "+r" (d) : "r" (s));
+ *dst = d;
+
+ dst++;
+ src++;
+ w--;
+ }
+
+ while (w >= 4)
+ {
+ asm ("uqadd8 %0, %1, %2"
+ : "=r" (*(uint32_t*)dst)
+ : "r" (*(uint32_t*)src), "r" (*(uint32_t*)dst));
+ dst += 4;
+ src += 4;
+ w -= 4;
+ }
+
+ while (w)
+ {
+ s = *src;
+ d = *dst;
+ asm ("uqadd8 %0, %1, %2" : "+r" (d) : "r" (s));
+ *dst = d;
+
+ dst++;
+ src++;
+ w--;
+ }
+ }
+
+}
+
+void
+pixman_composite_over_8888_8888_asm_armv6 (int32_t width,
+ int32_t height,
+ uint32_t *dst_line,
+ int32_t dst_stride,
+ uint32_t *src_line,
+ int32_t src_stride)
+{
+ uint32_t *dst;
+ uint32_t *src;
+ int32_t w;
+ uint32_t component_half = 0x800080;
+ uint32_t upper_component_mask = 0xff00ff00;
+ uint32_t alpha_mask = 0xff;
+
+ while (height--)
+ {
+ dst = dst_line;
+ dst_line += dst_stride;
+ src = src_line;
+ src_line += src_stride;
+ w = width;
+
+/* #define inner_branch */
+ asm volatile (
+ "cmp %[w], #0\n\t"
+ "beq 2f\n\t"
+ "1:\n\t"
+ /* load src */
+ "ldr r5, [%[src]], #4\n\t"
+#ifdef inner_branch
+ /* We can avoid doing the multiplication in two cases: 0x0 or 0xff.
+ * The 0x0 case also allows us to avoid doing an unecessary data
+ * write which is more valuable so we only check for that
+ */
+ "cmp r5, #0\n\t"
+ "beq 3f\n\t"
+
+ /* = 255 - alpha */
+ "sub r8, %[alpha_mask], r5, lsr #24\n\t"
+
+ "ldr r4, [%[dest]] \n\t"
+
+#else
+ "ldr r4, [%[dest]] \n\t"
+
+ /* = 255 - alpha */
+ "sub r8, %[alpha_mask], r5, lsr #24\n\t"
+#endif
+ "uxtb16 r6, r4\n\t"
+ "uxtb16 r7, r4, ror #8\n\t"
+
+ /* multiply by 257 and divide by 65536 */
+ "mla r6, r6, r8, %[component_half]\n\t"
+ "mla r7, r7, r8, %[component_half]\n\t"
+
+ "uxtab16 r6, r6, r6, ror #8\n\t"
+ "uxtab16 r7, r7, r7, ror #8\n\t"
+
+ /* recombine the 0xff00ff00 bytes of r6 and r7 */
+ "and r7, r7, %[upper_component_mask]\n\t"
+ "uxtab16 r6, r7, r6, ror #8\n\t"
+
+ "uqadd8 r5, r6, r5\n\t"
+
+#ifdef inner_branch
+ "3:\n\t"
+
+#endif
+ "str r5, [%[dest]], #4\n\t"
+ /* increment counter and jmp to top */
+ "subs %[w], %[w], #1\n\t"
+ "bne 1b\n\t"
+ "2:\n\t"
+ : [w] "+r" (w), [dest] "+r" (dst), [src] "+r" (src)
+ : [component_half] "r" (component_half), [upper_component_mask] "r" (upper_component_mask),
+ [alpha_mask] "r" (alpha_mask)
+ : "r4", "r5", "r6", "r7", "r8", "cc", "memory"
+ );
+ }
+}
+
+void
+pixman_composite_over_8888_n_8888_asm_armv6 (int32_t width,
+ int32_t height,
+ uint32_t *dst_line,
+ int32_t dst_stride,
+ uint32_t *src_line,
+ int32_t src_stride,
+ uint32_t mask)
+{
+ uint32_t *dst;
+ uint32_t *src;
+ int32_t w;
+ uint32_t component_half = 0x800080;
+ uint32_t alpha_mask = 0xff;
+
+ mask = (mask) >> 24;
+
+ while (height--)
+ {
+ dst = dst_line;
+ dst_line += dst_stride;
+ src = src_line;
+ src_line += src_stride;
+ w = width;
+
+/* #define inner_branch */
+ asm volatile (
+ "cmp %[w], #0\n\t"
+ "beq 2f\n\t"
+ "1:\n\t"
+ /* load src */
+ "ldr r5, [%[src]], #4\n\t"
+#ifdef inner_branch
+ /* We can avoid doing the multiplication in two cases: 0x0 or 0xff.
+ * The 0x0 case also allows us to avoid doing an unecessary data
+ * write which is more valuable so we only check for that
+ */
+ "cmp r5, #0\n\t"
+ "beq 3f\n\t"
+
+#endif
+ "ldr r4, [%[dest]] \n\t"
+
+ "uxtb16 r6, r5\n\t"
+ "uxtb16 r7, r5, ror #8\n\t"
+
+ /* multiply by alpha (r8) then by 257 and divide by 65536 */
+ "mla r6, r6, %[mask_alpha], %[component_half]\n\t"
+ "mla r7, r7, %[mask_alpha], %[component_half]\n\t"
+
+ "uxtab16 r6, r6, r6, ror #8\n\t"
+ "uxtab16 r7, r7, r7, ror #8\n\t"
+
+ "uxtb16 r6, r6, ror #8\n\t"
+ "uxtb16 r7, r7, ror #8\n\t"
+
+ /* recombine */
+ "orr r5, r6, r7, lsl #8\n\t"
+
+ "uxtb16 r6, r4\n\t"
+ "uxtb16 r7, r4, ror #8\n\t"
+
+ /* 255 - alpha */
+ "sub r8, %[alpha_mask], r5, lsr #24\n\t"
+
+ /* multiply by alpha (r8) then by 257 and divide by 65536 */
+ "mla r6, r6, r8, %[component_half]\n\t"
+ "mla r7, r7, r8, %[component_half]\n\t"
+
+ "uxtab16 r6, r6, r6, ror #8\n\t"
+ "uxtab16 r7, r7, r7, ror #8\n\t"
+
+ "uxtb16 r6, r6, ror #8\n\t"
+ "uxtb16 r7, r7, ror #8\n\t"
+
+ /* recombine */
+ "orr r6, r6, r7, lsl #8\n\t"
+
+ "uqadd8 r5, r6, r5\n\t"
+
+#ifdef inner_branch
+ "3:\n\t"
+
+#endif
+ "str r5, [%[dest]], #4\n\t"
+ /* increment counter and jmp to top */
+ "subs %[w], %[w], #1\n\t"
+ "bne 1b\n\t"
+ "2:\n\t"
+ : [w] "+r" (w), [dest] "+r" (dst), [src] "+r" (src)
+ : [component_half] "r" (component_half), [mask_alpha] "r" (mask),
+ [alpha_mask] "r" (alpha_mask)
+ : "r4", "r5", "r6", "r7", "r8", "r9", "cc", "memory"
+ );
+ }
+}
+
+void
+pixman_composite_over_n_8_8888_asm_armv6 (int32_t width,
+ int32_t height,
+ uint32_t *dst_line,
+ int32_t dst_stride,
+ uint32_t src,
+ int32_t unused,
+ uint8_t *mask_line,
+ int32_t mask_stride)
+{
+ uint32_t srca;
+ uint32_t *dst;
+ uint8_t *mask;
+ int32_t w;
+
+ srca = src >> 24;
+
+ uint32_t component_mask = 0xff00ff;
+ uint32_t component_half = 0x800080;
+
+ uint32_t src_hi = (src >> 8) & component_mask;
+ uint32_t src_lo = src & component_mask;
+
+ while (height--)
+ {
+ dst = dst_line;
+ dst_line += dst_stride;
+ mask = mask_line;
+ mask_line += mask_stride;
+ w = width;
+
+/* #define inner_branch */
+ asm volatile (
+ "cmp %[w], #0\n\t"
+ "beq 2f\n\t"
+ "1:\n\t"
+ /* load mask */
+ "ldrb r5, [%[mask]], #1\n\t"
+#ifdef inner_branch
+ /* We can avoid doing the multiplication in two cases: 0x0 or 0xff.
+ * The 0x0 case also allows us to avoid doing an unecessary data
+ * write which is more valuable so we only check for that
+ */
+ "cmp r5, #0\n\t"
+ "beq 3f\n\t"
+
+#endif
+ "ldr r4, [%[dest]] \n\t"
+
+ /* multiply by alpha (r8) then by 257 and divide by 65536 */
+ "mla r6, %[src_lo], r5, %[component_half]\n\t"
+ "mla r7, %[src_hi], r5, %[component_half]\n\t"
+
+ "uxtab16 r6, r6, r6, ror #8\n\t"
+ "uxtab16 r7, r7, r7, ror #8\n\t"
+
+ "uxtb16 r6, r6, ror #8\n\t"
+ "uxtb16 r7, r7, ror #8\n\t"
+
+ /* recombine */
+ "orr r5, r6, r7, lsl #8\n\t"
+
+ "uxtb16 r6, r4\n\t"
+ "uxtb16 r7, r4, ror #8\n\t"
+
+ /* we could simplify this to use 'sub' if we were
+ * willing to give up a register for alpha_mask
+ */
+ "mvn r8, r5\n\t"
+ "mov r8, r8, lsr #24\n\t"
+
+ /* multiply by alpha (r8) then by 257 and divide by 65536 */
+ "mla r6, r6, r8, %[component_half]\n\t"
+ "mla r7, r7, r8, %[component_half]\n\t"
+
+ "uxtab16 r6, r6, r6, ror #8\n\t"
+ "uxtab16 r7, r7, r7, ror #8\n\t"
+
+ "uxtb16 r6, r6, ror #8\n\t"
+ "uxtb16 r7, r7, ror #8\n\t"
+
+ /* recombine */
+ "orr r6, r6, r7, lsl #8\n\t"
+
+ "uqadd8 r5, r6, r5\n\t"
+
+#ifdef inner_branch
+ "3:\n\t"
+
+#endif
+ "str r5, [%[dest]], #4\n\t"
+ /* increment counter and jmp to top */
+ "subs %[w], %[w], #1\n\t"
+ "bne 1b\n\t"
+ "2:\n\t"
+ : [w] "+r" (w), [dest] "+r" (dst), [src] "+r" (src), [mask] "+r" (mask)
+ : [component_half] "r" (component_half),
+ [src_hi] "r" (src_hi), [src_lo] "r" (src_lo)
+ : "r4", "r5", "r6", "r7", "r8", "cc", "memory");
+ }
+}
+
+#endif
+
+PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, add_8_8,
+ uint8_t, 1, uint8_t, 1)
+PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, over_8888_8888,
+ uint32_t, 1, uint32_t, 1)
+
+PIXMAN_ARM_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, armv6, over_8888_n_8888,
+ uint32_t, 1, uint32_t, 1)
+
+PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, armv6, over_n_8_8888,
+ uint8_t, 1, uint32_t, 1)
+
+PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (armv6, 0565_0565, SRC,
+ uint16_t, uint16_t)
+PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (armv6, 8888_8888, SRC,
+ uint32_t, uint32_t)
+
+static const pixman_fast_path_t arm_simd_fast_paths[] =
+{
+ PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, a8r8g8b8, armv6_composite_over_8888_8888),
+ PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, armv6_composite_over_8888_8888),
+ PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, armv6_composite_over_8888_8888),
+ PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, x8b8g8r8, armv6_composite_over_8888_8888),
+ PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, a8r8g8b8, armv6_composite_over_8888_n_8888),
+ PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, x8r8g8b8, armv6_composite_over_8888_n_8888),
+ PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, a8b8g8r8, armv6_composite_over_8888_n_8888),
+ PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, x8b8g8r8, armv6_composite_over_8888_n_8888),
+
+ PIXMAN_STD_FAST_PATH (ADD, a8, null, a8, armv6_composite_add_8_8),
+
+ PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, armv6_composite_over_n_8_8888),
+ PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8r8g8b8, armv6_composite_over_n_8_8888),
+ PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, armv6_composite_over_n_8_8888),
+ PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8b8g8r8, armv6_composite_over_n_8_8888),
+
+ PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, r5g6b5, r5g6b5, armv6_0565_0565),
+ PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, b5g6r5, b5g6r5, armv6_0565_0565),
+
+ PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, armv6_8888_8888),
+ PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, armv6_8888_8888),
+ PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, armv6_8888_8888),
+ PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, a8b8g8r8, armv6_8888_8888),
+ PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, x8b8g8r8, armv6_8888_8888),
+ PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, x8b8g8r8, x8b8g8r8, armv6_8888_8888),
+
+ { PIXMAN_OP_NONE },
+};
+
+pixman_implementation_t *
+_pixman_implementation_create_arm_simd (pixman_implementation_t *fallback)
+{
+ pixman_implementation_t *imp = _pixman_implementation_create (fallback, arm_simd_fast_paths);
+
+ return imp;
+}
diff --git a/xorg-server/xkeyboard-config/rules/base.lists.part b/xorg-server/xkeyboard-config/rules/base.lists.part index a0fecdff1..64319d376 100644 --- a/xorg-server/xkeyboard-config/rules/base.lists.part +++ b/xorg-server/xkeyboard-config/rules/base.lists.part @@ -9,7 +9,7 @@ ! $pcmodels = pc101 pc102 pc104 pc105
// Microsoft models (using MS geometry)
-! $msmodels = microsoft microsoft7000 microsoftpro microsoftprousb microsoftprose
+! $msmodels = microsoft microsoft4000 microsoft7000 microsoftpro microsoftprousb microsoftprose
// Nokia devices and keyboards
! $nokiamodels = nokiasu8w nokiarx44 nokiarx51
@@ -57,8 +57,8 @@ logiinkse logiinkseusb logiitc logiik \
logitech_base itouch logiultrax \
logitech_g15 \
- logidinovo logidinovoedge \
- microsoft7000 microsoftinet microsoftprousb microsoftprooem microsoftprose \
+ logidinovo logidinovoedge \
+ microsoft4000 microsoft7000 microsoftinet microsoftprousb microsoftprooem microsoftprose \
microsoftoffice microsoftmult \
mx1998 mx2500 mx2750 \
oretec \
diff --git a/xorg-server/xkeyboard-config/rules/base.xml.in b/xorg-server/xkeyboard-config/rules/base.xml.in index 8a83c2f0d..1a3d528d1 100644 --- a/xorg-server/xkeyboard-config/rules/base.xml.in +++ b/xorg-server/xkeyboard-config/rules/base.xml.in @@ -792,6 +792,13 @@ </model>
<model>
<configItem>
+ <name>microsoft4000</name>
+ <_description>Microsoft Natural Wireless Ergonomic Keyboard 4000</_description>
+ <vendor>Microsoft Inc.</vendor>
+ </configItem>
+ </model>
+ <model>
+ <configItem>
<name>microsoft7000</name>
<_description>Microsoft Natural Wireless Ergonomic Keyboard 7000</_description>
<vendor>Microsoft Inc.</vendor>
diff --git a/xorg-server/xkeyboard-config/symbols/inet b/xorg-server/xkeyboard-config/symbols/inet index 8f1151768..5fbc8a7a7 100644 --- a/xorg-server/xkeyboard-config/symbols/inet +++ b/xorg-server/xkeyboard-config/symbols/inet @@ -1266,6 +1266,19 @@ xkb_symbols "mx2750" { // Microsoft
+// Microsoft Natural Wireless Ergonomic Keyboard 4000
+partial alphanumeric_keys
+xkb_symbols "microsoft4000" {
+ include "inet(media_nav_common)"
+ key <I192> { [ XF86Launch1 ] };
+ key <I193> { [ XF86Launch2 ] };
+ key <I194> { [ XF86Launch3 ] };
+ key <I195> { [ XF86Launch4 ] };
+ key <I196> { [ XF86Launch5 ] };
+// Missing because of lack of support from kbd driver: Zoom in and
+// slider.
+};
+
// Microsoft Natural Wireless Ergonomic Keyboard 7000
partial alphanumeric_keys
xkb_symbols "microsoft7000" {
|