From 5d7f0875e9cda2d6ab37b49f0b6ceed8f0d16f45 Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Mon, 19 Sep 2011 18:47:26 +0200 Subject: [PATCH] emulator: opengl: 'large' buffer optimization This patch modifies the guest encoding libraries to avoid un-necessary copies when sending large buffers (e.g. pixels) to the host. Instead, the data is sent directly through a new IOStream method (writeFully()). On my machine, this improves the NenaMark2 benchmark (from 50.8 to 57.1 fps). More importantly, this speeds up the display of non-GL surfaces too, which are sent through the special rcUpdateColorBuffer() function in gralloc_goldfish. This is noticeable in many parts of the UI (e.g. when scrolling through lists). To tag a given parameter, use the new 'isLarge' variable flag in the protocol .attrib file. Implemented for the following encoding functions: rcUpdateColorBuffer glTexSubImage2D glTexImage2Di glBufferData glBufferSubData glCompressedTexImage2D glCompressedTexSubImage2D glTexImage3DOES glTexSubImage3DOES glCompressedTexImage3DOES glCompressedTexSubImage3DOES + Optimize the auto-generated encoder functions to avoid repeated function calls (for size computations). Change-Id: I13a02607b606c40cd05984cd2051b1f3424bc2d0 --- .../host/include/libOpenglRender/IOStream.h | 2 + .../opengl/host/tools/emugen/ApiGen.cpp | 314 +++++++++++++----- .../opengl/host/tools/emugen/EntryPoint.cpp | 44 ++- .../emulator/opengl/host/tools/emugen/README | 5 +- tools/emulator/opengl/host/tools/emugen/Var.h | 8 +- .../shared/OpenglCodecCommon/SocketStream.cpp | 7 +- .../shared/OpenglCodecCommon/SocketStream.h | 2 +- .../opengl/system/GLESv1_enc/gl.attrib | 3 +- .../opengl/system/GLESv2_enc/gl2.attrib | 16 +- .../OpenglSystemCommon/QemuPipeStream.h | 3 +- .../renderControl_enc/renderControl.attrib | 7 +- 11 files changed, 302 insertions(+), 109 deletions(-) diff --git a/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h b/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h index 41d80238f..445ec17da 100644 --- a/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h +++ b/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h @@ -34,6 +34,7 @@ public: virtual int commitBuffer(size_t size) = 0; virtual const unsigned char *readFully( void *buf, size_t len) = 0; virtual const unsigned char *read( void *buf, size_t *inout_len) = 0; + virtual int writeFully(const void* buf, size_t len) = 0; virtual ~IOStream() { @@ -82,6 +83,7 @@ public: return readFully(buf, len); } + private: unsigned char *m_buf; size_t m_bufsize; diff --git a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp index 9e9560403..72b7bb314 100644 --- a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp +++ b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp @@ -21,6 +21,15 @@ #include #include +/* Define this to 1 to enable support for the 'isLarge' variable flag + * that instructs the encoder to send large data buffers by a direct + * write through the pipe (i.e. without copying it into a temporary + * buffer. This has definite performance benefits when using a QEMU Pipe. + * + * Set to 0 otherwise. + */ +#define WITH_LARGE_SUPPORT 1 + EntryPoint * ApiGen::findEntryByName(const std::string & name) { EntryPoint * entry = NULL; @@ -338,6 +347,99 @@ int ApiGen::genEncoderHeader(const std::string &filename) return 0; } +// Format the byte length expression for a given variable into a user-provided buffer +// If the variable type is not a pointer, this is simply its size as a decimal constant +// If the variable is a pointer, this will be an expression provided by the .attrib file +// through the 'len' attribute. +// +// Returns 1 if the variable is a pointer, 0 otherwise +// +static int getVarEncodingSizeExpression(Var& var, EntryPoint* e, char* buff, size_t bufflen) +{ + int ret = 0; + if (!var.isPointer()) { + snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes()); + } else { + ret = 1; + const char* lenExpr = var.lenExpression().c_str(); + const char* varname = var.name().c_str(); + if (e != NULL && lenExpr[0] == '\0') { + fprintf(stderr, "%s: data len is undefined for '%s'\n", + e->name().c_str(), varname); + } + if (var.nullAllowed()) { + snprintf(buff, bufflen, "((%s != NULL) ? %s : 0)", varname, lenExpr); + } else { + snprintf(buff, bufflen, "%s", lenExpr); + } + } + return ret; +} + +static int writeVarEncodingSize(Var& var, FILE* fp) +{ + int ret = 0; + if (!var.isPointer()) { + fprintf(fp, "%u", (unsigned int) var.type()->bytes()); + } else { + ret = 1; + fprintf(fp, "__size_%s", var.name().c_str()); + } + return ret; +} + + + +static void writeVarEncodingExpression(Var& var, FILE* fp) +{ + const char* varname = var.name().c_str(); + + if (var.isPointer()) { + // encode a pointer header + fprintf(fp, "\t*(unsigned int *)(ptr) = __size_%s; ptr += 4;\n", varname); + + Var::PointerDir dir = var.pointerDir(); + if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) { + if (var.nullAllowed()) { + fprintf(fp, "\tif (%s != NULL) ", varname); + } else { + fprintf(fp, "\t"); + } + + if (var.packExpression().size() != 0) { + fprintf(fp, "%s;", var.packExpression().c_str()); + } else { + fprintf(fp, "memcpy(ptr, %s, __size_%s);", + varname, varname); + } + + fprintf(fp, "ptr += __size_%s;\n", varname); + } + } else { + // encode a non pointer variable + if (!var.isVoid()) { + fprintf(fp, "\t*(%s *) (ptr) = %s; ptr += %u;\n", + var.type()->name().c_str(), varname, + (uint) var.type()->bytes()); + } + } +} + +#if WITH_LARGE_SUPPORT +static void writeVarLargeEncodingExpression(Var& var, FILE* fp) +{ + const char* varname = var.name().c_str(); + + fprintf(fp, "\tstream->writeFully(&__size_%s,4);\n", varname); + if (var.nullAllowed()) { + fprintf(fp, "\tif (%s != NULL) ", varname); + } else { + fprintf(fp, "\t"); + } + fprintf(fp, "stream->writeFully(%s, __size_%s);\n", varname, varname); +} +#endif /* WITH_LARGE_SUPPORT */ + int ApiGen::genEncoderImpl(const std::string &filename) { FILE *fp = fopen(filename.c_str(), "wt"); @@ -368,46 +470,139 @@ int ApiGen::genEncoderImpl(const std::string &filename) fprintf(fp, "{\n"); // fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str()); - fprintf(fp, "\n\t%s *ctx = (%s *)self;\n\n", + fprintf(fp, "\n\t%s *ctx = (%s *)self;\n", classname.c_str(), classname.c_str()); - - // size calculation ; - fprintf(fp, "\t size_t packetSize = "); - + fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n\n"); VarsArray & evars = e->vars(); + size_t maxvars = evars.size(); + size_t j; + + char buff[256]; + + // Define the __size_XXX variables that contain the size of data + // associated with pointers. + for (j = 0; j < maxvars; j++) { + Var& var = evars[j]; + + if (!var.isPointer()) + continue; + + const char* varname = var.name().c_str(); + fprintf(fp, "\tconst unsigned int __size_%s = ", varname); + + getVarEncodingSizeExpression(var, e, buff, sizeof(buff)); + fprintf(fp, "%s;\n", buff); + } + +#if WITH_LARGE_SUPPORT + // We need to take care of 'isLarge' variable in a special way + // Anything before an isLarge variable can be packed into a single + // buffer, which is then commited. Each isLarge variable is a pointer + // to data that can be written to directly through the pipe, which + // will be instant when using a QEMU pipe + + size_t nvars = 0; + size_t npointers = 0; + + // First, compute the total size, 8 bytes for the opcode + payload size + fprintf(fp, "\t unsigned char *ptr;\n"); + fprintf(fp, "\t const size_t packetSize = 8"); + + for (j = 0; j < maxvars; j++) { + fprintf(fp, " + "); + npointers += writeVarEncodingSize(evars[j], fp); + } + if (npointers > 0) { + fprintf(fp, " + %u*4", npointers); + } + fprintf(fp, ";\n"); + + // We need to divide the packet into fragments. Each fragment contains + // either copied arguments to a temporary buffer, or direct writes for + // large variables. + // + // The first fragment must also contain the opcode+payload_size + // + nvars = 0; + while (nvars < maxvars || maxvars == 0) { + + // Skip over non-large fields + for (j = nvars; j < maxvars; j++) { + if (evars[j].isLarge()) + break; + } + + // Write a fragment if needed. + if (nvars == 0 || j > nvars) { + const char* plus = ""; + + if (nvars == 0 && j == maxvars) { + // Simple shortcut for the common case where we don't have large variables; + fprintf(fp, "\tptr = stream->alloc(packetSize);\n"); + + } else { + // allocate buffer from the stream until the first large variable + fprintf(fp, "\tptr = stream->alloc("); + plus = ""; + + if (nvars == 0) { + fprintf(fp,"8"); plus = " + "; + } + if (j > nvars) { + npointers = 0; + for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) { + fprintf(fp, "%s", plus); plus = " + "; + npointers += writeVarEncodingSize(evars[j], fp); + } + if (npointers > 0) { + fprintf(fp, "%s%u*4", plus, npointers); plus = " + "; + } + } + fprintf(fp,");\n"); + } + + // encode packet header if needed. + if (nvars == 0) { + fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n", e->name().c_str()); + fprintf(fp, "\t*(unsigned int *)(ptr) = (unsigned int) packetSize; ptr += 4;\n"); + } + + if (maxvars == 0) + break; + + // encode non-large fields in this fragment + for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) { + writeVarEncodingExpression(evars[j],fp); + } + + // Ensure the fragment is commited if it is followed by a large variable + if (j < maxvars) { + fprintf(fp, "\tstream->flush();\n"); + } + } + + // If we have one or more large variables, write them directly. + // As size + data + for ( ; j < maxvars && evars[j].isLarge(); j++) { + writeVarLargeEncodingExpression(evars[j], fp); + } + + nvars = j; + } + +#else /* !WITH_LARGE_SUPPORT */ size_t nvars = evars.size(); size_t npointers = 0; + fprintf(fp, "\t const size_t packetSize = 8"); for (size_t j = 0; j < nvars; j++) { - fprintf(fp, "%s ", j == 0 ? "" : " +"); - if (evars[j].isPointer()) { - npointers++; - - if (evars[j].lenExpression() == "") { - fprintf(stderr, "%s: data len is undefined for '%s'\n", - e->name().c_str(), evars[j].name().c_str()); - } - - if (evars[j].nullAllowed()) { - fprintf(fp, "(%s != NULL ? %s : 0)", - evars[j].name().c_str(), - evars[j].lenExpression().c_str()); - } else { - if (evars[j].pointerDir() == Var::POINTER_IN || - evars[j].pointerDir() == Var::POINTER_INOUT) { - fprintf(fp, "%s", evars[j].lenExpression().c_str()); - } else { - fprintf(fp, "0"); - } - } - } else { - fprintf(fp, "%u", (unsigned int) evars[j].type()->bytes()); - } + npointers += getVarEncodingSizeExpression(evars[j],e,buff,sizeof(buff)); + fprintf(fp, " + %s", buff); } - fprintf(fp, " %s 8 + %u * 4;\n", nvars != 0 ? "+" : "", (unsigned int) npointers); + fprintf(fp, " + %u * 4;\n", (unsigned int) npointers); // allocate buffer from the stream; - fprintf(fp, "\t unsigned char *ptr = ctx->m_stream->alloc(packetSize);\n\n"); + fprintf(fp, "\t unsigned char *ptr = stream->alloc(packetSize);\n\n"); // encode into the stream; fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n", e->name().c_str()); @@ -415,62 +610,23 @@ int ApiGen::genEncoderImpl(const std::string &filename) // out variables for (size_t j = 0; j < nvars; j++) { - if (evars[j].isPointer()) { - // encode a pointer header - if (evars[j].nullAllowed()) { - fprintf(fp, "\t*(unsigned int *)(ptr) = (%s != NULL) ? %s : 0; ptr += 4; \n", - evars[j].name().c_str(), evars[j].lenExpression().c_str()); - } else { - fprintf(fp, "\t*(unsigned int *)(ptr) = %s; ptr += 4; \n", - evars[j].lenExpression().c_str()); - } - - Var::PointerDir dir = evars[j].pointerDir(); - if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) { - if (evars[j].nullAllowed()) { - fprintf(fp, "\tif (%s != NULL) ", evars[j].name().c_str()); - } else { - fprintf(fp, "\t"); - } - - if (evars[j].packExpression().size() != 0) { - fprintf(fp, "%s;", evars[j].packExpression().c_str()); - } else { - fprintf(fp, "memcpy(ptr, %s, %s);", - evars[j].name().c_str(), - evars[j].lenExpression().c_str()); - } - - if (evars[j].nullAllowed()) { - fprintf(fp, "ptr += %s == NULL ? 0 : %s; \n", evars[j].name().c_str(), evars[j].lenExpression().c_str()); - } else { - fprintf(fp, "ptr += %s;\n", evars[j].lenExpression().c_str()); - } - } - } else { - // encode a non pointer variable - if (!evars[j].isVoid()) { - fprintf(fp, "\t*(%s *) (ptr) = %s; ptr += %u;\n", - evars[j].type()->name().c_str(), evars[j].name().c_str(), - (uint) evars[j].type()->bytes()); - } - } + writeVarEncodingExpression(evars[j], fp); } +#endif /* !WITH_LARGE_SUPPORT */ + // in variables; for (size_t j = 0; j < nvars; j++) { if (evars[j].isPointer()) { Var::PointerDir dir = evars[j].pointerDir(); if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) { + const char* varname = evars[j].name().c_str(); if (evars[j].nullAllowed()) { - fprintf(fp, "\tif (%s != NULL) ctx->m_stream->readback(%s, %s);\n", - evars[j].name().c_str(), - evars[j].name().c_str(), - evars[j].lenExpression().c_str()); + fprintf(fp, "\tif (%s != NULL) ",varname); } else { - fprintf(fp, "\tctx->m_stream->readback(%s, %s);\n", - evars[j].name().c_str(), - evars[j].lenExpression().c_str()); + fprintf(fp, "\t"); } + fprintf(fp, "stream->readback(%s, __size_%s);\n", + varname, varname); } } } @@ -482,7 +638,7 @@ int ApiGen::genEncoderImpl(const std::string &filename) fprintf(fp, "\t return NULL;\n"); } else if (e->retval().type()->name() != "void") { fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str()); - fprintf(fp, "\tctx->m_stream->readback(&retval, %u);\n",(uint) e->retval().type()->bytes()); + fprintf(fp, "\tstream->readback(&retval, %u);\n",(uint) e->retval().type()->bytes()); fprintf(fp, "\treturn retval;\n"); } fprintf(fp, "}\n\n"); diff --git a/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp b/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp index 413b56af6..044433d90 100644 --- a/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp +++ b/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp @@ -286,22 +286,36 @@ int EntryPoint::setAttribute(const std::string &line, size_t lc) (unsigned int)lc, varname.c_str(), name().c_str()); return -2; } - pos = last; - std::string flag = getNextToken(line, pos, &last, WHITESPACE); - if (flag.size() == 0) { - fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc); - return -3; - } - - if (flag == "nullAllowed") { - if (v->isPointer()) { - v->setNullAllowed(true); - } else { - fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n", - (unsigned int) lc, v->name().c_str()); + int count = 0; + for (;;) { + pos = last; + std::string flag = getNextToken(line, pos, &last, WHITESPACE); + if (flag.size() == 0) { + if (count == 0) { + fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc); + return -3; + } + break; + } + count++; + + if (flag == "nullAllowed") { + if (v->isPointer()) { + v->setNullAllowed(true); + } else { + fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n", + (unsigned int) lc, v->name().c_str()); + } + } else if (flag == "isLarge") { + if (v->isPointer()) { + v->setIsLarge(true); + } else { + fprintf(stderr, "WARNING: %u: setting isLarge flag for a non-pointer variable %s\n", + (unsigned int) lc, v->name().c_str()); + } + } else { + fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str()); } - } else { - fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str()); } } else if (token == "custom_pack") { pos = last; diff --git a/tools/emulator/opengl/host/tools/emugen/README b/tools/emulator/opengl/host/tools/emugen/README index 4d2c28d41..5df11a3ab 100644 --- a/tools/emulator/opengl/host/tools/emugen/README +++ b/tools/emulator/opengl/host/tools/emugen/README @@ -313,7 +313,10 @@ custom_pack var_flag description : set variable flags - format: var_flag < nullAllowed | ... > + format: var_flag < nullAllowed | isLarge | ... > + + nullAllowed -> for pointer variables, indicates that NULL is a valid value + isLarge -> for pointer variables, indicates that the data should be sent without an intermediate copy flag description: set entry point flag; diff --git a/tools/emulator/opengl/host/tools/emugen/Var.h b/tools/emulator/opengl/host/tools/emugen/Var.h index c9735c714..658b80566 100644 --- a/tools/emulator/opengl/host/tools/emugen/Var.h +++ b/tools/emulator/opengl/host/tools/emugen/Var.h @@ -30,6 +30,7 @@ public: m_lenExpression(""), m_pointerDir(POINTER_IN), m_nullAllowed(false), + m_isLarge(false), m_packExpression(""), m_paramCheckExpression("") @@ -46,8 +47,9 @@ public: m_lenExpression(lenExpression), m_pointerDir(dir), m_nullAllowed(false), + m_isLarge(false), m_packExpression(packExpression), - m_paramCheckExpression("") + m_paramCheckExpression("") { } @@ -60,6 +62,7 @@ public: m_packExpression = packExpression; m_pointerDir = dir; m_nullAllowed = false; + m_isLarge = false; } @@ -76,7 +79,9 @@ public: void setPointerDir(PointerDir dir) { m_pointerDir = dir; } PointerDir pointerDir() { return m_pointerDir; } void setNullAllowed(bool state) { m_nullAllowed = state; } + void setIsLarge(bool state) { m_isLarge = state; } bool nullAllowed() const { return m_nullAllowed; } + bool isLarge() const { return m_isLarge; } void printType(FILE *fp) { fprintf(fp, "%s", m_type->name().c_str()); } void printTypeName(FILE *fp) { printType(fp); fprintf(fp, " %s", m_name.c_str()); } @@ -87,6 +92,7 @@ private: std::string m_lenExpression; // an expression to calcualte a pointer data size PointerDir m_pointerDir; bool m_nullAllowed; + bool m_isLarge; std::string m_packExpression; // an expression to pack data into the stream std::string m_paramCheckExpression; //an expression to check parameter value diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp index 244cfbb20..ddc56d0e3 100644 --- a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp +++ b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp @@ -84,6 +84,11 @@ void *SocketStream::allocBuffer(size_t minSize) }; int SocketStream::commitBuffer(size_t size) +{ + return writeFully(m_buf, size); +} + +int SocketStream::writeFully(const void* buffer, size_t size) { if (!valid()) return -1; @@ -91,7 +96,7 @@ int SocketStream::commitBuffer(size_t size) int retval = 0; while (res > 0) { - ssize_t stat = ::send(m_sock, (const char *)(m_buf) + (size - res), res, 0); + ssize_t stat = ::send(m_sock, (const char *)buffer + (size - res), res, 0); if (stat < 0) { if (errno != EINTR) { retval = stat; diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h index c54dea702..3a501b411 100644 --- a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h +++ b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h @@ -37,6 +37,7 @@ public: bool valid() { return m_sock >= 0; } virtual int recv(void *buf, size_t len); + virtual int writeFully(const void *buf, size_t len); protected: int m_sock; @@ -44,7 +45,6 @@ protected: unsigned char *m_buf; SocketStream(int sock, size_t bufSize); - int writeFully(const void *buf, size_t len); }; #endif /* __SOCKET_STREAM_H */ diff --git a/tools/emulator/opengl/system/GLESv1_enc/gl.attrib b/tools/emulator/opengl/system/GLESv1_enc/gl.attrib index fed0f7afa..9b84f89ca 100644 --- a/tools/emulator/opengl/system/GLESv1_enc/gl.attrib +++ b/tools/emulator/opengl/system/GLESv1_enc/gl.attrib @@ -240,7 +240,7 @@ glTexEnvxv glTexImage2D dir pixels in len pixels pixelDataSize(self, width, height, format, type, 0) - var_flag pixels nullAllowed + var_flag pixels nullAllowed isLarge #void glTexParameteriv(GLenum target, GLenum pname, GLint *params) glTexParameteriv @@ -253,6 +253,7 @@ glTexParameterxv #void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) glTexSubImage2D len pixels pixelDataSize(self, width, height, format, type, 0) + var_flag pixels isLarge #void glVertexPointer(GLint size, GLenum type, GLsizei stride, GLvoid *pointer) # we treat the pointer as an offset to a VBO diff --git a/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib b/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib index 538c453ef..7fe9a66c7 100644 --- a/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib +++ b/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib @@ -9,20 +9,22 @@ glBindAttribLocation #void glBufferData(GLenum target, GLsizeiptr size, GLvoid *data, GLenum usage) glBufferData len data size - var_flag data nullAllowed + var_flag data nullAllowed isLarge #void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) glBufferSubData len data size + var_flag data isLarge #void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLvoid *data) glCompressedTexImage2D len data imageSize - var_flag data nullAllowed + var_flag data nullAllowed isLarge #void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLvoid *data) glCompressedTexSubImage2D len data imageSize + var_flag data isLarge #void glDeleteBuffers(GLsizei n, GLuint *buffers) glDeleteBuffers @@ -243,7 +245,7 @@ glShaderBinary glTexImage2D dir pixels in len pixels pixelDataSize(self, width, height, format, type, 0) - var_flag pixels nullAllowed + var_flag pixels nullAllowed isLarge #void glTexParameterfv(GLenum target, GLenum pname, GLfloat *params) glTexParameterfv @@ -255,6 +257,7 @@ glTexParameteriv #void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) glTexSubImage2D len pixels pixelDataSize(self, width, height, format, type, 0) + var_flag pixels isLarge #void glUniform1fv(GLint location, GLsizei count, GLfloat *v) glUniform1fv @@ -333,20 +336,23 @@ glMapBufferOES #void glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLvoid *pixels) glTexImage3DOES - len pixels pixelDataSize3D(self, width, height, depth, format, type, 0) - var_flag pixels nullAllowed + len pixels pixelDataSize3D(self, width, height, depth, format, type, 0) + var_flag pixels nullAllowed isLarge #void glTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *pixels) glTexSubImage3DOES len pixels pixelDataSize3D(self, width, height, depth, format, type, 0) + var_flag pixels isLarge #void glCompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLvoid *data) glCompressedTexImage3DOES len data imageSize + var_flag data isLarge #void glCompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLvoid *data) glCompressedTexSubImage3DOES len data imageSize + var_flag data isLarge #void glDeleteVertexArraysOES(GLsizei n, GLuint *arrays) glDeleteVertexArraysOES diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h b/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h index db362867a..57ee399b4 100644 --- a/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h +++ b/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h @@ -39,8 +39,7 @@ public: bool valid() { return m_sock >= 0; } int recv(void *buf, size_t len); -private: - int writeFully(const void *buf, size_t len); + virtual int writeFully(const void *buf, size_t len); private: int m_sock; diff --git a/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib b/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib index c51ae0eef..8b9972ff7 100644 --- a/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib +++ b/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib @@ -26,10 +26,10 @@ rcGetConfigs rcChooseConfig dir attribs in - len attribs attribs_size - dir configs out + len attribs attribs_size + dir configs out var_flag configs nullAllowed - len configs configs_size*sizeof(uint32_t) + len configs configs_size*sizeof(uint32_t) rcReadColorBuffer dir pixels out @@ -38,3 +38,4 @@ rcReadColorBuffer rcUpdateColorBuffer dir pixels in len pixels (((glUtilsPixelBitSize(format, type) * width) >> 3) * height) + var_flag pixels isLarge