@@ -309,6 +309,24 @@ obj-y += $(addprefix ../libdis/, $(libdis-y))
obj-y += $(libobj-y)
obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
+ifeq ($(TARGET_BASE_ARCH), arm)
+ifdef CONFIG_GLES2
+CFLAGS+=-I$(DGLES2)/include
+LIBS+=-L$(DGLES2)/lib
+ifdef CONFIG_GLES2_STATIC
+LIBS+=-Wl,-Bstatic -lEGL -lGLESv2 -lOSMesa -Wl,-Bdynamic
+else
+LIBS+=-lEGL -lGLESv2
+endif
+ifndef CONFIG_WIN32
+LIBS+=-LX11 -ldl
+endif
+gles2_calls.o: gles2_calls.c gles2.h gles2_calls.h
+gles2.o: gles2.c gles2.h gles2_calls.h
+obj-arm-y += gles2.o gles2_calls.o
+endif # CONFIG_GLES2
+endif # TARGET_BASE_ARCH==arm
+
endif # CONFIG_SOFTMMU
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
@@ -295,6 +295,8 @@ blobs="yes"
pkgversion=""
check_utests="no"
user_pie="no"
+gles2="no"
+gles2_static="no"
zero_malloc=""
# OS specific
@@ -651,6 +653,12 @@ for opt do
;;
--enable-docs) docs="yes"
;;
+ --enable-gles2) gles2="yes"; gles2dir="/usr";
+ ;;
+ --enable-gles2-static) gles2="yes"; gles2_static="yes" gles2dir="/usr";
+ ;;
+ --gles2dir=*) gles2dir="$optarg"
+ ;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@@ -806,6 +814,9 @@ echo " --disable-blobs disable installing provided firmware blobs"
echo " --kerneldir=PATH look for kernel includes in PATH"
echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build"
+echo " --enable-gles2 ARM target: Enable OpenGL ES 2.0 hardware accelerator"
+echo " --enable-gles2-static ARM target: Link OpenGL ES 2.0 hardware accelerator statically"
+echo " --gles2dir=PATH prefix where dgles2 is installed"
echo ""
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
@@ -1629,6 +1640,21 @@ if compile_prog "" "" ; then
inotify=yes
fi
+inotify1=no
+cat > $TMPC << EOF
+#include <sys/inotify.h>
+
+int
+main(void)
+{
+ /* try to start inotify */
+ return inotify_init1(0);
+}
+EOF
+if compile_prog "" "" ; then
+ inotify1=yes
+fi
+
# check if utimensat and futimens are supported
utimens=no
cat > $TMPC << EOF
@@ -1966,8 +1992,9 @@ echo "Install blobs $blobs"
echo "KVM support $kvm"
echo "fdt support $fdt"
echo "preadv support $preadv"
-echo "fdatasync $fdatasync"
-echo "uuid support $uuid"
+echo "gles2 support $gles2"
+echo "gles2 static $gles2_static"
+echo "dgles2 prefix $gles2dir"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2136,6 +2163,9 @@ fi
if test "$inotify" = "yes" ; then
echo "CONFIG_INOTIFY=y" >> $config_host_mak
fi
+if test "$inotify1" = "yes" ; then
+ echo "CONFIG_INOTIFY1=y" >> $config_host_mak
+fi
if test "$byteswap_h" = "yes" ; then
echo "CONFIG_BYTESWAP_H=y" >> $config_host_mak
fi
@@ -2183,6 +2213,13 @@ fi
if test "$fdatasync" = "yes" ; then
echo "CONFIG_FDATASYNC=y" >> $config_host_mak
fi
+if test "$gles2" = "yes" ; then
+ echo "CONFIG_GLES2=y" >> $config_host_mak
+if test "$gles2_static" = "yes" ; then
+ echo "CONFIG_GLES2_STATIC=y" >> $config_host_mak
+fi
+ echo "DGLES2=$gles2dir" >> $config_host_mak
+fi
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
new file mode 100644
@@ -0,0 +1,764 @@
+/* Copyright (c) 2009-2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gles2.h"
+#include <pthread.h>
+
+// From target-arm/helper.c.
+extern int get_phys_addr(CPUState *env, uint32_t address,
+ int access_type, int is_user,
+ uint32_t *phys_ptr, int *prot,
+ target_ulong *page_size);
+
+
+// Information holder for guest->host call.
+struct gles2_Call
+{
+#ifndef NDEBUG
+ char const* name;
+#endif //!NDEBUG
+ gles2_Callback* callback;
+};
+
+// List of calls to used by the kernel module (page 0).
+static gles2_Call const gles2_kcalls[];
+// List of calls used by clients (page 1->15).
+static gles2_Call const gles2_calls[];
+int gles2_quality = 100;
+
+// Translate a target virtual address to physical address.
+static target_ulong gles2_pa(gles2_State *s, target_ulong va,
+ int access_type)
+{
+ target_ulong pa, ps;
+ int prot;
+
+ if (get_phys_addr(s->env, va, access_type, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Page fault on guest!\n");
+ return 0;
+ }
+
+ return pa;
+}
+
+int gles2_transfer_compile(gles2_CompiledTransfer* tfr, gles2_State *s,
+ target_ulong va, target_ulong len)
+{
+ tfr->nsections = 0;
+ tfr->sections = 0;
+
+#if (GLES2_DEBUG == 1)
+ target_ulong first_page = TARGET_PAGE(va);
+#endif // GLES2_DEBUG == 1
+
+ target_ulong last_page = TARGET_PAGE(va + len - 1);
+ target_ulong start_addr = va;
+
+ GLES2_PRINT("DEBUG: Compiling transfer of %d bytes at 0x%x (0x%x->0x%x).\n",
+ len, va, first_page, last_page);
+
+ // Loop through the pages.
+ while (len) {
+ target_ulong start_page = TARGET_PAGE(start_addr);
+ target_ulong start_pa = gles2_pa(s, start_page, 0);
+ target_ulong end_pa = start_pa;
+
+ // Solve length of continuous section.
+ target_ulong end_page = start_page;
+ while(end_page < last_page) {
+ target_ulong next_page = end_page + TARGET_PAGE_SIZE;
+ target_ulong next_pa = gles2_pa(s, next_page, 0);
+
+ // If the target pages are not linearly spaced, stop..
+ if((next_pa < start_pa) ||
+ (next_pa - start_pa > next_page - start_page)) {
+ break;
+ }
+
+ end_page = next_page;
+ end_pa = next_pa;
+ }
+
+ unsigned id = tfr->nsections++;
+
+ GLES2_PRINT("\tContinuous from 0x%x to 0x%x (0x%x to 0x%x) #%d.\n",
+ start_page, end_page, start_pa, end_pa, id);
+ tfr->sections = realloc(tfr->sections,
+ tfr->nsections*sizeof(*(tfr->sections)));
+
+ target_phys_addr_t pages_len = end_page + TARGET_PAGE_SIZE - start_page;
+ void* target_pages = cpu_physical_memory_map(start_pa, &pages_len, 0);
+
+ if (!target_pages || !pages_len) {
+ fprintf(stderr, "ERROR: Failed to map memory to host!\n");
+ return 0;
+ }
+
+ target_ulong section_len = end_page + TARGET_PAGE_SIZE - start_addr;
+
+ if (section_len > len) {
+ section_len = len;
+ }
+
+ target_ulong offset = TARGET_OFFSET(start_addr);
+ void* target_data = target_pages + offset;
+
+ GLES2_PRINT("\tSlice of %d bytes at %p (offset = %x).\n",
+ section_len, target_data, offset);
+
+ tfr->sections[id].base = target_data;
+ tfr->sections[id].len = section_len;
+
+ cpu_physical_memory_unmap(target_pages, pages_len, 0, pages_len);
+ len -= section_len;
+ start_addr += section_len;
+ GLES2_PRINT("\t%d bytes remain...\n", len);
+ }
+ return 1;
+}
+
+void gles2_transfer_exec(gles2_CompiledTransfer* tfr, gles2_State *s,
+ void* data, int access_type)
+{
+ unsigned i;
+
+ for (i = 0; i < tfr->nsections; ++i) {
+ void* target_data = tfr->sections[i].base;
+ target_ulong len = tfr->sections[i].len;
+ if (access_type == 0) {
+ memcpy(data, target_data, len);
+ } else {
+ memcpy(target_data, data, len);
+ }
+ data += len;
+ }
+}
+
+void gles2_transfer_free(gles2_CompiledTransfer* tfr)
+{
+ free(tfr->sections);
+ tfr->sections = 0;
+ tfr->nsections = 0;
+}
+
+int gles2_transfer(gles2_State *s, target_ulong va, target_ulong len,
+ void* data, int access_type)
+{
+#if (GLES2_DEBUG == 1)
+ target_ulong first_page = TARGET_PAGE(va);
+#endif // GLES2_DEBUG == 1
+
+ target_ulong last_page = TARGET_PAGE(va + len - 1);
+ target_ulong start_addr = va;
+
+ GLES2_PRINT("DEBUG: Request transfer of %d bytes at 0x%x (0x%x->0x%x) (access=%d).\n",
+ len, va, first_page, last_page, access_type);
+
+ // Loop through the pages.
+ while (len) {
+ target_ulong start_page = TARGET_PAGE(start_addr);
+ target_ulong start_pa = gles2_pa(s, start_page, access_type);
+ target_ulong end_pa = start_pa;
+
+ // Solve length of continuous section.
+ target_ulong end_page = start_page;
+ while(end_page < last_page) {
+ target_ulong next_page = end_page + TARGET_PAGE_SIZE;
+ target_ulong next_pa = gles2_pa(s, next_page, access_type);
+
+ // If the target pages are not linearly spaced, stop..
+ if ((next_pa < start_pa) ||
+ (next_pa - start_pa > next_page - start_page)) {
+ break;
+ }
+
+ end_page = next_page;
+ end_pa = next_pa;
+ }
+
+ GLES2_PRINT("\tContinuous from 0x%x to 0x%x (0x%x to 0x%x).\n",
+ start_page, end_page, start_pa, end_pa);
+
+ target_phys_addr_t pages_len = end_page + TARGET_PAGE_SIZE - start_page;
+ void* target_pages = cpu_physical_memory_map(start_pa, &pages_len, access_type);
+ if (!target_pages || !pages_len) {
+ GLES2_PRINT("ERROR: Failed to map memory to host!\n");
+ return 0;
+ }
+
+ target_ulong section_len = end_page + TARGET_PAGE_SIZE - start_addr;
+ target_ulong offset = TARGET_OFFSET(start_addr);
+ void* target_data = target_pages + offset;
+
+ if (section_len > len) {
+ section_len = len;
+ }
+
+ GLES2_PRINT("\tTransfering %d bytes at %p (offset = %x).\n",
+ section_len, target_data, offset);
+
+ if (access_type == 0) {
+ memcpy(data, target_data, section_len);
+ } else {
+ memcpy(target_data, data, section_len);
+ }
+
+ cpu_physical_memory_unmap(target_pages, pages_len, access_type, pages_len);
+ len -= section_len;
+ start_addr += section_len;
+ data += section_len;
+
+ GLES2_PRINT("\t%d bytes remain...\n", len);
+ }
+ return 1;
+}
+
+void gles2_put_byte(gles2_State *s, target_ulong va, uint8_t byte)
+{
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 1, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return;
+ }
+
+ GLES2_PRINT("DEBUG: Written 0x%x to 0x%x(0x%x)\n", byte, va, pa);
+ stb_phys(pa, byte);
+}
+
+uint8_t gles2_get_byte(gles2_State *s, target_ulong va)
+{
+ uint8_t byte;
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 0, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return 0xDE;
+ }
+
+ byte = ldub_phys(pa);
+
+ GLES2_PRINT("DEBUG: Read 0x%x from 0x%x(0x%x)\n", byte, va, pa);
+
+ return byte;
+}
+
+void gles2_put_word(gles2_State *s, target_ulong va, uint16_t word)
+{
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 1, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return;
+ }
+
+ GLES2_PRINT("DEBUG: Written 0x%x to 0x%x(0x%x)\n", word, va, pa);
+ stw_phys(pa, word);
+}
+
+uint16_t gles2_get_word(gles2_State *s, target_ulong va)
+{
+ uint16_t word;
+
+ int prot;
+ target_ulong pa, ps;
+ if (get_phys_addr(s->env, va, 0, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return 0xDEAD;
+ }
+
+ word = lduw_phys(pa);
+
+ GLES2_PRINT("DEBUG: Read 0x%x from 0x%x(0x%x)\n", word, va, pa);
+
+ return word;
+}
+
+uint32_t gles2_get_dword(gles2_State *s, target_ulong va)
+{
+ uint32_t dword;
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 0, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return 0xDEAD000;
+ }
+
+ dword = ldl_phys(pa);
+
+ GLES2_PRINT("DEBUG: Read 0x%x from 0x%x(0x%x)\n", dword, va, pa);
+
+ return dword;
+}
+
+void gles2_put_dword(gles2_State *s, target_ulong va, uint32_t dword)
+{
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 1, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return;
+ }
+
+ GLES2_PRINT("DEBUG: Written 0x%x to 0x%x(0x%x)\n", dword, va, pa);
+ stl_phys(pa, dword);
+}
+
+float gles2_get_float(gles2_State *s, target_ulong va)
+{
+ float flt;
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 0, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return -123456789.f;
+ }
+
+ cpu_physical_memory_read(pa, (unsigned char*)&flt, 4);
+ // flt = ldfl_p(pa);
+
+ GLES2_PRINT("DEBUG: Read %f from 0x%x(0x%x)\n", flt, va, pa);
+
+ return flt;
+}
+
+void gles2_put_float(gles2_State *s, target_ulong va, float flt)
+{
+ int prot;
+ target_ulong pa, ps;
+
+ if (get_phys_addr(s->env, va, 1, 1, &pa, &prot, &ps)) {
+ GLES2_PRINT("ERROR: Memory mapping failed for 0x%x!\n", va);
+ return;
+ }
+
+ GLES2_PRINT("DEBUG: Written %f to 0x%x(0x%x)\n", flt, va, pa);
+ cpu_physical_memory_write(pa, (unsigned char*)&flt, 4);
+ // stfl_p(pa, flt);
+}
+
+uint32_t gles2_handle_create(gles2_State *s, void* data)
+{
+ uint32_t i = 0;
+
+ if (data) {
+ for (i = 0; i < GLES2_NHANDLES; ++i) {
+ if (!s->handles[i]) {
+ break;
+ }
+ }
+
+ if (i == GLES2_NHANDLES) {
+ fprintf(stderr, "ERROR: No free handles!\n");
+ return 0x0;
+ }
+ s->handles[i] = data;
+ i |= GLES2_HANDLE_BASE;
+ }
+
+ GLES2_PRINT("Handle %x created for %p!\n", i, data);
+ return i;
+}
+
+uint32_t gles2_handle_find(gles2_State *s, void* data)
+{
+ uint32_t i = 0;
+
+ if (data) {
+ for(i = 0; i < GLES2_NHANDLES; ++i) {
+ if(s->handles[i] == data) {
+ break;
+ }
+ }
+
+ if (i == GLES2_NHANDLES) {
+// fprintf(stderr, "ERROR: Handle not found!\n");
+ return 0x0;
+ }
+ i |= GLES2_HANDLE_BASE;
+ }
+
+ GLES2_PRINT("Handle %x found for %p!\n", i, data);
+ return i;
+}
+
+void* gles2_handle_get(gles2_State *s, uint32_t i)
+{
+#if(GLES2_DEBUG == 1)
+ if(i && (i & ~GLES2_HANDLE_MASK) != GLES2_HANDLE_BASE)
+ {
+ GLES2_PRINT("ERROR: Invalid handle %x!\n", i);
+ exit(1);
+ }
+#endif // GLES2_DEBUG == 1
+
+ void* data = i ? s->handles[i & GLES2_HANDLE_MASK] : NULL;
+
+ GLES2_PRINT("Reading handle %x => %p\n", i, data);
+
+ return data;
+}
+
+void* gles2_handle_free(gles2_State *s, uint32_t i)
+{
+ void* data = NULL;
+ if (i) {
+ data = s->handles[i & GLES2_HANDLE_MASK];
+ s->handles[i & GLES2_HANDLE_MASK] = NULL;
+ }
+
+ GLES2_PRINT("Freed handle %i => %p\n", i, data);
+ return data;
+}
+
+// Virtual register area write operation handler.
+static void gles2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ gles2_State *s = (gles2_State*)opaque;
+
+ target_ulong page = addr/(4*TARGET_PAGE_SIZE);
+ target_ulong callnr = TARGET_OFFSET(addr)/0x04;
+
+ GLES2_PRINT("Page %d write (call nr. %d).\n", page, callnr);
+
+ if (page) {
+ gles2_Call const *call = gles2_calls + callnr;
+
+ if (page > 1) {
+ gles2_Client* client;
+
+ // Client API calls without active context should be ignored.
+ if ((page - 2 > GLES2_NCLIENTS) ||
+ !(client = s->clients[page - 2])) {
+ return;
+ }
+
+ // Make sure nothing is running.
+ GLES2_PRINT("Syncing with worker...\n");
+ pthread_mutex_lock(&client->mutex_wait);
+ while (client->state != gles2_ClientState_ready) {
+ pthread_cond_wait(&client->cond_state, &client->mutex_wait);
+ }
+ pthread_mutex_lock(&client->mutex_run);
+ pthread_mutex_lock(&client->mutex_xcode);
+ client->call = call;
+ client->state = gles2_ClientState_pending;
+ client->phase_xcode = 0;
+ GLES2_PRINT("Requesting call %s...\n", call->name);
+ pthread_cond_signal(&client->cond_start);
+ pthread_mutex_unlock(&client->mutex_wait);
+
+ GLES2_PRINT("Releasing worker for decoding...\n");
+ pthread_mutex_unlock(&client->mutex_run);
+ do {
+ pthread_cond_wait(&client->cond_xcode, &client->mutex_xcode);
+ } while (client->phase_xcode < 1);
+
+ pthread_mutex_unlock(&client->mutex_xcode);
+ GLES2_PRINT("Decoding finished.\n");
+ } else {
+ gles2_decode_t d = 0;
+ GLES2_PRINT("Calling clientless function %s...\n", call->name);
+ call->callback(s, &d, 0);
+ }
+ } else {
+ gles2_Call const *call = gles2_kcalls + callnr;
+ gles2_decode_t d = 0;
+
+ GLES2_PRINT("Calling kernel function %s...\n", call->name);
+
+ call->callback(s, &d, 0);
+ }
+}
+
+// Virtual register area read operation handler.
+static uint32_t gles2_read(void *opaque, target_phys_addr_t addr)
+{
+ gles2_State *s = (gles2_State*)opaque;
+
+ target_ulong page = addr/(4*TARGET_PAGE_SIZE);
+
+ if (page) {
+ gles2_Client* client;
+
+ // Client API calls without active context should be ignored.
+ if ((page - 2 > GLES2_NCLIENTS) ||
+ !(client = s->clients[page - 2])) {
+ return 0;
+ }
+
+ if(pthread_mutex_trylock(&client->mutex_xcode)) {
+ return 1;
+ }
+
+ if(client->phase_xcode == 2) {
+ while (client->phase_xcode < 4) {
+ client->phase_xcode = 3;
+ pthread_cond_signal(&client->cond_return);
+ pthread_cond_wait(&client->cond_xcode, &client->mutex_xcode);
+ }
+ pthread_mutex_unlock(&client->mutex_xcode);
+ return 0;
+ }
+ int ret = (client->phase_xcode == 4 ? 0 : 1);
+ pthread_mutex_unlock(&client->mutex_xcode);
+ return ret;
+ }
+ return 0;
+}
+
+static CPUReadMemoryFunc *gles2_readfn[] = {
+ gles2_read,
+ gles2_read,
+ gles2_read,
+};
+
+static CPUWriteMemoryFunc *gles2_writefn[] = {
+ gles2_write,
+ gles2_write,
+ gles2_write,
+};
+
+// Initializes a new gles2 device.
+void *gles2_init(CPUState *env)
+{
+ gles2_State *s = qemu_malloc(sizeof(*s));
+ unsigned i;
+
+ s->env = env;
+ s->quality = gles2_quality;
+
+ GLES2_PRINT("GLES2 quality: %d\n", s->quality);
+
+ cpu_register_physical_memory(GLES2_HWBASE,
+ GLES2_HWSIZE,
+ cpu_register_io_memory(gles2_readfn,
+ gles2_writefn, s));
+
+ for (i = 0; i < GLES2_NCLIENTS; ++i) {
+ s->clients[i] = NULL;
+ }
+
+ for (i = 0; i < GLES2_NHANDLES; ++i) {
+ s->handles[i] = NULL;
+ }
+
+ GLES2_PRINT("Registered IO memory!\n");
+ return s;
+}
+
+/******************************************************************************
+ *
+ * Kernel interface functions.
+ *
+ *****************************************************************************/
+
+static void* gles2_client_worker(void *opaque)
+{
+ gles2_Client *client = opaque;
+ int run = 1;
+
+ GLES2_PRINT("WORKER(%d): Starting!\n", client->nr);
+
+ pthread_mutex_lock(&client->mutex_xcode);
+ do
+ {
+ gles2_decode_t d = 0;
+ GLES2_PRINT("WORKER(%d): Waiting for call...\n", client->nr);
+ pthread_mutex_lock(&client->mutex_wait);
+
+ client->state = gles2_ClientState_ready;
+ pthread_cond_signal(&client->cond_state);
+ client->phase_xcode = 4;
+ pthread_cond_signal(&client->cond_xcode);
+ pthread_mutex_unlock(&client->mutex_xcode);
+ while (client->state != gles2_ClientState_pending) {
+ pthread_cond_wait(&client->cond_start, &client->mutex_wait);
+ }
+
+ GLES2_PRINT("WORKER(%d): Got call, waiting permission to run...\n", client->nr);
+
+ pthread_mutex_lock(&client->mutex_run);
+ GLES2_PRINT("WORKER(%d): Running!\n", client->nr);
+ client->state = gles2_ClientState_running;
+ pthread_mutex_unlock(&client->mutex_wait);
+
+ if (client->call) {
+ GLES2_PRINT("WORKER(%d): Calling function %s (%p)...\n",
+ client->nr, client->call->name, client->call);
+ client->call->callback(client->s, &d, client);
+
+ GLES2_PRINT("\tWORKER(%d): Done.\n", client->nr);
+ client->state = gles2_ClientState_done;
+ } else {
+ GLES2_PRINT("WORKER(%d): Exit requested!\n", client->nr);
+ run = 0;
+ client->state = gles2_ClientState_exit;
+ pthread_cond_signal(&client->cond_state);
+ }
+ pthread_mutex_unlock(&client->mutex_run);
+ } while (run);
+
+ GLES2_PRINT("WORKER(%d): Exiting!\n", client->nr);
+ return opaque;
+}
+
+// Called by kernel module when a new client connects.
+static void gles2_init_cb(gles2_State *s, gles2_decode_t *d, gles2_Client *c)
+{
+ unsigned i;
+ gles2_Client *client;
+ pthread_attr_t attr;
+
+ for (i = 0; i < GLES2_NCLIENTS; ++i) {
+ if (!s->clients[i]) {
+ break;
+ }
+ }
+
+ if (i == GLES2_NCLIENTS) {
+ GLES2_PRINT("ERROR: No free slots!\n");
+ gles2_ret_dword(s, 0);
+ return;
+ }
+
+ GLES2_PRINT("Initialization!\n");
+
+ client = malloc(sizeof(*client));
+ client->s = s;
+ client->nr = i + 1;
+ pthread_mutex_init(&client->mutex_wait, NULL);
+ pthread_mutex_init(&client->mutex_run, NULL);
+ pthread_mutex_init(&client->mutex_xcode, NULL);
+ pthread_cond_init(&client->cond_start, NULL);
+ pthread_cond_init(&client->cond_state, NULL);
+ pthread_cond_init(&client->cond_xcode, NULL);
+ pthread_cond_init(&client->cond_return, NULL);
+ client->state = gles2_ClientState_init;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_mutex_lock(&client->mutex_wait);
+
+ GLES2_PRINT("Creating worker...\n");
+ pthread_create(&client->thread, &attr, gles2_client_worker, client);
+
+ do {
+ pthread_cond_wait(&client->cond_state, &client->mutex_wait);
+ } while(client->state != gles2_ClientState_ready);
+ pthread_mutex_unlock(&client->mutex_wait);
+
+ GLES2_PRINT("Worker initialized\n");
+
+ s->clients[i] = client;
+ gles2_ret_dword(s, client->nr);
+}
+
+// Called by kernel module when an existing client disconnects.
+static void gles2_exit_cb(gles2_State *s, gles2_decode_t *d, gles2_Client *c)
+{
+ uint32_t nr = gles2_arg_dword(s, d);
+ gles2_Client *client;
+
+ GLES2_PRINT("Exit called for client %d!\n", nr);
+
+ if ((nr > GLES2_NCLIENTS + 1) ||
+ (nr == 0)) {
+ GLES2_PRINT("Client number out of range!\n");
+ return;
+ } else {
+ client = s->clients[nr - 1];
+ }
+
+ if (!client) {
+ GLES2_PRINT("Can't exit NULL client!\n");
+ return;
+ }
+
+ GLES2_PRINT("\tRequesting worker to exit.\n");
+
+ // Make sure nothing is running.
+ GLES2_PRINT("Syncing with worker...\n");
+ pthread_mutex_lock(&client->mutex_wait);
+ while (client->state != gles2_ClientState_ready) {
+ pthread_cond_wait(&client->cond_state, &client->mutex_wait);
+ }
+ pthread_mutex_lock(&client->mutex_run);
+ client->call = NULL;
+ client->state = gles2_ClientState_pending;
+ GLES2_PRINT("Requesting exit...\n");
+ pthread_cond_signal(&client->cond_start);
+ pthread_mutex_unlock(&client->mutex_wait);
+
+ GLES2_PRINT("Waiting worker to exit...\n");
+ do {
+ pthread_cond_wait(&client->cond_state, &client->mutex_run);
+ } while (client->state != gles2_ClientState_exit);
+ pthread_mutex_unlock(&client->mutex_run);
+
+ GLES2_PRINT("\tJoining...\n");
+ pthread_join(client->thread, NULL);
+ pthread_mutex_destroy(&client->mutex_wait);
+ pthread_mutex_destroy(&client->mutex_run);
+ pthread_cond_destroy(&client->cond_start);
+ pthread_cond_destroy(&client->cond_state);
+
+ free(client);
+ s->clients[nr - 1] = NULL;
+
+ GLES2_PRINT("\tDone!\n");
+}
+
+/******************************************************************************
+ *
+ * Call tables
+ *
+ *****************************************************************************/
+
+/* Make a weak stub for every dummy function. */
+#define CALL_DUMMY(func) \
+ void gles2_##func##_cb(gles2_State *s, gles2_decode_t *d, struct gles2_Client *c); \
+ void gles2_##func##_cb(gles2_State *s, gles2_decode_t *d, struct gles2_Client *c) \
+ { \
+ fprintf(stderr, "GLES2: DUMMY " #func "\n"); \
+ }
+
+#define CALL_ENTRY(func) \
+ void gles2_##func##_cb(gles2_State *s, gles2_decode_t *d, struct gles2_Client *c);
+
+#include "gles2_calls.h"
+
+#undef CALL_ENTRY
+#undef CALL_DUMMY
+
+#define CALL_ENTRY(func) { #func, gles2_##func##_cb },
+#define CALL_DUMMY(func) { #func, gles2_##func##_cb },
+
+static gles2_Call const gles2_kcalls[] =
+{
+ CALL_ENTRY(init)
+ CALL_ENTRY(exit)
+};
+
+static gles2_Call const gles2_calls[] =
+{
+ { "<<none>>", 0 },
+#include "gles2_calls.h"
+};
+
+#undef CALL_ENTRY
+
new file mode 100644
@@ -0,0 +1,323 @@
+/* Copyright (c) 2009-2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GLES2_H__
+#define GLES2_H__
+
+#include "qemu-common.h"
+#include "cpu.h"
+#include <pthread.h>
+
+#define GLES2_HWBASE 0x4f000000
+#define GLES2_HWSIZE 0x00100000
+#define GLES2_NCLIENTS (GLES2_HWSIZE/TARGET_PAGE_SIZE - 2)
+#define GLES2_NHANDLES GLES2_NCLIENTS * 16
+// Address base for host to guest pointer handles.
+#define GLES2_HANDLE_BASE 0xCAFE0000
+#define GLES2_HANDLE_MASK 0x0000FFFF // Handle to index bitmask.
+
+// Round address to lower page boundary.
+#define TARGET_PAGE(addr) ((addr) & ~(TARGET_PAGE_SIZE - 1))
+// Return the page offset part of address.
+#define TARGET_OFFSET(addr) ((addr) & (TARGET_PAGE_SIZE - 1))
+
+#define GLES2_DEBUG 0
+#if(GLES2_DEBUG == 1)
+# define GLES2_PRINT(format, args...) \
+ fprintf(stderr, "GLES2: " format, ##args)
+#else
+# define GLES2_PRINT(format, args...) (void)0
+#endif // GLES_DEBUG != 1
+
+struct gles2_Array;
+typedef struct gles2_Array gles2_Array;
+struct gles2_Call;
+typedef struct gles2_Call gles2_Call;
+struct gles2_State;
+typedef struct gles2_State gles2_State;
+
+typedef enum gles2_ClientState
+{
+ gles2_ClientState_init,
+ gles2_ClientState_ready,
+ gles2_ClientState_pending,
+ gles2_ClientState_running,
+ gles2_ClientState_done,
+ gles2_ClientState_exit
+} gles2_ClientState;
+
+// A connected GLES2 client.
+typedef struct gles2_Client
+{
+ gles2_State *s; // Link to the device state the client was connected to.
+ target_ulong nr; // The client ID from kernel.
+
+ gles2_Call const *call; // Next/current call to perform.
+ pthread_t thread; // The worker thread.
+ pthread_cond_t cond_start; // To wake worker for a call.
+ pthread_cond_t cond_state; // Worker signals when state changes.
+ volatile gles2_ClientState state;// Status of the client.
+ pthread_mutex_t mutex_run; // Locked when thread is running, or is
+ // prevented from doing so.
+ pthread_mutex_t mutex_wait; // For synchronization of worker and caller.
+
+ pthread_mutex_t mutex_xcode; // For decode/encode synchronization.
+ volatile int phase_xcode; // Phase of call 0: pending 1: decode done
+ // 2: exec done 3: encode done
+ pthread_cond_t cond_xcode; // --''--
+ pthread_cond_t cond_return; // --''--
+
+ gles2_Array *arrays; // Host side vertex pointer arrays.
+ int narrays; // Number of arrays (the maximum too).
+} gles2_Client;
+
+// The GLES2 device state holder.
+struct gles2_State
+{
+ CPUState *env; // The CPU the device is attached to.
+ gles2_Client *clients[GLES2_NCLIENTS]; // Array of clients.
+ void *handles[GLES2_NHANDLES]; // Handles passed from host to guest.
+ int quality; // Rendering quality.
+};
+
+typedef unsigned int gles2_decode_t; // Function call decoding state.
+typedef uint32_t gles2_target_arg_t; // Target unit argument type.
+// Callback for register area access.
+typedef void gles2_Callback(gles2_State *s, gles2_decode_t *d,
+ gles2_Client *c);
+
+// Create and initialize a GLES2 device and attach to CPU.
+extern void *gles2_init(CPUState *env);
+// Rendering quality option.
+extern int gles2_quality;
+
+/******************************************************************************
+ *
+ * Guest memory continuous access functions
+ *
+ *****************************************************************************/
+
+// Holder for compiled transfer holder.
+typedef struct gles2_CompiledTransfer
+{
+ unsigned nsections; // Number of physical memory sections in the transfer.
+ struct
+ {
+ char* base; // Base address of the section.
+ target_ulong len; // Length of the section.
+ } *sections; // Sections of the transfer.
+} gles2_CompiledTransfer;
+
+// Pre-compile a transfer to or from virtual guest address.
+// NOTE: An assumption is made that the mapping is equal for read and write, for
+// complicated transfers, use gles2_transfer or Fix It!
+extern int gles2_transfer_compile(gles2_CompiledTransfer *tfr, gles2_State *s,
+ target_ulong va, target_ulong len);
+// Execute a pre-compiled transfer.
+extern void gles2_transfer_exec(gles2_CompiledTransfer *tfr, gles2_State *s,
+ void* data, int access_type);
+// Free a pre-compiled transfer.
+extern void gles2_transfer_free(gles2_CompiledTransfer *tfr);
+// Perform a non-compiled transfer between guest and host.
+// access_type, read = 0, write = 1, execute = 2
+extern int gles2_transfer(gles2_State *s, target_ulong va, target_ulong len,
+ void* data, int access_type);
+
+/******************************************************************************
+ *
+ * Guest memory random access functions
+ *
+ *****************************************************************************/
+
+// Read an 8-bit byte from target system memory.
+extern uint8_t gles2_get_byte(gles2_State *s, target_ulong va);
+// Write an 8-bit byte to target system memory.
+extern void gles2_put_byte(gles2_State *s, target_ulong va, uint8_t byte);
+// Read a 16-bit word from target system memory.
+extern uint16_t gles2_get_word(gles2_State *s, target_ulong va);
+// Write a 16-bit word to target system memory.
+extern void gles2_put_word(gles2_State *s, target_ulong va, uint16_t word);
+// Read a 32-bit double word from target system memory.
+extern uint32_t gles2_get_dword(gles2_State *s, target_ulong va);
+// Write a 32-bit double word to target system memory.
+extern void gles2_put_dword(gles2_State *s, target_ulong va,
+ uint32_t dword);
+// Read a 32-bit float from target system memory.
+extern float gles2_get_float(gles2_State *s, target_ulong va);
+// Write a 32-bit float to target system memory.
+extern void gles2_put_float(gles2_State *s, target_ulong va, float flt);
+
+#define gles2_put_handle(s, va, handle) gles2_put_dword(s, va, handle)
+#define gles2_get_handle(s, va) gles2_get_dword(s, va)
+
+/******************************************************************************
+ *
+ * Handle management functions
+ *
+ *****************************************************************************/
+
+// Create a handle from host side pointer to be passed to guest.
+extern uint32_t gles2_handle_create(gles2_State *s, void* data);
+// Find if there is previously created handle for pointer.
+extern uint32_t gles2_handle_find(gles2_State *s, void* data);
+// Get the host pointer by guest handle.
+extern void* gles2_handle_get(gles2_State *s, uint32_t i);
+// Release a handle for reuse.
+extern void* gles2_handle_free(gles2_State *s, uint32_t i);
+
+// Get the smallest function argument according to target CPU ABI.
+static inline gles2_target_arg_t gles2_arg_raw(gles2_State *s, unsigned i);
+static inline gles2_target_arg_t gles2_arg_raw(gles2_State *s, unsigned i)
+{
+ if (i < 4) {
+ return s->env->regs[i];
+ }
+
+ return gles2_get_dword(s, s->env->regs[13] + 2*0x04 + (i - 4)*0x04);
+}
+
+/******************************************************************************
+ *
+ * ABI function argument decoding functions
+ *
+ *****************************************************************************/
+
+#define GLES2_DEBUG_ARGS 1
+static inline uint8_t gles2_arg_byte(gles2_State *s, gles2_decode_t *d);
+static inline uint8_t gles2_arg_byte(gles2_State *s, gles2_decode_t *d)
+{
+ uint8_t byte = gles2_arg_raw(s, (*d)++) & 0xFF;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("byte arg(%d) = %x\n", *d - 1, byte);
+#endif
+ return byte;
+}
+
+static inline uint16_t gles2_arg_word(gles2_State *s, gles2_decode_t *d);
+static inline uint16_t gles2_arg_word(gles2_State *s, gles2_decode_t *d)
+{
+ uint16_t word = gles2_arg_raw(s, (*d)++) & 0xFFFF;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("word arg(%d) = %x\n", *d - 1, word);
+#endif
+ return word;
+}
+
+static inline uint32_t gles2_arg_dword(gles2_State *s, gles2_decode_t *d);
+static inline uint32_t gles2_arg_dword(gles2_State *s, gles2_decode_t *d)
+{
+ uint32_t dword = gles2_arg_raw(s, (*d)++);
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("dword arg(%d) = %x\n", *d - 1, dword);
+#endif
+ return dword;
+}
+
+static inline uint64_t gles2_arg_qword(gles2_State *s, gles2_decode_t *d);
+static inline uint64_t gles2_arg_qword(gles2_State *s, gles2_decode_t *d)
+{
+ uint64_t qword = gles2_arg_raw(s, (*d)++)
+ | ((uint64_t)gles2_arg_raw(s, (*d)++) << 32);
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("qword arg(%d) = %"PRIu64"\n", *d - 2, qword);
+#endif
+ return qword;
+}
+
+static inline uint32_t gles2_arg_handle(gles2_State *s, gles2_decode_t *d);
+static inline uint32_t gles2_arg_handle(gles2_State *s, gles2_decode_t *d)
+{
+ uint32_t handle = gles2_arg_raw(s, (*d)++);
+
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("handle arg(%d) = %x\n", *d - 1, handle);
+#endif
+ return handle;
+}
+
+// This needs to be its own special function, because we must preserve the byteorder.
+static inline float gles2_arg_float(gles2_State *s, gles2_decode_t *d);
+static inline float gles2_arg_float(gles2_State *s, gles2_decode_t *d)
+{
+ unsigned i = (*d)++;
+
+ if (i < 4) {
+ return *((float*)&s->env->regs[i]);
+ }
+
+ return gles2_get_float(s, s->env->regs[13] + 2*0x04 + (i - 4)*0x04);
+}
+
+/******************************************************************************
+ *
+ * ABI return value encoding functions
+ *
+ *****************************************************************************/
+
+static inline void gles2_ret_byte(gles2_State *s, uint8_t byte);
+static inline void gles2_ret_byte(gles2_State *s, uint8_t byte)
+{
+ s->env->regs[0] = byte;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("byte ret = %d\n", byte);
+#endif
+}
+
+static inline void gles2_ret_word(gles2_State *s, uint16_t word);
+static inline void gles2_ret_word(gles2_State *s, uint16_t word)
+{
+ s->env->regs[0] = word;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("word ret = %d\n", word);
+#endif
+}
+
+static inline void gles2_ret_dword(gles2_State *s, uint32_t dword);
+static inline void gles2_ret_dword(gles2_State *s, uint32_t dword)
+{
+ s->env->regs[0] = dword;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("dword ret = %d\n", dword);
+#endif
+}
+
+static inline void gles2_ret_qword(gles2_State *s, uint64_t qword);
+static inline void gles2_ret_qword(gles2_State *s, uint64_t qword)
+{
+ s->env->regs[0] = qword & 0xFFFFFFFF;
+ s->env->regs[1] = qword >> 32;
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("qword ret = %"PRIu64"\n", qword);
+#endif
+}
+
+static inline void gles2_ret_handle(gles2_State *s, uint32_t handle);
+static inline void gles2_ret_handle(gles2_State *s, uint32_t handle)
+{
+ s->env->regs[0] = handle;
+
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("handle ret = %x\n", handle);
+#endif
+}
+
+static inline void gles2_ret_float(gles2_State *s, float flt);
+static inline void gles2_ret_float(gles2_State *s, float flt)
+{
+ s->env->regs[0] = *(uint32_t*)&flt;
+
+#if (GLES2_DEBUG_ARGS == 1)
+ GLES2_PRINT("float ret = %f\n", flt);
+#endif
+}
+
+#endif // GLES2_H__
+
new file mode 100644
@@ -0,0 +1,2409 @@
+/* Copyright (c) 2009-2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gles2.h"
+#include "EGL/degl.h"
+#include "GLES2/gl2.h"
+
+// Automatically create the prototype and function definition.
+#define GLES2_CB(FUNC) \
+ void gles2_##FUNC##_cb(gles2_State *s, \
+ gles2_decode_t *d, gles2_Client *c); \
+ void gles2_##FUNC##_cb(gles2_State *s, \
+ gles2_decode_t *d, gles2_Client *c)
+
+// Sizes of primitive types in the ABI.
+#define GLES2_HTYPE_byte uint8_t
+#define GLES2_HTYPE_word uint16_t
+#define GLES2_HTYPE_dword uint32_t
+#define GLES2_HTYPE_float float
+#define GLES2_HTYPE_handle uint32_t
+
+// Defines shorthands for handling types.
+#define GLES2_TYPE(TYPE, SIZE) \
+ typedef GLES2_HTYPE_##SIZE TYPE; \
+ inline void gles2_ret_##TYPE(gles2_State *s, TYPE value); \
+ inline void gles2_ret_##TYPE(gles2_State *s, TYPE value) \
+ { gles2_ret_##SIZE(s, value); } \
+ inline void gles2_put_##TYPE(gles2_State *s, target_ulong va, TYPE value); \
+ inline void gles2_put_##TYPE(gles2_State *s, target_ulong va, TYPE value) \
+ { gles2_put_##SIZE(s, va, value); } \
+ inline TYPE gles2_get_##TYPE(gles2_State *s, target_ulong va); \
+ inline TYPE gles2_get_##TYPE(gles2_State *s, target_ulong va) \
+ { return (TYPE)gles2_get_##SIZE(s, va); } \
+ inline TYPE gles2_arg_##TYPE(gles2_State *s, gles2_decode_t *d); \
+ inline TYPE gles2_arg_##TYPE(gles2_State *s, gles2_decode_t *d) \
+ { return (TYPE)gles2_arg_##SIZE(s, d); }
+
+// Bunch of expansions of previous macro to ease things up.
+GLES2_TYPE(Tptr, dword)
+GLES2_TYPE(TEGLBoolean, dword)
+GLES2_TYPE(TEGLint, dword)
+GLES2_TYPE(TEGLDisplay, handle)
+GLES2_TYPE(TEGLConfig, handle)
+GLES2_TYPE(TEGLContext, handle)
+GLES2_TYPE(TEGLSurface, handle)
+
+GLES2_TYPE(TGLclampf, float)
+GLES2_TYPE(TGLbitfield, dword)
+GLES2_TYPE(TGLboolean, byte)
+GLES2_TYPE(TGLint, dword)
+GLES2_TYPE(TGLuint, dword)
+GLES2_TYPE(TGLushort, word)
+GLES2_TYPE(TGLubyte, byte)
+GLES2_TYPE(TGLenum, dword)
+GLES2_TYPE(TGLsizei, dword)
+GLES2_TYPE(TGLfloat, float)
+
+// Just one more macro for even less typing.
+#define GLES2_ARG(TYPE, NAME) \
+ TYPE NAME = gles2_arg_##TYPE(s, d)
+
+#define GLES2_BARRIER_ARG \
+ if (c) { \
+ pthread_mutex_lock(&c->mutex_xcode); \
+ c->phase_xcode = 1; \
+ pthread_cond_signal(&c->cond_xcode); \
+ pthread_mutex_unlock(&c->mutex_xcode); \
+ GLES2_PRINT("-- ARG BARRIER --\n"); \
+ }
+#define GLES2_BARRIER_ARG_NORET \
+ if (c) { \
+ pthread_mutex_lock(&c->mutex_xcode); \
+ c->phase_xcode = 3; \
+ GLES2_PRINT("-- ARG & RETURN BARRIER --\n"); \
+ }
+#define GLES2_BARRIER_RET \
+ if (c) { \
+ pthread_mutex_lock(&c->mutex_xcode); \
+ c->phase_xcode = 2; \
+ do { \
+ pthread_cond_wait(&c->cond_return, &c->mutex_xcode); \
+ } while (c->phase_xcode == 2); \
+ GLES2_PRINT("-- RETURN BARRIER --\n"); \
+ }
+
+// pthread_cond_signal(&s->cond_xcode);
+
+GLES2_CB(eglGetDisplay)
+{
+// GLES2_ARG(TEGLDisplay, dpy);
+// (void)dpy;
+ GLES2_BARRIER_ARG;
+
+ GLES2_PRINT("Getting display...\n");
+
+ EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ GLES2_PRINT("\tGot host display %p...\n", dpy);
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLDisplay(s, gles2_handle_create(s, dpy));
+}
+
+GLES2_CB(eglInitialize)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(Tptr, majorp);
+ GLES2_ARG(Tptr, minorp);
+
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+
+ GLES2_PRINT("Request to initialize display %p...\n", dpy);
+
+ EGLint major, minor;
+ if (eglInitialize(dpy, &major, &minor)) {
+ GLES2_PRINT("Display initialized (EGL %d.%d)!\n", major, minor);
+ gles2_put_TEGLint(s, majorp, major);
+ gles2_put_TEGLint(s, minorp, minor);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_TRUE);
+ return;
+ }
+
+ GLES2_PRINT("Failed to initialize...\n");
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_FALSE);
+}
+
+GLES2_CB(eglGetConfigs)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(Tptr, configsp);
+ GLES2_ARG(TEGLint, config_size);
+ GLES2_ARG(Tptr, num_configp);
+
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+
+ EGLConfig* configs = configsp ? malloc(sizeof(EGLConfig)*config_size) : NULL;
+
+ EGLint num_config;
+ EGLBoolean ret = eglGetConfigs(dpy, configs, config_size, &num_config);
+
+ GLES2_BARRIER_RET;
+ if (configs) {
+ EGLint i;
+
+ for (i = 0; i < num_config; ++i) {
+ uint32_t handle;
+ if (!(handle = gles2_handle_find(s, configs[i]))) {
+ handle = gles2_handle_create(s, configs[i]);
+ }
+ gles2_put_TEGLConfig(s, configsp + i*sizeof(TEGLConfig), handle);
+ }
+
+ free(configs);
+ }
+ gles2_put_TEGLint(s, num_configp, num_config);
+
+ gles2_ret_TEGLBoolean(s, ret);
+}
+
+GLES2_CB(eglChooseConfig)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(Tptr, attrib_listp);
+ GLES2_ARG(Tptr, configsp);
+ GLES2_ARG(TEGLint, config_size);
+ GLES2_ARG(Tptr, num_configp);
+ (void)config_size;
+ (void)attrib_listp;
+
+ EGLint attrib_list_n = 0;
+ while (gles2_get_TEGLint(s, attrib_listp
+ + attrib_list_n*sizeof(EGLint)) != EGL_NONE) {
+ attrib_list_n += 2;
+ }
+ EGLint* attrib_list = malloc((attrib_list_n + 1)*sizeof(EGLint));
+ EGLint i;
+
+ for (i = 0; i < attrib_list_n; ++i) {
+ attrib_list[i] = gles2_get_TEGLint(s, attrib_listp
+ + i*sizeof(EGLint));
+ }
+ attrib_list[attrib_list_n] = EGL_NONE;
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+
+ EGLConfig* configs = configsp ? malloc(sizeof(EGLConfig)*config_size) : NULL;
+
+ EGLint num_config;
+ EGLBoolean ret = eglChooseConfig(dpy, attrib_list, configs, config_size, &num_config);
+ free(attrib_list);
+ GLES2_BARRIER_RET;
+ if (configs) {
+ EGLint i;
+
+ for (i = 0; i < num_config; ++i) {
+ uint32_t handle;
+ if (!(handle = gles2_handle_find(s, configs[i]))) {
+ handle = gles2_handle_create(s, configs[i]);
+ }
+ gles2_put_TEGLConfig(s, configsp + i*sizeof(TEGLConfig), handle);
+ }
+
+ free(configs);
+ }
+ gles2_put_TEGLint(s, num_configp, num_config);
+
+ gles2_ret_TEGLBoolean(s, ret);
+}
+
+GLES2_CB(eglGetConfigAttrib)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLConfig, config);
+ GLES2_ARG(TEGLint, attribute);
+ GLES2_ARG(Tptr, valuep);
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+
+ EGLint value;
+ EGLBoolean ret = eglGetConfigAttrib(dpy, gles2_handle_get(s, config), attribute, &value);
+
+ GLES2_BARRIER_RET;
+
+ gles2_put_TEGLint(s, valuep, value);
+ gles2_ret_TEGLBoolean(s, ret);
+}
+
+typedef struct gles2_Surface
+{
+ uint32_t ddrawp; // Pointer to the offscreen drawable in guest memory.
+ DEGLDrawable ddraw; // Offscreen drawable, read from guest memory.
+ EGLSurface surf; // Pointer to the EGL surface.
+ uint32_t pixelsp; // Pointer to pixels in guest memory.
+ int pixmap; // True if surface is pixmap.
+ gles2_CompiledTransfer tfr; // Framebuffer transfer.
+} gles2_Surface;
+
+// See if guest offscreen drawable was changed and if so, update host copy.
+static int gles2_surface_update(gles2_State *s, gles2_Surface *surf)
+{
+ int ret = 0;
+
+ uint32_t width = gles2_get_dword(s, surf->ddrawp + 0*sizeof(uint32_t));
+ uint32_t height = gles2_get_dword(s, surf->ddrawp + 1*sizeof(uint32_t));
+ uint32_t depth = gles2_get_dword(s, surf->ddrawp + 2*sizeof(uint32_t));
+ uint32_t bpp = gles2_get_dword(s, surf->ddrawp + 3*sizeof(uint32_t));
+ uint32_t pixelsp = gles2_get_dword(s, surf->ddrawp + 4*sizeof(uint32_t));
+
+ if (width != surf->ddraw.width
+ || height != surf->ddraw.height
+ || depth != surf->ddraw.depth) {
+ surf->ddraw.width = width;
+ surf->ddraw.height = height;
+ surf->ddraw.depth = depth;
+ surf->ddraw.bpp = bpp;
+ ret = 1;
+ }
+
+ surf->pixelsp = pixelsp;
+
+ return ret;
+}
+
+// TODO: Support swapping of offscreen surfaces.
+static void gles2_eglSwapCallback(void* userdata)
+{
+ (void)userdata;
+ GLES2_PRINT("Swap called!\n");
+}
+
+GLES2_CB(eglCreateWindowSurface)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLConfig, config_);
+ GLES2_ARG(Tptr, winp);
+ GLES2_ARG(Tptr, attrib_listp);
+
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ EGLConfig config = (EGLConfig)gles2_handle_get(s, config_);
+ (void)attrib_listp;
+
+ gles2_Surface* fsurf;
+
+ if (!(fsurf = malloc(sizeof(*fsurf)))) {
+ GLES2_PRINT("\tFake window creation failed!\n");
+ gles2_ret_TEGLSurface(s, 0);
+ return;
+ }
+
+
+ fsurf->ddrawp = winp;
+ fsurf->pixmap = 0;
+ gles2_surface_update(s, fsurf);
+ GLES2_BARRIER_ARG;
+
+ GLES2_PRINT("Host window creation requested, %dx%d@%d(Bpp=%d) at 0x%x...\n",
+ fsurf->ddraw.width, fsurf->ddraw.height,
+ fsurf->ddraw.depth, fsurf->ddraw.bpp, fsurf->pixelsp);
+
+ unsigned nbytes = fsurf->ddraw.width*fsurf->ddraw.height*fsurf->ddraw.bpp;
+ fsurf->ddraw.pixels = malloc(nbytes);
+ fsurf->ddraw.userdata = fsurf;
+ fsurf->ddraw.swap = gles2_eglSwapCallback;
+
+ if((fsurf->surf = eglCreateWindowSurface(dpy, config,
+ (EGLNativeWindowType)&fsurf->ddraw, NULL)) == EGL_NO_CONTEXT)
+ {
+ GLES2_PRINT("\tHost window creation failed!\n");
+ free(fsurf->ddraw.pixels);
+ free(fsurf);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLSurface(s, 0);
+ return;
+ }
+
+ GLES2_PRINT("Created at %p!\n", fsurf);
+ GLES2_BARRIER_RET;
+ gles2_transfer_compile(&fsurf->tfr, s, fsurf->pixelsp, nbytes);
+ gles2_ret_TEGLSurface(s, gles2_handle_create(s, fsurf));
+}
+
+GLES2_CB(eglCreatePixmapSurface)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLConfig, config_);
+ GLES2_ARG(Tptr, pixmapp);
+ GLES2_ARG(Tptr, attrib_listp);
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ EGLConfig config = (EGLConfig)gles2_handle_get(s, config_);
+ (void)attrib_listp;
+
+ gles2_Surface* fsurf;
+
+ if (!(fsurf = malloc(sizeof(*fsurf)))) {
+ GLES2_PRINT("\tFake pixmap creation failed!\n");
+ GLES2_BARRIER_ARG_NORET;
+ gles2_ret_TEGLSurface(s, 0);
+ return;
+ }
+
+ fsurf->ddrawp = pixmapp;
+ fsurf->pixmap = 1;
+ gles2_surface_update(s, fsurf);
+ GLES2_BARRIER_ARG;
+
+ GLES2_PRINT("Host pixmap creation requested, %dx%d@%d(Bpp=%d) at 0x%x...\n",
+ fsurf->ddraw.width, fsurf->ddraw.height,
+ fsurf->ddraw.depth, fsurf->ddraw.bpp, fsurf->pixelsp);
+
+ unsigned nbytes = fsurf->ddraw.width*fsurf->ddraw.height*fsurf->ddraw.bpp;
+ fsurf->ddraw.pixels = malloc(nbytes);
+ fsurf->ddraw.userdata = fsurf;
+ fsurf->ddraw.swap = gles2_eglSwapCallback;
+
+ if((fsurf->surf = eglCreatePixmapSurface(dpy, config,
+ (EGLNativeWindowType)&fsurf->ddraw, NULL)) == EGL_NO_CONTEXT) {
+ GLES2_PRINT("\tHost pixmap creation failed!\n");
+ free(fsurf->ddraw.pixels);
+ free(fsurf);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLSurface(s, 0);
+ return;
+ }
+
+ GLES2_PRINT("Created at %p!\n", fsurf);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLSurface(s, gles2_handle_create(s, fsurf));
+}
+
+GLES2_CB(eglDestroySurface)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLSurface, surface_);
+ GLES2_BARRIER_ARG_NORET;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ gles2_Surface* fsurf = (EGLSurface)gles2_handle_get(s, surface_);
+ gles2_handle_free(s, surface_);
+
+ eglDestroySurface(dpy, fsurf->surf);
+ free(fsurf->ddraw.pixels);
+
+ if(fsurf->pixmap == 0) {
+ gles2_transfer_free(&fsurf->tfr);
+ }
+ free(fsurf);
+}
+
+GLES2_CB(eglBindTexImage)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLSurface, surface_);
+ GLES2_ARG(TEGLint, buffer);
+ gles2_CompiledTransfer tfr;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ gles2_Surface* fsurf = (gles2_Surface*)gles2_handle_get(s, surface_);
+
+ // FIXME: Not a very clean way..
+ uint32_t pixelsp = gles2_get_dword(s, fsurf->ddrawp + 4*sizeof(uint32_t));
+ if (pixelsp) {
+ unsigned nbytes = fsurf->ddraw.width
+ * fsurf->ddraw.height*fsurf->ddraw.bpp;
+ gles2_transfer_compile(&tfr, s, pixelsp, nbytes);
+ }
+ GLES2_BARRIER_ARG;
+
+ if (pixelsp) {
+// gles2_transfer(s, pixelsp, nbytes, fsurf->ddraw.pixels, 0);
+ gles2_transfer_exec(&tfr, s, fsurf->ddraw.pixels, 0);
+ }
+
+ EGLBoolean ret = eglBindTexImage(dpy, &fsurf->ddraw, buffer);
+ if (pixelsp) {
+ gles2_transfer_free(&tfr);
+ }
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, ret);
+}
+
+GLES2_CB(eglReleaseTexImage)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLSurface, surface_);
+ GLES2_ARG(TEGLint, buffer);
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ gles2_Surface* fsurf = (gles2_Surface*)gles2_handle_get(s, surface_);
+
+ EGLBoolean ret = eglReleaseTexImage(dpy, &fsurf->ddraw, buffer);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, ret);
+}
+
+GLES2_CB(eglCreateContext)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLConfig, config_);
+ GLES2_ARG(TEGLContext, share_context_);
+ GLES2_ARG(Tptr, attrib_listp);
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ EGLConfig config = (EGLConfig)gles2_handle_get(s, config_);
+ EGLContext share_context = (EGLContext)gles2_handle_get(s, share_context_);
+
+ GLES2_PRINT("TODO: Handle attribs...\n");
+ (void)attrib_listp;
+
+ GLES2_PRINT("Host context creation requested...\n");
+ EGLContext ctx;
+ if ((ctx = eglCreateContext(dpy, config,
+ share_context, NULL)) == EGL_NO_CONTEXT) {
+ GLES2_PRINT("\tContext creation failed!\n");
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLContext(s, 0);
+ return;
+ }
+ GLES2_PRINT("Created at %p!\n", ctx);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLContext(s, gles2_handle_create(s, ctx));
+}
+
+GLES2_CB(eglDestroyContext)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLContext, ctx_);
+ GLES2_BARRIER_ARG;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ EGLContext ctx = (EGLContext)gles2_handle_get(s, ctx_);
+ gles2_handle_free(s, ctx_);
+ GLES2_PRINT("Destroyed %p!\n", ctx);
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, eglDestroyContext(dpy, ctx));
+}
+
+// Host to guest vertex array copy.
+struct gles2_Array
+{
+ GLuint indx; // Parameter of the call.
+ GLint size; // --''--
+ GLenum type; // --''--
+ GLboolean normalized; // --''--
+ GLsizei stride; // --''--
+ Tptr tptr; // Pointer in the guest memory.
+ void* ptr; // Pointer in the host memory.
+
+ GLboolean enabled; // State.
+};
+
+GLES2_CB(eglMakeCurrent)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLSurface, draw_);
+ GLES2_ARG(TEGLSurface, read_);
+ GLES2_ARG(TEGLContext, ctx_);
+ GLES2_BARRIER_ARG;
+ int i;
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ gles2_Surface* draw = (EGLSurface)gles2_handle_get(s, draw_);
+ gles2_Surface* read = (EGLSurface)gles2_handle_get(s, read_);
+ EGLContext ctx = (EGLContext)gles2_handle_get(s, ctx_);
+
+ GLES2_PRINT("Making host context current...\n");
+
+ if (!eglMakeCurrent(dpy,
+ draw ? draw->surf : NULL,
+ read ? read->surf : NULL,
+ ctx)) {
+ GLES2_PRINT("\tMakeCurrent failed!\n");
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_FALSE);
+ return;
+ }
+
+ // Initialize client state.
+ if (ctx) {
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &c->narrays);
+
+ GLES2_PRINT("Maximum number of host vertex arrays: %d.\n", c->narrays);
+
+ c->arrays = malloc(c->narrays * sizeof(*c->arrays));
+ for (i = 0; i < c->narrays; ++i) {
+ c->arrays[i].type = GL_NONE;
+ c->arrays[i].enabled = 0;
+ c->arrays[i].ptr = 0;
+ }
+ }
+
+ GLES2_PRINT("Made %p current!\n", ctx);
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_TRUE);
+}
+
+GLES2_CB(eglSwapBuffers)
+{
+ GLES2_ARG(TEGLDisplay, dpy_);
+ GLES2_ARG(TEGLSurface, surface_);
+
+ EGLDisplay dpy = (EGLDisplay)gles2_handle_get(s, dpy_);
+ gles2_Surface* fsurf = (EGLSurface)gles2_handle_get(s, surface_);
+ if (!fsurf) {
+ fprintf(stderr, "ERROR: Trying to swap NULL surface!\n");
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_TRUE);
+ return;
+ }
+
+ if (gles2_surface_update(s, fsurf)) {
+ GLES2_BARRIER_ARG;
+ GLES2_PRINT("DIMENSIONS CHANGED!\n");
+ glFinish();
+ free(fsurf->ddraw.pixels);
+ unsigned nbytes = fsurf->ddraw.width
+ * fsurf->ddraw.height*fsurf->ddraw.bpp;
+ fsurf->ddraw.pixels = malloc(nbytes);
+
+ gles2_transfer_free(&fsurf->tfr);
+ GLES2_BARRIER_RET;
+ gles2_transfer_compile(&fsurf->tfr, s, fsurf->pixelsp, nbytes);
+ eglSwapBuffers(dpy, fsurf->surf);
+ gles2_ret_TEGLBoolean(s, EGL_TRUE);
+ return;
+ }
+ GLES2_BARRIER_ARG;
+
+ GLES2_PRINT("Swapping DGLES2 surfaces!\n");
+ eglSwapBuffers(dpy, fsurf->surf);
+
+ GLES2_PRINT("Transferring frame!\n");
+ gles2_transfer_exec(&fsurf->tfr, s, fsurf->ddraw.pixels, 1);
+ GLES2_PRINT("\tDone!\n");
+ GLES2_BARRIER_RET;
+ gles2_ret_TEGLBoolean(s, EGL_TRUE);
+}
+
+GLES2_CB(glClearColor)
+{
+ GLES2_ARG(TGLclampf, red);
+ GLES2_ARG(TGLclampf, green);
+ GLES2_ARG(TGLclampf, blue);
+ GLES2_ARG(TGLclampf, alpha);
+ GLES2_BARRIER_ARG_NORET;
+
+ glClearColor(red, green, blue, alpha);
+}
+
+
+GLES2_CB(glClear)
+{
+ GLES2_ARG(TGLbitfield, mask);
+ GLES2_BARRIER_ARG_NORET;
+
+ glClear(mask);
+}
+
+GLES2_CB(glDisableVertexAttribArray)
+{
+ GLES2_ARG(TGLuint, index);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("Disabling array %d\n", index);
+ c->arrays[index].enabled = 0;
+ glDisableVertexAttribArray(index);
+}
+
+static void fglTransferArrays(gles2_State *s, gles2_Client *c,
+ GLint first, GLsizei count)
+{
+ int i;
+
+ for(i = 0; i < c->narrays; ++i) {
+ gles2_Array* va = c->arrays + i;
+ if(!va->enabled) {
+ continue;
+ }
+ unsigned esize = 1;
+ switch (va->type) {
+ case GL_BYTE:
+ case GL_UNSIGNED_BYTE: esize = 1; break;
+ case GL_SHORT:
+ case GL_UNSIGNED_SHORT: esize = 2; break;
+ case GL_FIXED:
+ case GL_FLOAT: esize = 4; break;
+ }
+ if (!va->stride) {
+ va->stride = va->size*esize;
+ }
+
+ if (va->ptr) {
+ free(va->ptr);
+ }
+ unsigned nbytes = esize*count*va->size;
+ va->ptr = malloc(nbytes);
+
+ GLsizei j;
+ for (j = 0; j < count; ++j) {
+ signed k;
+ for (k = 0; k < va->size; ++k) {
+ switch (esize) {
+ case 1:
+ ((TGLubyte*)va->ptr)[j*va->size + k] =
+ gles2_get_byte(s, va->tptr + va->stride*(first + j)
+ + k*sizeof(TGLubyte));
+ break;
+ case 2:
+ ((TGLushort*)va->ptr)[j*va->size + k] =
+ gles2_get_word(s, va->tptr + va->stride*(first + j)
+ + k*sizeof(TGLushort));
+ break;
+ case 4:
+ if(va->type == GL_FLOAT) {
+ ((TGLfloat*)va->ptr)[j*va->size + k] =
+ gles2_get_float(s, va->tptr
+ + va->stride*(first + j)
+ + k*sizeof(TGLfloat));
+ } else {
+ ((TGLuint*)va->ptr)[j*va->size + k] =
+ gles2_get_dword(s, va->tptr
+ + va->stride*(first + j)
+ + k*sizeof(TGLuint));
+ }
+ break;
+ }
+ }
+ }
+
+ glVertexAttribPointer(va->indx, va->size, va->type,
+ va->normalized, 0, va->ptr);
+ GLenum error;
+
+ if ((error = glGetError()) != GL_NO_ERROR) {
+ GLES2_PRINT("glVertexAttribPointer(%d, %d, 0x%x, 0, %d, %p\n)"
+ " failed with 0x%x!\n", va->indx, va->size, va->type,
+ va->normalized, va->ptr, error);
+ }
+ }
+}
+
+GLES2_CB(glDrawArrays)
+{
+ GLES2_ARG(TGLenum, mode);
+ GLES2_ARG(TGLint, first);
+ GLES2_ARG(TGLsizei, count);
+
+ fglTransferArrays(s, c, first, count);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDrawArrays(mode, 0, count);
+}
+
+GLES2_CB(glDrawElements)
+{
+ GLES2_ARG(TGLenum, mode);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(TGLenum, type);
+ GLES2_ARG(Tptr, indicesp);
+
+ (void)indicesp;
+ (void)count;
+ (void)mode;
+
+ GLint indice_size;
+ switch (type) {
+ case GL_UNSIGNED_BYTE: indice_size = sizeof(TGLubyte); break;
+ case GL_UNSIGNED_SHORT: indice_size = sizeof(TGLushort); break;
+ default:
+ fprintf(stderr, "ERROR: Invalid type %d!\n", type);
+ return;
+ }
+
+ fglTransferArrays(s, c, (GLint)indicesp/indice_size, count);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDrawElements(mode, count, type, 0);
+}
+
+GLES2_CB(glEnableVertexAttribArray)
+{
+ GLES2_ARG(TGLuint, index);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("Enabling array %d\n", index);
+ c->arrays[index].enabled = 1;
+ glEnableVertexAttribArray(index);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname,
+ GLfloat* params)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname,
+ GLint* params)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv(GLuint index,
+ GLenum pname, void** pointer)
+{
+ DUMMY();
+}
+#endif //0
+
+GLES2_CB(glVertexAttrib1f)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib1f(indx, x);
+}
+
+GLES2_CB(glVertexAttrib1fv)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(Tptr, valuesp);
+ GLfloat x = gles2_get_float(s, valuesp);
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib1f(indx, x);
+}
+
+GLES2_CB(glVertexAttrib2f)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib2f(indx, x, y);
+}
+
+GLES2_CB(glVertexAttrib2fv)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(Tptr, valuesp);
+
+ GLfloat x = gles2_get_float(s, valuesp);
+ GLfloat y = gles2_get_float(s, valuesp + sizeof(TGLfloat));
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib2f(indx, x, y);
+}
+
+GLES2_CB(glVertexAttrib3f)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_ARG(TGLfloat, z);
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib3f(indx, x, y, z);
+}
+
+GLES2_CB(glVertexAttrib3fv)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(Tptr, valuesp);
+
+ GLfloat x = gles2_get_float(s, valuesp + 0*sizeof(TGLfloat));
+ GLfloat y = gles2_get_float(s, valuesp + 1*sizeof(TGLfloat));
+ GLfloat z = gles2_get_float(s, valuesp + 2*sizeof(TGLfloat));
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib3f(indx, x, y, z);
+}
+
+GLES2_CB(glVertexAttrib4f)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_ARG(TGLfloat, z);
+ GLES2_ARG(TGLfloat, w);
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib4f(indx, x, y, z, w);
+}
+
+GLES2_CB(glVertexAttrib4fv)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(Tptr, valuesp);
+
+ GLfloat x = gles2_get_float(s, valuesp + 0*sizeof(TGLfloat));
+ GLfloat y = gles2_get_float(s, valuesp + 1*sizeof(TGLfloat));
+ GLfloat z = gles2_get_float(s, valuesp + 2*sizeof(TGLfloat));
+ GLfloat w = gles2_get_float(s, valuesp + 3*sizeof(TGLfloat));
+ GLES2_BARRIER_ARG_NORET;
+
+ glVertexAttrib4f(indx, x, y, z, w);
+}
+
+GLES2_CB(glVertexAttribPointer)
+{
+ GLES2_ARG(TGLuint, indx);
+ GLES2_ARG(TGLint, size);
+ GLES2_ARG(TGLenum, type);
+ GLES2_ARG(TGLboolean, normalized);
+ GLES2_ARG(TGLsizei, stride);
+ GLES2_ARG(Tptr, tptr);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("Array %d at 0x%x (%d elements every %d bytes)\n",
+ indx, tptr, size, stride);
+
+ gles2_Array *va = c->arrays + indx;
+ va->type = type;
+ va->indx = indx;
+ va->size = size;
+ va->normalized = normalized;
+ va->stride = stride;
+ va->tptr = tptr;
+}
+
+static unsigned gles2_glGetCount(TGLenum pname)
+{
+ unsigned count;
+ switch(pname) {
+ case GL_ACTIVE_TEXTURE: count = 1; break;
+ case GL_ALIASED_LINE_WIDTH_RANGE: count = 2; break;
+ case GL_ALIASED_POINT_SIZE_RANGE: count = 2; break;
+ case GL_ALPHA_BITS: count = 1; break;
+ case GL_ARRAY_BUFFER_BINDING: count = 1; break;
+ case GL_BLEND: count = 1; break;
+ case GL_BLEND_COLOR: count = 4; break;
+ case GL_BLEND_DST_ALPHA: count = 1; break;
+ case GL_BLEND_DST_RGB: count = 1; break;
+ case GL_BLEND_EQUATION_ALPHA: count = 1; break;
+ case GL_BLEND_EQUATION_RGB: count = 1; break;
+ case GL_BLEND_SRC_ALPHA: count = 1; break;
+ case GL_BLEND_SRC_RGB: count = 1; break;
+ case GL_BLUE_BITS: count = 1; break;
+ case GL_COLOR_CLEAR_VALUE: count = 4; break;
+ case GL_COLOR_WRITEMASK: count = 4; break;
+ case GL_COMPRESSED_TEXTURE_FORMATS: count = GL_NUM_COMPRESSED_TEXTURE_FORMATS; break;
+ case GL_CULL_FACE: count = 1; break;
+ case GL_CULL_FACE_MODE: count = 1; break;
+ case GL_CURRENT_PROGRAM: count = 1; break;
+ case GL_DEPTH_BITS: count = 1; break;
+ case GL_DEPTH_CLEAR_VALUE: count = 1; break;
+ case GL_DEPTH_FUNC: count = 1; break;
+ case GL_DEPTH_RANGE: count = 2; break;
+ case GL_DEPTH_TEST: count = 1; break;
+ case GL_DEPTH_WRITEMASK: count = 1; break;
+ case GL_DITHER: count = 1; break;
+ case GL_ELEMENT_ARRAY_BUFFER_BINDING: count = 1; break;
+ case GL_FRAMEBUFFER_BINDING: count = 1; break;
+ case GL_FRONT_FACE: count = 1; break;
+ case GL_GENERATE_MIPMAP_HINT: count = 1; break;
+ case GL_GREEN_BITS: count = 1; break;
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT: count = 1; break;
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE: count = 1; break;
+ case GL_LINE_WIDTH: count = 1; break;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: count = 1; break;
+ case GL_MAX_CUBE_MAP_TEXTURE_SIZE: count = 1; break;
+ case GL_MAX_FRAGMENT_UNIFORM_VECTORS: count = 1; break;
+ case GL_MAX_RENDERBUFFER_SIZE: count = 1; break;
+ case GL_MAX_TEXTURE_IMAGE_UNITS: count = 1; break;
+ case GL_MAX_TEXTURE_SIZE: count = 1; break;
+ case GL_MAX_VARYING_VECTORS: count = 1; break;
+ case GL_MAX_VERTEX_ATTRIBS: count = 1; break;
+ case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: count = 1; break;
+ case GL_MAX_VERTEX_UNIFORM_VECTORS: count = 1; break;
+ case GL_MAX_VIEWPORT_DIMS: count = 2; break;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS: count = 1; break;
+ case GL_NUM_SHADER_BINARY_FORMATS: count = 1; break;
+ case GL_PACK_ALIGNMENT: count = 1; break;
+ case GL_POLYGON_OFFSET_FACTOR: count = 1; break;
+ case GL_POLYGON_OFFSET_FILL: count = 1; break;
+ case GL_POLYGON_OFFSET_UNITS: count = 1; break;
+ case GL_RED_BITS: count = 1; break;
+ case GL_RENDERBUFFER_BINDING: count = 1; break;
+ case GL_SAMPLE_BUFFERS: count = 1; break;
+ case GL_SAMPLE_COVERAGE_INVERT: count = 1; break;
+ case GL_SAMPLE_COVERAGE_VALUE: count = 1; break;
+ case GL_SAMPLES: count = 1; break;
+ case GL_SCISSOR_BOX: count = 4; break;
+ case GL_SCISSOR_TEST: count = 1; break;
+ case GL_SHADER_BINARY_FORMATS: count = GL_NUM_SHADER_BINARY_FORMATS; break;
+ case GL_SHADER_COMPILER: count = 1; break;
+ case GL_STENCIL_BACK_FAIL: count = 1; break;
+ case GL_STENCIL_BACK_FUNC: count = 1; break;
+ case GL_STENCIL_BACK_PASS_DEPTH_FAIL: count = 1; break;
+ case GL_STENCIL_BACK_PASS_DEPTH_PASS: count = 1; break;
+ case GL_STENCIL_BACK_REF: count = 1; break;
+ case GL_STENCIL_BACK_VALUE_MASK: count = 1; break;
+ case GL_STENCIL_BACK_WRITEMASK: count = 1; break;
+ case GL_STENCIL_BITS: count = 1; break;
+ case GL_STENCIL_CLEAR_VALUE: count = 1; break;
+ case GL_STENCIL_FAIL: count = 1; break;
+ case GL_STENCIL_FUNC: count = 1; break;
+ case GL_STENCIL_PASS_DEPTH_FAIL: count = 1; break;
+ case GL_STENCIL_PASS_DEPTH_PASS: count = 1; break;
+ case GL_STENCIL_REF: count = 1; break;
+ case GL_STENCIL_TEST: count = 1; break;
+ case GL_STENCIL_VALUE_MASK: count = 1; break;
+ case GL_STENCIL_WRITEMASK: count = 1; break;
+ case GL_SUBPIXEL_BITS: count = 1; break;
+ case GL_TEXTURE_BINDING_2D: count = 1; break;
+ case GL_TEXTURE_BINDING_CUBE_MAP: count = 1; break;
+ case GL_UNPACK_ALIGNMENT: count = 1; break;
+ case GL_VIEWPORT: count = 4; break;
+ default:
+ GLES2_PRINT("ERROR: Unknown pname 0x%x in glGet!\n", pname);
+ count = 1;
+ break;
+ }
+
+ GLES2_PRINT("glGet(0x%x) -> %u!\n", pname, count);
+
+ return count;
+}
+
+GLES2_CB(glGetBooleanv)
+{
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLboolean params[4];
+ glGetBooleanv(pname, params);
+ unsigned const count = gles2_glGetCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ gles2_put_TGLboolean(s, paramsp + i*sizeof(TGLboolean), params[i]);
+ }
+}
+
+GLES2_CB(glGetError)
+{
+ GLES2_BARRIER_ARG;
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLenum(s, glGetError());
+}
+
+GLES2_CB(eglGetError)
+{
+ GLES2_BARRIER_ARG;
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLint(s, eglGetError());
+}
+
+GLES2_CB(glGetFloatv)
+{
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLfloat params[4];
+ glGetFloatv(pname, params);
+ unsigned const count = gles2_glGetCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ gles2_put_TGLfloat(s, paramsp + i*sizeof(TGLfloat), params[i]);
+ }
+}
+
+GLES2_CB(glGetIntegerv)
+{
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLint params[4];
+ glGetIntegerv(pname, params);
+ unsigned const count = gles2_glGetCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ gles2_put_TGLint(s, paramsp + i*sizeof(TGLint), params[i]);
+ }
+}
+
+GLES2_CB(glColorMask)
+{
+ GLES2_ARG(TGLboolean, red);
+ GLES2_ARG(TGLboolean, green);
+ GLES2_ARG(TGLboolean, blue);
+ GLES2_ARG(TGLboolean, alpha);
+ GLES2_BARRIER_ARG_NORET;
+
+ glColorMask(red, green, blue, alpha);
+}
+
+GLES2_CB(glCullFace)
+{
+ GLES2_ARG(TGLenum, mode);
+ GLES2_BARRIER_ARG_NORET;
+
+ glCullFace(mode);
+}
+
+GLES2_CB(glDisable)
+{
+ GLES2_ARG(TGLenum, cap);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDisable(cap);
+}
+
+GLES2_CB(glEnable)
+{
+ GLES2_ARG(TGLenum, cap);
+ GLES2_BARRIER_ARG_NORET;
+
+ glEnable(cap);
+}
+
+GLES2_CB(glFinish)
+{
+ GLES2_BARRIER_ARG_NORET;
+ glFinish();
+}
+
+GLES2_CB(glFlush)
+{
+ GLES2_BARRIER_ARG_NORET;
+ glFlush();
+}
+
+GLES2_CB(glFrontFace)
+{
+ GLES2_ARG(TGLenum, mode);
+ GLES2_BARRIER_ARG_NORET;
+
+ glFrontFace(mode);
+}
+
+GLES2_CB(glIsEnabled)
+{
+ GLES2_ARG(TGLenum, cap);
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLboolean(s, glIsEnabled(cap));
+}
+
+GLES2_CB(glHint)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, mode);
+ GLES2_BARRIER_ARG_NORET;
+
+ if(s->quality <= 75)
+ {
+ switch(target)
+ {
+ default: mode = GL_FASTEST; break;
+ }
+ }
+
+ glHint(target, mode);
+}
+
+GLES2_CB(glLineWidth)
+{
+ GLES2_ARG(TGLfloat, width);
+ GLES2_BARRIER_ARG_NORET;
+
+ glLineWidth(width);
+}
+
+GLES2_CB(glPolygonOffset)
+{
+ GLES2_ARG(TGLfloat, factor);
+ GLES2_ARG(TGLfloat, units);
+ GLES2_BARRIER_ARG_NORET;
+
+ glPolygonOffset(factor, units);
+}
+
+GLES2_CB(glSampleCoverage)
+{
+ GLES2_ARG(TGLclampf, value);
+ GLES2_ARG(TGLboolean, invert);
+ GLES2_BARRIER_ARG_NORET;
+
+ glSampleCoverage(value, invert);
+}
+
+GLES2_CB(glScissor)
+{
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_BARRIER_ARG_NORET;
+
+ glScissor(x, y, width, height);
+}
+
+GLES2_CB(glViewport)
+{
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_BARRIER_ARG_NORET;
+
+ glViewport(x, y, width, height);
+}
+
+GLES2_CB(glActiveTexture)
+{
+ GLES2_ARG(TGLenum, texture);
+ GLES2_BARRIER_ARG_NORET;
+
+ glActiveTexture(texture);
+}
+
+GLES2_CB(glBindTexture)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLuint, texture);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBindTexture(target, texture);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D(GLenum target,
+ GLint level, GLenum internalformat, GLsizei width, GLsizei height,
+ GLint border, GLsizei imageSize, const void* data)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D(GLenum target,
+ GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize, const void* data)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glCopyTexImage2D(GLenum target, GLint level,
+ GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D(GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint x, GLint y,
+ GLsizei width, GLsizei height)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glDeleteTextures)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, texturesp);
+
+ GLsizei i;
+ GLuint* textures = (GLuint*)malloc(sizeof(GLuint)*n);
+ for(i = 0; i < n; ++i) {
+ textures[i] = gles2_get_TGLuint(s, texturesp + i*sizeof(TGLuint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glDeleteTextures(n, textures);
+ free(textures);
+}
+
+GLES2_CB(glGenerateMipmap)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_BARRIER_ARG_NORET;
+
+ glGenerateMipmap(target);
+}
+
+GLES2_CB(glGenTextures)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, texturesp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLsizei i;
+ GLuint* textures = (GLuint*)malloc(sizeof(GLuint)*n);
+ glGenTextures(n, textures);
+ for(i = 0; i < n; ++i) {
+ gles2_put_TGLuint(s, texturesp + i*sizeof(TGLuint), textures[i]);
+ }
+ free(textures);
+}
+
+static unsigned gles2_glTexParameterCount(GLenum pname)
+{
+ unsigned count;
+
+ switch(pname) {
+ case GL_TEXTURE_MIN_FILTER: count = 1; break;
+ case GL_TEXTURE_MAG_FILTER: count = 1; break;
+ case GL_TEXTURE_WRAP_S: count = 1; break;
+ case GL_TEXTURE_WRAP_T: count = 1; break;
+ default:
+ GLES2_PRINT("ERROR: Unknown texture parameter 0x%x!\n", pname);
+ count = 1;
+ break;
+ }
+
+ return count;
+}
+
+GLES2_CB(glGetTexParameterfv)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLfloat params[4];
+ glGetTexParameterfv(target, pname, params);
+ unsigned const count = gles2_glTexParameterCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ gles2_put_TGLfloat(s, paramsp + i*sizeof(TGLfloat), params[i]);
+ }
+}
+
+GLES2_CB(glGetTexParameteriv)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLint params[4];
+ glGetTexParameteriv(target, pname, params);
+ unsigned const count = gles2_glTexParameterCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ gles2_put_TGLint(s, paramsp + i*sizeof(TGLint), params[i]);
+ }
+}
+
+GLES2_CB(glIsTexture)
+{
+ GLES2_ARG(TGLuint, texture);
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLboolean(s, glIsTexture(texture));
+}
+
+GLES2_CB(glReadPixels)
+{
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_ARG(TGLenum, format);
+ GLES2_ARG(TGLenum, type);
+ GLES2_ARG(Tptr, pixelsp);
+ GLES2_BARRIER_ARG;
+
+ unsigned bpp;
+ switch (format) {
+ case GL_ALPHA: bpp = 1; break;
+ case GL_RGB: bpp = (type == GL_UNSIGNED_BYTE) ? 3 : 2; break;
+ case GL_RGBA: bpp = (type == GL_UNSIGNED_BYTE) ? 4 : 2; break;
+ case GL_LUMINANCE: bpp = 1; break;
+ case GL_LUMINANCE_ALPHA: bpp = 2; break;
+ default:
+ GLES2_PRINT("ERROR: Unknown format 0x%x...\n", format);
+ bpp = 1;
+ break;
+ }
+
+ GLES2_PRINT("Reading %dx%dx%d image at %d,%d...\n",
+ width, height, bpp, x, y);
+ char* pixels = NULL;
+ unsigned nbytes = width*height*bpp;
+ pixels = malloc(nbytes);
+
+ glReadPixels(x, y, width, height, format, type, pixels);
+ GLES2_BARRIER_RET;
+ gles2_transfer(s, pixelsp, nbytes, pixels, 1);
+ free(pixels);
+}
+
+GLES2_CB(glTexImage2D)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLint, level);
+ GLES2_ARG(TGLint, internalformat);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_ARG(TGLint, border);
+ GLES2_ARG(TGLenum, format);
+ GLES2_ARG(TGLenum, type);
+ GLES2_ARG(Tptr, pixelsp);
+
+ unsigned bpp;
+
+ switch(format) {
+ case GL_ALPHA: bpp = 1; break;
+ case GL_RGB: bpp = (type == GL_UNSIGNED_BYTE) ? 3 : 2; break;
+ case GL_RGBA: bpp = (type == GL_UNSIGNED_BYTE) ? 4 : 2; break;
+ case GL_LUMINANCE: bpp = 1; break;
+ case GL_LUMINANCE_ALPHA: bpp = 2; break;
+ default:
+ GLES2_PRINT("ERROR: Unknown format 0x%x...\n", format);
+ bpp = 1;
+ break;
+ }
+
+ GLES2_PRINT("Uploading %dx%dx%d image...\n", width, height, bpp);
+ char* pixels = NULL;
+ if (pixelsp) {
+ unsigned nbytes = width*height*bpp;
+ pixels = malloc(nbytes);
+ gles2_transfer(s, pixelsp, nbytes, pixels, 0);
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+ free(pixels);
+}
+
+GLES2_CB(glTexParameterf)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(TGLfloat, param);
+ GLES2_BARRIER_ARG_NORET;
+
+ glTexParameterf(target, pname, param);
+}
+
+GLES2_CB(glTexParameterfv)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+
+ GLfloat params[4];
+ unsigned const count = gles2_glTexParameterCount(pname);
+ unsigned i;
+ for (i = 0; i < count; ++i) {
+ params[i] = gles2_get_TGLfloat(s, paramsp + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glTexParameterfv(target, pname, params);
+}
+
+GLES2_CB(glTexParameteri)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(TGLint, param);
+ GLES2_BARRIER_ARG_NORET;
+
+ if(s->quality <= 50)
+ {
+ switch(pname)
+ {
+ case GL_TEXTURE_MIN_FILTER: param = GL_NEAREST; break;
+ case GL_TEXTURE_MAG_FILTER: param = GL_NEAREST; break;
+ default: break;
+ }
+ }
+
+ glTexParameterf(target, pname, param);
+}
+
+GLES2_CB(glTexParameteriv)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+
+ GLint params[4];
+ unsigned const count = gles2_glTexParameterCount(pname);
+ unsigned i;
+ for(i = 0; i < count; ++i) {
+ params[i] = gles2_get_TGLint(s, paramsp + i*sizeof(GLint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glTexParameteriv(target, pname, params);
+}
+
+GLES2_CB(glTexSubImage2D)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLint, level);
+ GLES2_ARG(TGLint, xoffset);
+ GLES2_ARG(TGLint, yoffset);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_ARG(TGLenum, format);
+ GLES2_ARG(TGLenum, type);
+ GLES2_ARG(Tptr, pixelsp);
+
+ unsigned bpp;
+ switch (format) {
+ case GL_ALPHA: bpp = 1; break;
+ case GL_RGB: bpp = (type == GL_UNSIGNED_BYTE) ? 3 : 2; break;
+ case GL_RGBA: bpp = (type == GL_UNSIGNED_BYTE) ? 4 : 2; break;
+ case GL_LUMINANCE: bpp = 1; break;
+ case GL_LUMINANCE_ALPHA: bpp = 2; break;
+ default:
+ GLES2_PRINT("ERROR: Unknown format 0x%x...\n", format);
+ bpp = 1;
+ break;
+ }
+
+ GLES2_PRINT("Uploading partial %dx%dx%d image at %d,%d...\n",
+ width, height, bpp, xoffset, yoffset);
+
+ unsigned nbytes = width*height*bpp;
+ char* pixels = malloc(nbytes);
+ gles2_transfer(s, pixelsp, nbytes, pixels, 0);
+ GLES2_BARRIER_ARG_NORET;
+
+ glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+ free(pixels);
+}
+
+
+GLES2_CB(glCompileShader)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_BARRIER_ARG_NORET;
+
+ glCompileShader(shader);
+}
+
+GLES2_CB(glCreateShader)
+{
+ GLES2_ARG(TGLenum, type);
+ GLES2_BARRIER_ARG_NORET;
+
+ gles2_ret_TGLuint(s, glCreateShader(type));
+}
+
+GLES2_CB(glDeleteShader)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDeleteShader(shader);
+}
+
+GLES2_CB(glIsShader)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLboolean(s, glIsShader(shader));
+}
+
+GLES2_CB(glGetShaderiv)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLint param;
+ glGetShaderiv(shader, pname, ¶m);
+ gles2_put_TGLint(s, paramsp, param);
+}
+
+GLES2_CB(glGetShaderInfoLog)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_ARG(TGLsizei, bufsize);
+ GLES2_ARG(Tptr, lengthp);
+ GLES2_ARG(Tptr, infologp);
+
+ GLsizei length = gles2_get_TGLsizei(s, lengthp);
+ char* infolog = malloc(bufsize);
+ glGetShaderInfoLog(shader, bufsize, &length, infolog);
+ gles2_transfer(s, infologp, length, infolog, 1);
+ gles2_put_TGLsizei(s, lengthp, length);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("shader %d infolog:\n%.*s\n", shader, length, infolog);
+ free(infolog);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype,
+ GLenum precisiontype, GLint* range, GLint* precision)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize,
+ GLsizei* length, char* source)
+{
+ DUMMY();
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsShader(GLuint shader)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler(void)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders,
+ GLenum binaryformat, const void* binary, GLsizei length)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glShaderSource)
+{
+ GLES2_ARG(TGLuint, shader);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, stringp);
+ GLES2_ARG(Tptr, lengthp);
+
+ char** string_fgl = malloc(sizeof(char*)*count);
+ GLint* length_fgl = malloc(sizeof(GLint)*count);
+
+ unsigned i;
+ for (i = 0; i < count; ++i) {
+ length_fgl[i] = gles2_get_TGLint(s, lengthp + i*sizeof(TGLint));
+ string_fgl[i] = malloc(length_fgl[i] + 1);
+ gles2_transfer(s, gles2_get_dword(s, stringp + i*sizeof(Tptr)),
+ length_fgl[i], string_fgl[i], 0);
+ string_fgl[i][length_fgl[i]] = 0;
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("shader %d source:\n", shader);
+ #if(GLES2_DEBUG == 1)
+ for(i = 0; i < count; ++i) {
+ fprintf(stderr, "%.*s", length_fgl[i], string_fgl[i]);
+ }
+ #endif // GLES2_DEBUG == 1
+ GLES2_PRINT("\n--END--");
+
+ glShaderSource(shader, (GLsizei)count,
+ (const char**)string_fgl, length_fgl);
+
+ for (i = 0; i < count; ++i) {
+ free(string_fgl[i]);
+ }
+
+ free(string_fgl);
+ free(length_fgl);
+}
+
+GLES2_CB(glAttachShader)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(TGLuint, shader);
+ GLES2_BARRIER_ARG_NORET;
+
+ glAttachShader(program, shader);
+}
+
+GLES2_CB(glBindAttribLocation)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(TGLuint, index);
+ GLES2_ARG(Tptr, namep);
+
+ char name[120];
+ Tptr i;
+
+ for(i = 0; (name[i] = gles2_get_byte(s, namep + i)) ; ++i);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLES2_PRINT("Binding attribute %s at %d...\n", name, index);
+ glBindAttribLocation(program, index, name);
+}
+
+GLES2_CB(glCreateProgram)//(void)
+{
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLuint(s, glCreateProgram());
+}
+
+GLES2_CB(glDeleteProgram)//(GLuint program)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDeleteProgram(program);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glDetachShader(GLuint program, GLuint shader)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index,
+ GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index,
+ GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program,
+ GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glGetAttribLocation)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(Tptr, namep);
+
+ char name[120];
+ Tptr i;
+
+ for (i = 0; (name[i] = gles2_get_byte(s, namep + i)) ; ++i);
+
+ GLES2_PRINT("Getting attribute %s location...\n", name);
+
+ gles2_ret_TGLint(s, glGetAttribLocation(program, name));
+ GLES2_BARRIER_ARG_NORET;
+}
+
+GLES2_CB(glGetProgramiv)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(Tptr, paramsp);
+ GLES2_BARRIER_ARG_NORET;
+
+ GLint param;
+
+ glGetProgramiv(program, pname, ¶m);
+ gles2_put_TGLint(s, paramsp, param);
+}
+
+GLES2_CB(glGetProgramInfoLog)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(TGLsizei, bufsize);
+ GLES2_ARG(Tptr, lengthp);
+ GLES2_ARG(Tptr, infologp);
+
+ GLsizei length = gles2_get_TGLsizei(s, lengthp);
+ char* infolog = malloc(bufsize);
+ glGetProgramInfoLog(program, bufsize, &length, infolog);
+ gles2_transfer(s, infologp, length, infolog, 1);
+ gles2_put_TGLsizei(s, lengthp, length);
+ GLES2_BARRIER_ARG_NORET;
+ GLES2_PRINT("program %d infolog:\n%.*s\n", program, length, infolog);
+ free(infolog);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+{
+ DUMMY();
+}
+
+GL_APICALL void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glGetUniformLocation)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_ARG(Tptr, namep);
+
+ char name[120];
+ Tptr i;
+
+ for (i = 0; (name[i] = gles2_get_byte(s, namep + i)) ; ++i);
+
+ GLES2_PRINT("Getting uniform %s location...\n", name);
+
+ gles2_ret_TGLint(s, glGetUniformLocation(program, name));
+ GLES2_BARRIER_ARG_NORET;
+}
+
+GLES2_CB(glIsProgram)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLboolean(s, glIsProgram(program));
+}
+
+GLES2_CB(glLinkProgram)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_BARRIER_ARG_NORET;
+
+ glLinkProgram(program);
+}
+
+GLES2_CB(glUniform1f)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform1f(location, x);
+}
+
+GLES2_CB(glUniform1fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*1;
+ GLfloat* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+
+ for (i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLint(s, vp + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform1fv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform1i)//(GLint location, GLint x)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, x);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform1i(location, x);
+}
+
+GLES2_CB(glUniform1iv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*1;
+ GLint* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for (i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLint(s, vp + i*sizeof(TGLint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform1iv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform2f)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform2f(location, x, y);
+}
+
+GLES2_CB(glUniform2fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*2;
+ GLfloat* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for (i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLfloat(s, vp + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform2fv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform2i)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform2i(location, x, y);
+}
+
+GLES2_CB(glUniform2iv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*2;
+ GLint* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for (i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLint(s, vp + i*sizeof(TGLint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform2iv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform3f)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_ARG(TGLfloat, z);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform3f(location, x, y, z);
+}
+
+GLES2_CB(glUniform3fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*3;
+ GLfloat* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for(i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLfloat(s, vp + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform3fv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform3i)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_ARG(TGLint, z);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform3i(location, x, y, z);
+}
+
+GLES2_CB(glUniform3iv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*3;
+ GLint* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for(i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLint(s, vp + i*sizeof(TGLint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform3iv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform4f)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLfloat, x);
+ GLES2_ARG(TGLfloat, y);
+ GLES2_ARG(TGLfloat, z);
+ GLES2_ARG(TGLfloat, w);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform4f(location, x, y, z, w);
+}
+
+GLES2_CB(glUniform4fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*4;
+ GLfloat* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for(i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLfloat(s, vp + i*sizeof(TGLfloat));
+ }
+
+ GLES2_BARRIER_ARG_NORET;
+ glUniform4fv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniform4i)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, x);
+ GLES2_ARG(TGLint, y);
+ GLES2_ARG(TGLint, z);
+ GLES2_ARG(TGLint, w);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniform4i(location, x, y, z, w);
+}
+
+GLES2_CB(glUniform4iv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLsizei, count);
+ GLES2_ARG(Tptr, vp);
+
+ unsigned nvs = count*4;
+ GLint* v = malloc(nvs*sizeof(*v));
+ unsigned i;
+ for(i = 0; i < nvs; ++i) {
+ v[i] = gles2_get_TGLint(s, vp + i*sizeof(TGLint));
+ }
+
+ GLES2_BARRIER_ARG_NORET;
+ glUniform4iv(location, count, v);
+ free(v);
+}
+
+GLES2_CB(glUniformMatrix2fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, count);
+ GLES2_ARG(TGLboolean, transpose);
+ GLES2_ARG(Tptr, valuep);
+
+ unsigned nfloats = 2*2*count;
+ GLfloat* value = malloc(nfloats*sizeof(TGLfloat));
+ unsigned i;
+
+ for (i = 0; i < nfloats; ++i) {
+ value[i] = gles2_get_TGLfloat(s, valuep + i*sizeof(TGLfloat));
+ }
+
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniformMatrix2fv(location, count, transpose, value);
+ free(value);
+}
+
+GLES2_CB(glUniformMatrix3fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, count);
+ GLES2_ARG(TGLboolean, transpose);
+ GLES2_ARG(Tptr, valuep);
+
+ unsigned nfloats = 3*3*count;
+ GLfloat* value = malloc(nfloats*sizeof(TGLfloat));
+ unsigned i;
+ for(i = 0; i < nfloats; ++i) {
+ value[i] = gles2_get_TGLfloat(s, valuep + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniformMatrix3fv(location, count, transpose, value);
+ free(value);
+}
+
+GLES2_CB(glUniformMatrix4fv)
+{
+ GLES2_ARG(TGLint, location);
+ GLES2_ARG(TGLint, count);
+ GLES2_ARG(TGLboolean, transpose);
+ GLES2_ARG(Tptr, valuep);
+
+ unsigned nfloats = 4*4*count;
+ GLfloat* value = malloc(nfloats*sizeof(TGLfloat));
+ unsigned i;
+ for(i = 0; i < nfloats; ++i) {
+ value[i] = gles2_get_TGLfloat(s, valuep + i*sizeof(TGLfloat));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glUniformMatrix4fv(location, count, transpose, value);
+ free(value);
+}
+
+GLES2_CB(glUseProgram)
+{
+ GLES2_ARG(TGLuint, program);
+ GLES2_BARRIER_ARG_NORET;
+
+ glUseProgram(program);
+}
+
+GLES2_CB(glBlendColor)
+{
+ GLES2_ARG(TGLclampf, red);
+ GLES2_ARG(TGLclampf, green);
+ GLES2_ARG(TGLclampf, blue);
+ GLES2_ARG(TGLclampf, alpha);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBlendColor(red, green, blue, alpha);
+}
+
+GLES2_CB(glBlendEquation)
+{
+ GLES2_ARG(TGLenum, mode);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBlendEquation(mode);
+}
+
+GLES2_CB(glBlendEquationSeparate)
+{
+ GLES2_ARG(TGLenum, modeRGB);
+ GLES2_ARG(TGLenum, modeAlpha);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBlendEquationSeparate(modeRGB, modeAlpha);
+}
+
+GLES2_CB(glBlendFunc)
+{
+ GLES2_ARG(TGLenum, sfactor);
+ GLES2_ARG(TGLenum, dfactor);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBlendFunc(sfactor, dfactor);
+}
+
+GLES2_CB(glBlendFuncSeparate)
+{
+ GLES2_ARG(TGLenum, srcRGB);
+ GLES2_ARG(TGLenum, dstRGB);
+ GLES2_ARG(TGLenum, srcAlpha);
+ GLES2_ARG(TGLenum, dstAlpha);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+GLES2_CB(glPixelStorei)
+{
+ GLES2_ARG(TGLenum, pname);
+ GLES2_ARG(TGLint, param);
+ GLES2_BARRIER_ARG_NORET;
+
+ glPixelStorei(pname, param);
+}
+
+#if 0
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glClearStencil)
+{
+ GLES2_ARG(TGLint, s_);
+ GLES2_BARRIER_ARG_NORET;
+
+ glClearStencil(s_);
+}
+
+GLES2_CB(glStencilFunc)
+{
+ GLES2_ARG(TGLenum, func);
+ GLES2_ARG(TGLint, ref);
+ GLES2_ARG(TGLuint, mask);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilFunc(func, ref, mask);
+}
+
+GLES2_CB(glStencilFuncSeparate)
+{
+ GLES2_ARG(TGLenum, face);
+ GLES2_ARG(TGLenum, func);
+ GLES2_ARG(TGLint, ref);
+ GLES2_ARG(TGLuint, mask);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilFuncSeparate(face, func, ref, mask);
+}
+
+GLES2_CB(glStencilMask)
+{
+ GLES2_ARG(TGLuint, mask);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilMask(mask);
+}
+
+GLES2_CB(glStencilMaskSeparate)
+{
+ GLES2_ARG(TGLenum, face);
+ GLES2_ARG(TGLuint, mask);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilMaskSeparate(face, mask);
+}
+
+GLES2_CB(glStencilOp)
+{
+ GLES2_ARG(TGLenum, fail);
+ GLES2_ARG(TGLenum, zfail);
+ GLES2_ARG(TGLenum, zpass);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilOp(fail, zfail, zpass);
+}
+
+GLES2_CB(glStencilOpSeparate)
+{
+ GLES2_ARG(TGLenum, face);
+ GLES2_ARG(TGLenum, fail);
+ GLES2_ARG(TGLenum, zfail);
+ GLES2_ARG(TGLenum, zpass);
+ GLES2_BARRIER_ARG_NORET;
+
+ glStencilOpSeparate(face, fail, zfail, zpass);
+}
+
+GLES2_CB(glBindFramebuffer)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLuint, framebuffer);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBindFramebuffer(target, framebuffer);
+}
+
+GLES2_CB(glBindRenderbuffer)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLuint, renderbuffer);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBindRenderbuffer(target, renderbuffer);
+}
+
+GLES2_CB(glCheckFramebufferStatus)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_BARRIER_ARG;
+
+ GLES2_BARRIER_RET;
+ gles2_ret_TGLenum(s, glCheckFramebufferStatus(target));
+}
+
+GLES2_CB(glDeleteFramebuffers)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, framebuffersp);
+
+ GLsizei i;
+ GLuint* framebuffers = (GLuint*)malloc(sizeof(GLuint)*n);
+
+ for (i = 0; i < n; ++i) {
+ framebuffers[i] = gles2_get_TGLuint(s,
+ framebuffersp + i*sizeof(TGLuint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glDeleteFramebuffers(n, framebuffers);
+ free(framebuffers);
+}
+
+GLES2_CB(glDeleteRenderbuffers)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, renderbuffersp);
+
+ GLsizei i;
+ GLuint* renderbuffers = (GLuint*)malloc(sizeof(GLuint)*n);
+
+ for (i = 0; i < n; ++i) {
+ renderbuffers[i] = gles2_get_TGLuint(s,
+ renderbuffersp + i*sizeof(TGLuint));
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ glDeleteRenderbuffers(n, renderbuffers);
+ free(renderbuffers);
+}
+
+GLES2_CB(glFramebufferRenderbuffer)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, attachment);
+ GLES2_ARG(TGLenum, renderbuffertarget);
+ GLES2_ARG(TGLuint, renderbuffer);
+ GLES2_BARRIER_ARG_NORET;
+
+ glFramebufferRenderbuffer(target, attachment,
+ renderbuffertarget, renderbuffer);
+}
+
+GLES2_CB(glFramebufferTexture2D)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, attachment);
+ GLES2_ARG(TGLenum, textarget);
+ GLES2_ARG(TGLuint, texture);
+ GLES2_ARG(TGLint, level);
+ GLES2_BARRIER_ARG_NORET;
+
+ glFramebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+GLES2_CB(glGenFramebuffers)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, framebuffersp);
+
+ GLsizei i;
+ GLuint* framebuffers = (GLuint*)malloc(sizeof(GLuint)*n);
+
+ glGenFramebuffers(n, framebuffers);
+ for(i = 0; i < n; ++i) {
+ gles2_put_TGLuint(s, framebuffersp + i*sizeof(TGLuint),
+ framebuffers[i]);
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ free(framebuffers);
+}
+
+GLES2_CB(glGenRenderbuffers)//(GLsizei n, GLuint* renderbuffers)
+{
+ GLES2_ARG(TGLsizei, n);
+ GLES2_ARG(Tptr, renderbuffersp);
+
+ GLsizei i;
+ GLuint* renderbuffers = (GLuint*)malloc(sizeof(GLuint)*n);
+
+ glGenRenderbuffers(n, renderbuffers);
+ for(i = 0; i < n; ++i) {
+ gles2_put_TGLuint(s, renderbuffersp + i*sizeof(TGLuint),
+ renderbuffers[i]);
+ }
+ GLES2_BARRIER_ARG_NORET;
+
+ free(renderbuffers);
+}
+
+#if 0
+GLES2_CB(glGetFramebufferAttachmentParameteriv)//(GLenum target,
+ GLenum attachment, GLenum pname, GLint* params)
+{
+ DUMMY();
+}
+
+GLES2_CB(glGetRenderbufferParameteriv)//(GLenum target, GLenum pname,
+ GLint* params)
+{
+ DUMMY();
+}
+
+GLES2_CB(glIsFramebuffer)//(GLuint framebuffer)
+{
+ DUMMY();
+}
+
+GLES2_CB(glIsRenderbuffer)//(GLuint renderbuffer)
+{
+ DUMMY();
+}
+#endif // 0
+
+GLES2_CB(glBindBuffer)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLuint, buffer);
+ GLES2_BARRIER_ARG_NORET;
+
+ glBindTexture(target, buffer);
+}
+
+
+GLES2_CB(glRenderbufferStorage)
+{
+ GLES2_ARG(TGLenum, target);
+ GLES2_ARG(TGLenum, internalformat);
+ GLES2_ARG(TGLsizei, width);
+ GLES2_ARG(TGLsizei, height);
+ GLES2_BARRIER_ARG_NORET;
+
+ glRenderbufferStorage(target, internalformat, width, height);
+}
+
+GLES2_CB(glDepthFunc)
+{
+ GLES2_ARG(TGLenum, func);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDepthFunc(func);
+}
+
+GLES2_CB(glDepthMask)
+{
+ GLES2_ARG(TGLboolean, flag);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDepthMask(flag);
+}
+
+GLES2_CB(glDepthRangef)
+{
+ GLES2_ARG(TGLclampf, zNear);
+ GLES2_ARG(TGLclampf, zFar);
+ GLES2_BARRIER_ARG_NORET;
+
+ glDepthRangef(zNear, zFar);
+}
+
+GLES2_CB(glClearDepthf)
+{
+ GLES2_ARG(TGLclampf, depth);
+ GLES2_BARRIER_ARG_NORET;
+
+ glClearDepthf(depth);
+}
+
new file mode 100644
@@ -0,0 +1,189 @@
+/* Copyright (c) 2009-2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+CALL_ENTRY(eglGetError)
+CALL_ENTRY(eglGetDisplay)
+CALL_ENTRY(eglInitialize)
+CALL_DUMMY(eglTerminate)
+CALL_DUMMY(eglQueryString)
+CALL_ENTRY(eglGetConfigs)
+CALL_ENTRY(eglChooseConfig)
+CALL_ENTRY(eglGetConfigAttrib)
+CALL_ENTRY(eglCreateWindowSurface)
+CALL_DUMMY(eglCreatePbufferSurface)
+CALL_ENTRY(eglCreatePixmapSurface)
+CALL_ENTRY(eglDestroySurface)
+CALL_DUMMY(eglQuerySurface)
+CALL_DUMMY(eglBindAPI)
+CALL_DUMMY(eglQueryAPI)
+CALL_DUMMY(eglWaitClient)
+CALL_DUMMY(eglReleaseThread)
+CALL_DUMMY(eglCreatePbufferFromClientBuffer)
+CALL_DUMMY(eglSurfaceAttrib)
+CALL_ENTRY(eglBindTexImage)
+CALL_ENTRY(eglReleaseTexImage)
+CALL_DUMMY(eglSwapInterval)
+CALL_ENTRY(eglCreateContext)
+CALL_ENTRY(eglDestroyContext)
+CALL_ENTRY(eglMakeCurrent)
+CALL_DUMMY(eglGetCurrentContext)
+CALL_DUMMY(eglGetCurrentSurface)
+CALL_DUMMY(eglGetCurrentDisplay)
+CALL_DUMMY(eglQueryContext)
+CALL_DUMMY(eglWaitGL)
+CALL_DUMMY(eglWaitNative)
+CALL_ENTRY(eglSwapBuffers)
+CALL_DUMMY(eglCopyBuffers)
+CALL_DUMMY(eglGetProcAddress)
+
+CALL_ENTRY(glActiveTexture)
+CALL_ENTRY(glAttachShader)
+CALL_ENTRY(glBindAttribLocation)
+CALL_ENTRY(glBindBuffer)
+CALL_ENTRY(glBindFramebuffer)
+CALL_ENTRY(glBindRenderbuffer)
+CALL_ENTRY(glBindTexture)
+CALL_ENTRY(glBlendColor)
+CALL_ENTRY(glBlendEquation)
+CALL_ENTRY(glBlendEquationSeparate)
+CALL_ENTRY(glBlendFunc)
+CALL_ENTRY(glBlendFuncSeparate)
+CALL_DUMMY(glBufferData)
+CALL_DUMMY(glBufferSubData)
+CALL_ENTRY(glCheckFramebufferStatus)
+CALL_ENTRY(glClear)
+CALL_ENTRY(glClearColor)
+CALL_ENTRY(glClearDepthf)
+CALL_ENTRY(glClearStencil)
+CALL_ENTRY(glColorMask)
+CALL_ENTRY(glCompileShader)
+CALL_DUMMY(glCompressedTexImage2D)
+CALL_DUMMY(glCompressedTexSubImage2D)
+CALL_DUMMY(glCopyTexImage2D)
+CALL_DUMMY(glCopyTexSubImage2D)
+CALL_ENTRY(glCreateProgram)
+CALL_ENTRY(glCreateShader)
+CALL_ENTRY(glCullFace)
+CALL_DUMMY(glDeleteBuffers)
+CALL_ENTRY(glDeleteFramebuffers)
+CALL_ENTRY(glDeleteProgram)
+CALL_ENTRY(glDeleteRenderbuffers)
+CALL_ENTRY(glDeleteShader)
+CALL_ENTRY(glDeleteTextures)
+CALL_ENTRY(glDepthFunc)
+CALL_ENTRY(glDepthMask)
+CALL_ENTRY(glDepthRangef)
+CALL_DUMMY(glDetachShader)
+CALL_ENTRY(glDisable)
+CALL_ENTRY(glDisableVertexAttribArray)
+CALL_ENTRY(glDrawArrays)
+CALL_ENTRY(glDrawElements)
+CALL_ENTRY(glEnable)
+CALL_ENTRY(glEnableVertexAttribArray)
+CALL_ENTRY(glFinish)
+CALL_ENTRY(glFlush)
+CALL_ENTRY(glFramebufferRenderbuffer)
+CALL_ENTRY(glFramebufferTexture2D)
+CALL_ENTRY(glFrontFace)
+CALL_DUMMY(glGenBuffers)
+CALL_ENTRY(glGenerateMipmap)
+CALL_ENTRY(glGenFramebuffers)
+CALL_ENTRY(glGenRenderbuffers)
+CALL_ENTRY(glGenTextures)
+CALL_DUMMY(glGetActiveAttrib)
+CALL_DUMMY(glGetActiveUniform)
+CALL_DUMMY(glGetAttachedShaders)
+CALL_ENTRY(glGetAttribLocation)
+CALL_ENTRY(glGetBooleanv)
+CALL_DUMMY(glGetBufferParameteriv)
+CALL_ENTRY(glGetError)
+CALL_ENTRY(glGetFloatv)
+CALL_DUMMY(glGetFramebufferAttachmentParameteriv)
+CALL_ENTRY(glGetIntegerv)
+CALL_ENTRY(glGetProgramiv)
+CALL_ENTRY(glGetProgramInfoLog)
+CALL_DUMMY(glGetRenderbufferParameteriv)
+CALL_ENTRY(glGetShaderiv)
+CALL_ENTRY(glGetShaderInfoLog)
+CALL_DUMMY(glGetShaderPrecisionFormat)
+CALL_DUMMY(glGetShaderSource)
+CALL_DUMMY(glGetString)
+CALL_ENTRY(glGetTexParameterfv)
+CALL_ENTRY(glGetTexParameteriv)
+CALL_DUMMY(glGetUniformfv)
+CALL_DUMMY(glGetUniformiv)
+CALL_ENTRY(glGetUniformLocation)
+CALL_DUMMY(glGetVertexAttribfv)
+CALL_DUMMY(glGetVertexAttribiv)
+CALL_DUMMY(glGetVertexAttribPointerv)
+CALL_ENTRY(glHint)
+CALL_DUMMY(glIsBuffer)
+CALL_ENTRY(glIsEnabled)
+CALL_DUMMY(glIsFramebuffer)
+CALL_ENTRY(glIsProgram)
+CALL_DUMMY(glIsRenderbuffer)
+CALL_ENTRY(glIsShader)
+CALL_ENTRY(glIsTexture)
+CALL_ENTRY(glLineWidth)
+CALL_ENTRY(glLinkProgram)
+CALL_ENTRY(glPixelStorei)
+CALL_ENTRY(glPolygonOffset)
+CALL_ENTRY(glReadPixels)
+CALL_DUMMY(glReleaseShaderCompiler)
+CALL_ENTRY(glRenderbufferStorage)
+CALL_ENTRY(glSampleCoverage)
+CALL_ENTRY(glScissor)
+CALL_DUMMY(glShaderBinary)
+CALL_ENTRY(glShaderSource)
+CALL_ENTRY(glStencilFunc)
+CALL_ENTRY(glStencilFuncSeparate)
+CALL_ENTRY(glStencilMask)
+CALL_ENTRY(glStencilMaskSeparate)
+CALL_ENTRY(glStencilOp)
+CALL_ENTRY(glStencilOpSeparate)
+CALL_ENTRY(glTexImage2D)
+CALL_ENTRY(glTexParameterf)
+CALL_ENTRY(glTexParameterfv)
+CALL_ENTRY(glTexParameteri)
+CALL_ENTRY(glTexParameteriv)
+CALL_ENTRY(glTexSubImage2D)
+CALL_ENTRY(glUniform1f)
+CALL_ENTRY(glUniform1fv)
+CALL_ENTRY(glUniform1i)
+CALL_ENTRY(glUniform1iv)
+CALL_ENTRY(glUniform2f)
+CALL_ENTRY(glUniform2fv)
+CALL_ENTRY(glUniform2i)
+CALL_ENTRY(glUniform2iv)
+CALL_ENTRY(glUniform3f)
+CALL_ENTRY(glUniform3fv)
+CALL_ENTRY(glUniform3i)
+CALL_ENTRY(glUniform3iv)
+CALL_ENTRY(glUniform4f)
+CALL_ENTRY(glUniform4fv)
+CALL_ENTRY(glUniform4i)
+CALL_ENTRY(glUniform4iv)
+CALL_ENTRY(glUniformMatrix2fv)
+CALL_ENTRY(glUniformMatrix3fv)
+CALL_ENTRY(glUniformMatrix4fv)
+CALL_ENTRY(glUseProgram)
+CALL_DUMMY(glValidateProgram)
+CALL_ENTRY(glVertexAttrib1f)
+CALL_ENTRY(glVertexAttrib1fv)
+CALL_ENTRY(glVertexAttrib2f)
+CALL_ENTRY(glVertexAttrib2fv)
+CALL_ENTRY(glVertexAttrib3f)
+CALL_ENTRY(glVertexAttrib3fv)
+CALL_ENTRY(glVertexAttrib4f)
+CALL_ENTRY(glVertexAttrib4fv)
+CALL_ENTRY(glVertexAttribPointer)
+CALL_ENTRY(glViewport)
+
@@ -1554,6 +1554,10 @@ static QEMUMachine n810_machine = {
.init = n810_init,
};
+#ifdef CONFIG_GLES2
+#include "gles2.h"
+#endif
+
#define N900_SDRAM_SIZE (256 * 1024 * 1024)
#define N900_ONENAND_CS 0
#define N900_ONENAND_BUFSIZE (0xc000 << 1)
@@ -2135,6 +2139,9 @@ struct n900_s {
void *tpa6130;
void *lis302dl;
void *smc;
+#ifdef CONFIG_GLES2
+ void *gles2;
+#endif
int extended_key;
int slide_open;
int camera_cover_open;
@@ -2397,6 +2404,9 @@ static void n900_init(ram_addr_t ram_size,
qemu_add_kbd_event_handler(n900_key_handler, s);
qemu_set_display_close_handler(n900_display_close_callback, s);
+#ifdef CONFIG_GLES2
+ s->gles2 = gles2_init(s->cpu->env);
+#endif
qemu_register_reset(n900_reset, s);
n900_reset(s);
}
@@ -863,6 +863,25 @@ STEXI
@end table
ETEXI
+#ifdef TARGET_ARM
+DEFHEADING(arm target only:)
+#endif
+STEXI
+@table @option
+ETEXI
+
+#if(defined TARGET_ARM && defined CONFIG_GLES2)
+DEF("gles2-quality", HAS_ARG, QEMU_OPTION_gles2_quality,
+ "-gles2-quality set GLES 2.0 rendering quality [0 ... 100]\n")
+#endif
+
+#ifdef TARGET_ARM
+DEFHEADING()
+#endif
+STEXI
+@end table
+ETEXI
+
DEFHEADING(Network options:)
STEXI
@table @option
@@ -1168,7 +1168,15 @@ static int get_phys_addr_mpu(CPUState *env, uint32_t address, int access_type,
return 0;
}
-static inline int get_phys_addr(CPUState *env, uint32_t address,
+#ifdef CONFIG_GLES2
+int get_phys_addr(CPUState *env, uint32_t address,
+ int access_type, int is_user,
+ uint32_t *phys_ptr, int *prot,
+ target_ulong *page_size);
+#else
+static
+#endif
+int get_phys_addr(CPUState *env, uint32_t address,
int access_type, int is_user,
uint32_t *phys_ptr, int *prot,
target_ulong *page_size)
@@ -4342,6 +4342,16 @@ int main(int argc, char **argv, char **envp)
}
break;
#endif
+#ifdef TARGET_ARM
+#ifdef CONFIG_GLES2
+ case QEMU_OPTION_gles2_quality:
+ {
+ extern int gles2_quality;
+ gles2_quality = strtoul(optarg, NULL, 10);
+ }
+ break;
+#endif
+#endif
#ifdef CONFIG_KVM
case QEMU_OPTION_enable_kvm:
kvm_allowed = 1;