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
This commit is contained in:
@@ -34,6 +34,7 @@ public:
|
|||||||
virtual int commitBuffer(size_t size) = 0;
|
virtual int commitBuffer(size_t size) = 0;
|
||||||
virtual const unsigned char *readFully( void *buf, size_t len) = 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 const unsigned char *read( void *buf, size_t *inout_len) = 0;
|
||||||
|
virtual int writeFully(const void* buf, size_t len) = 0;
|
||||||
|
|
||||||
virtual ~IOStream() {
|
virtual ~IOStream() {
|
||||||
|
|
||||||
@@ -82,6 +83,7 @@ public:
|
|||||||
return readFully(buf, len);
|
return readFully(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned char *m_buf;
|
unsigned char *m_buf;
|
||||||
size_t m_bufsize;
|
size_t m_bufsize;
|
||||||
|
|||||||
@@ -21,6 +21,15 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* 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 * ApiGen::findEntryByName(const std::string & name)
|
||||||
{
|
{
|
||||||
EntryPoint * entry = NULL;
|
EntryPoint * entry = NULL;
|
||||||
@@ -338,6 +347,99 @@ int ApiGen::genEncoderHeader(const std::string &filename)
|
|||||||
return 0;
|
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)
|
int ApiGen::genEncoderImpl(const std::string &filename)
|
||||||
{
|
{
|
||||||
FILE *fp = fopen(filename.c_str(), "wt");
|
FILE *fp = fopen(filename.c_str(), "wt");
|
||||||
@@ -368,46 +470,139 @@ int ApiGen::genEncoderImpl(const std::string &filename)
|
|||||||
fprintf(fp, "{\n");
|
fprintf(fp, "{\n");
|
||||||
|
|
||||||
// fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str());
|
// 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(),
|
||||||
classname.c_str());
|
classname.c_str());
|
||||||
|
fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n\n");
|
||||||
// size calculation ;
|
|
||||||
fprintf(fp, "\t size_t packetSize = ");
|
|
||||||
|
|
||||||
VarsArray & evars = e->vars();
|
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 nvars = evars.size();
|
||||||
size_t npointers = 0;
|
size_t npointers = 0;
|
||||||
|
fprintf(fp, "\t const size_t packetSize = 8");
|
||||||
for (size_t j = 0; j < nvars; j++) {
|
for (size_t j = 0; j < nvars; j++) {
|
||||||
fprintf(fp, "%s ", j == 0 ? "" : " +");
|
npointers += getVarEncodingSizeExpression(evars[j],e,buff,sizeof(buff));
|
||||||
if (evars[j].isPointer()) {
|
fprintf(fp, " + %s", buff);
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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;
|
// 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;
|
// encode into the stream;
|
||||||
fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n", e->name().c_str());
|
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
|
// out variables
|
||||||
for (size_t j = 0; j < nvars; j++) {
|
for (size_t j = 0; j < nvars; j++) {
|
||||||
if (evars[j].isPointer()) {
|
writeVarEncodingExpression(evars[j], fp);
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif /* !WITH_LARGE_SUPPORT */
|
||||||
|
|
||||||
// in variables;
|
// in variables;
|
||||||
for (size_t j = 0; j < nvars; j++) {
|
for (size_t j = 0; j < nvars; j++) {
|
||||||
if (evars[j].isPointer()) {
|
if (evars[j].isPointer()) {
|
||||||
Var::PointerDir dir = evars[j].pointerDir();
|
Var::PointerDir dir = evars[j].pointerDir();
|
||||||
if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
|
if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
|
||||||
|
const char* varname = evars[j].name().c_str();
|
||||||
if (evars[j].nullAllowed()) {
|
if (evars[j].nullAllowed()) {
|
||||||
fprintf(fp, "\tif (%s != NULL) ctx->m_stream->readback(%s, %s);\n",
|
fprintf(fp, "\tif (%s != NULL) ",varname);
|
||||||
evars[j].name().c_str(),
|
|
||||||
evars[j].name().c_str(),
|
|
||||||
evars[j].lenExpression().c_str());
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(fp, "\tctx->m_stream->readback(%s, %s);\n",
|
fprintf(fp, "\t");
|
||||||
evars[j].name().c_str(),
|
|
||||||
evars[j].lenExpression().c_str());
|
|
||||||
}
|
}
|
||||||
|
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");
|
fprintf(fp, "\t return NULL;\n");
|
||||||
} else if (e->retval().type()->name() != "void") {
|
} else if (e->retval().type()->name() != "void") {
|
||||||
fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str());
|
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, "\treturn retval;\n");
|
||||||
}
|
}
|
||||||
fprintf(fp, "}\n\n");
|
fprintf(fp, "}\n\n");
|
||||||
|
|||||||
@@ -286,22 +286,36 @@ int EntryPoint::setAttribute(const std::string &line, size_t lc)
|
|||||||
(unsigned int)lc, varname.c_str(), name().c_str());
|
(unsigned int)lc, varname.c_str(), name().c_str());
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
pos = last;
|
int count = 0;
|
||||||
std::string flag = getNextToken(line, pos, &last, WHITESPACE);
|
for (;;) {
|
||||||
if (flag.size() == 0) {
|
pos = last;
|
||||||
fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
|
std::string flag = getNextToken(line, pos, &last, WHITESPACE);
|
||||||
return -3;
|
if (flag.size() == 0) {
|
||||||
}
|
if (count == 0) {
|
||||||
|
fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
|
||||||
if (flag == "nullAllowed") {
|
return -3;
|
||||||
if (v->isPointer()) {
|
}
|
||||||
v->setNullAllowed(true);
|
break;
|
||||||
} else {
|
}
|
||||||
fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
|
count++;
|
||||||
(unsigned int) lc, v->name().c_str());
|
|
||||||
|
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") {
|
} else if (token == "custom_pack") {
|
||||||
pos = last;
|
pos = last;
|
||||||
|
|||||||
@@ -313,7 +313,10 @@ custom_pack
|
|||||||
|
|
||||||
var_flag
|
var_flag
|
||||||
description : set variable flags
|
description : set variable flags
|
||||||
format: var_flag <varname> < nullAllowed | ... >
|
format: var_flag <varname> < 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
|
flag
|
||||||
description: set entry point flag;
|
description: set entry point flag;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public:
|
|||||||
m_lenExpression(""),
|
m_lenExpression(""),
|
||||||
m_pointerDir(POINTER_IN),
|
m_pointerDir(POINTER_IN),
|
||||||
m_nullAllowed(false),
|
m_nullAllowed(false),
|
||||||
|
m_isLarge(false),
|
||||||
m_packExpression(""),
|
m_packExpression(""),
|
||||||
m_paramCheckExpression("")
|
m_paramCheckExpression("")
|
||||||
|
|
||||||
@@ -46,8 +47,9 @@ public:
|
|||||||
m_lenExpression(lenExpression),
|
m_lenExpression(lenExpression),
|
||||||
m_pointerDir(dir),
|
m_pointerDir(dir),
|
||||||
m_nullAllowed(false),
|
m_nullAllowed(false),
|
||||||
|
m_isLarge(false),
|
||||||
m_packExpression(packExpression),
|
m_packExpression(packExpression),
|
||||||
m_paramCheckExpression("")
|
m_paramCheckExpression("")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +62,7 @@ public:
|
|||||||
m_packExpression = packExpression;
|
m_packExpression = packExpression;
|
||||||
m_pointerDir = dir;
|
m_pointerDir = dir;
|
||||||
m_nullAllowed = false;
|
m_nullAllowed = false;
|
||||||
|
m_isLarge = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +79,9 @@ public:
|
|||||||
void setPointerDir(PointerDir dir) { m_pointerDir = dir; }
|
void setPointerDir(PointerDir dir) { m_pointerDir = dir; }
|
||||||
PointerDir pointerDir() { return m_pointerDir; }
|
PointerDir pointerDir() { return m_pointerDir; }
|
||||||
void setNullAllowed(bool state) { m_nullAllowed = state; }
|
void setNullAllowed(bool state) { m_nullAllowed = state; }
|
||||||
|
void setIsLarge(bool state) { m_isLarge = state; }
|
||||||
bool nullAllowed() const { return m_nullAllowed; }
|
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 printType(FILE *fp) { fprintf(fp, "%s", m_type->name().c_str()); }
|
||||||
void printTypeName(FILE *fp) { printType(fp); fprintf(fp, " %s", m_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
|
std::string m_lenExpression; // an expression to calcualte a pointer data size
|
||||||
PointerDir m_pointerDir;
|
PointerDir m_pointerDir;
|
||||||
bool m_nullAllowed;
|
bool m_nullAllowed;
|
||||||
|
bool m_isLarge;
|
||||||
std::string m_packExpression; // an expression to pack data into the stream
|
std::string m_packExpression; // an expression to pack data into the stream
|
||||||
std::string m_paramCheckExpression; //an expression to check parameter value
|
std::string m_paramCheckExpression; //an expression to check parameter value
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,11 @@ void *SocketStream::allocBuffer(size_t minSize)
|
|||||||
};
|
};
|
||||||
|
|
||||||
int SocketStream::commitBuffer(size_t size)
|
int SocketStream::commitBuffer(size_t size)
|
||||||
|
{
|
||||||
|
return writeFully(m_buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SocketStream::writeFully(const void* buffer, size_t size)
|
||||||
{
|
{
|
||||||
if (!valid()) return -1;
|
if (!valid()) return -1;
|
||||||
|
|
||||||
@@ -91,7 +96,7 @@ int SocketStream::commitBuffer(size_t size)
|
|||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
while (res > 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 (stat < 0) {
|
||||||
if (errno != EINTR) {
|
if (errno != EINTR) {
|
||||||
retval = stat;
|
retval = stat;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public:
|
|||||||
|
|
||||||
bool valid() { return m_sock >= 0; }
|
bool valid() { return m_sock >= 0; }
|
||||||
virtual int recv(void *buf, size_t len);
|
virtual int recv(void *buf, size_t len);
|
||||||
|
virtual int writeFully(const void *buf, size_t len);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int m_sock;
|
int m_sock;
|
||||||
@@ -44,7 +45,6 @@ protected:
|
|||||||
unsigned char *m_buf;
|
unsigned char *m_buf;
|
||||||
|
|
||||||
SocketStream(int sock, size_t bufSize);
|
SocketStream(int sock, size_t bufSize);
|
||||||
int writeFully(const void *buf, size_t len);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __SOCKET_STREAM_H */
|
#endif /* __SOCKET_STREAM_H */
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ glTexEnvxv
|
|||||||
glTexImage2D
|
glTexImage2D
|
||||||
dir pixels in
|
dir pixels in
|
||||||
len pixels pixelDataSize(self, width, height, format, type, 0)
|
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)
|
#void glTexParameteriv(GLenum target, GLenum pname, GLint *params)
|
||||||
glTexParameteriv
|
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)
|
#void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
|
||||||
glTexSubImage2D
|
glTexSubImage2D
|
||||||
len pixels pixelDataSize(self, width, height, format, type, 0)
|
len pixels pixelDataSize(self, width, height, format, type, 0)
|
||||||
|
var_flag pixels isLarge
|
||||||
|
|
||||||
#void glVertexPointer(GLint size, GLenum type, GLsizei stride, GLvoid *pointer)
|
#void glVertexPointer(GLint size, GLenum type, GLsizei stride, GLvoid *pointer)
|
||||||
# we treat the pointer as an offset to a VBO
|
# we treat the pointer as an offset to a VBO
|
||||||
|
|||||||
@@ -9,20 +9,22 @@ glBindAttribLocation
|
|||||||
#void glBufferData(GLenum target, GLsizeiptr size, GLvoid *data, GLenum usage)
|
#void glBufferData(GLenum target, GLsizeiptr size, GLvoid *data, GLenum usage)
|
||||||
glBufferData
|
glBufferData
|
||||||
len data size
|
len data size
|
||||||
var_flag data nullAllowed
|
var_flag data nullAllowed isLarge
|
||||||
|
|
||||||
#void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data)
|
#void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data)
|
||||||
glBufferSubData
|
glBufferSubData
|
||||||
len data size
|
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)
|
#void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLvoid *data)
|
||||||
glCompressedTexImage2D
|
glCompressedTexImage2D
|
||||||
len data imageSize
|
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)
|
#void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLvoid *data)
|
||||||
glCompressedTexSubImage2D
|
glCompressedTexSubImage2D
|
||||||
len data imageSize
|
len data imageSize
|
||||||
|
var_flag data isLarge
|
||||||
|
|
||||||
#void glDeleteBuffers(GLsizei n, GLuint *buffers)
|
#void glDeleteBuffers(GLsizei n, GLuint *buffers)
|
||||||
glDeleteBuffers
|
glDeleteBuffers
|
||||||
@@ -243,7 +245,7 @@ glShaderBinary
|
|||||||
glTexImage2D
|
glTexImage2D
|
||||||
dir pixels in
|
dir pixels in
|
||||||
len pixels pixelDataSize(self, width, height, format, type, 0)
|
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)
|
#void glTexParameterfv(GLenum target, GLenum pname, GLfloat *params)
|
||||||
glTexParameterfv
|
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)
|
#void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
|
||||||
glTexSubImage2D
|
glTexSubImage2D
|
||||||
len pixels pixelDataSize(self, width, height, format, type, 0)
|
len pixels pixelDataSize(self, width, height, format, type, 0)
|
||||||
|
var_flag pixels isLarge
|
||||||
|
|
||||||
#void glUniform1fv(GLint location, GLsizei count, GLfloat *v)
|
#void glUniform1fv(GLint location, GLsizei count, GLfloat *v)
|
||||||
glUniform1fv
|
glUniform1fv
|
||||||
@@ -334,19 +337,22 @@ glMapBufferOES
|
|||||||
#void glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLvoid *pixels)
|
#void glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLvoid *pixels)
|
||||||
glTexImage3DOES
|
glTexImage3DOES
|
||||||
len pixels pixelDataSize3D(self, width, height, depth, format, type, 0)
|
len pixels pixelDataSize3D(self, width, height, depth, format, type, 0)
|
||||||
var_flag pixels nullAllowed
|
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)
|
#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
|
glTexSubImage3DOES
|
||||||
len pixels pixelDataSize3D(self, width, height, depth, format, type, 0)
|
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)
|
#void glCompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLvoid *data)
|
||||||
glCompressedTexImage3DOES
|
glCompressedTexImage3DOES
|
||||||
len data imageSize
|
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)
|
#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
|
glCompressedTexSubImage3DOES
|
||||||
len data imageSize
|
len data imageSize
|
||||||
|
var_flag data isLarge
|
||||||
|
|
||||||
#void glDeleteVertexArraysOES(GLsizei n, GLuint *arrays)
|
#void glDeleteVertexArraysOES(GLsizei n, GLuint *arrays)
|
||||||
glDeleteVertexArraysOES
|
glDeleteVertexArraysOES
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ public:
|
|||||||
bool valid() { return m_sock >= 0; }
|
bool valid() { return m_sock >= 0; }
|
||||||
int recv(void *buf, size_t len);
|
int recv(void *buf, size_t len);
|
||||||
|
|
||||||
private:
|
virtual int writeFully(const void *buf, size_t len);
|
||||||
int writeFully(const void *buf, size_t len);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_sock;
|
int m_sock;
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ rcGetConfigs
|
|||||||
|
|
||||||
rcChooseConfig
|
rcChooseConfig
|
||||||
dir attribs in
|
dir attribs in
|
||||||
len attribs attribs_size
|
len attribs attribs_size
|
||||||
dir configs out
|
dir configs out
|
||||||
var_flag configs nullAllowed
|
var_flag configs nullAllowed
|
||||||
len configs configs_size*sizeof(uint32_t)
|
len configs configs_size*sizeof(uint32_t)
|
||||||
|
|
||||||
rcReadColorBuffer
|
rcReadColorBuffer
|
||||||
dir pixels out
|
dir pixels out
|
||||||
@@ -38,3 +38,4 @@ rcReadColorBuffer
|
|||||||
rcUpdateColorBuffer
|
rcUpdateColorBuffer
|
||||||
dir pixels in
|
dir pixels in
|
||||||
len pixels (((glUtilsPixelBitSize(format, type) * width) >> 3) * height)
|
len pixels (((glUtilsPixelBitSize(format, type) * width) >> 3) * height)
|
||||||
|
var_flag pixels isLarge
|
||||||
|
|||||||
Reference in New Issue
Block a user