diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0ab2568d9687090645b14491436ae5eca2863ea0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +*~ +*.bak +*.pyc +Thumbs.db +*.class +*.DS_Store +testapps/testSensors/proguard.cfg +.gradle +/build/ivy.xml + +# Hide temporary files created by the build_server script +eclipse/assemble.com.android.ide.eclipse.*.xml +eclipse/package.com.android.ide.eclipse.*.xml +eclipse/final*Versions*.properties +eclipse/plugins/com.android.ide.eclipse.*/@dot* +eclipse/plugins/com.android.*/javaCompiler...args +eclipse/plugins/com.android.ide.eclipse.*/build.xml +eclipse/features/com.android.ide.eclipse.*/build.xml +eclipse/features/com.android.ide.eclipse.*/*.zip +/eclipse/v[0-9-]*-[0-9]* +/eclipse/v[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] +/status-output diff --git a/host/Android.bp b/host/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..5464fac40f76977f96c0362825adead503e83f9c --- /dev/null +++ b/host/Android.bp @@ -0,0 +1,5 @@ +cc_library_headers { + name: "virtio_gpu_uapi_headers", + host_supported: true, + export_include_dirs: ["linux_uapi"], +} diff --git a/host/commands/Android.bp b/host/commands/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..485e2ef26e9c6f24a241c2d2feea1bcb3e9c74af --- /dev/null +++ b/host/commands/Android.bp @@ -0,0 +1,32 @@ +// +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +subdirs = [ + "emugen", +] + +python_binary_host { + name: "gen_entries_cuttlefish", + srcs: ["gen_entries.py"], + main: "gen_entries.py", + version: { + py2: { + enabled: true, + }, + py3: { + enabled: false, + }, + }, +} diff --git a/host/commands/emugen/Android.bp b/host/commands/emugen/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..516d116a04307ccb8bfa3311fb1c6f34af88130a --- /dev/null +++ b/host/commands/emugen/Android.bp @@ -0,0 +1,12 @@ +cc_binary_host { + name: "emugen_cuttlefish", + srcs: [ + "ApiGen.cpp", + "EntryPoint.cpp", + "main.cpp", + "Parser.cpp", + "strUtils.cpp", + "TypeFactory.cpp", + ], + cflags: ["-Wno-unused-parameter"], +} diff --git a/host/commands/emugen/ApiGen.cpp b/host/commands/emugen/ApiGen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b40dc67740813d5fb126e693401aeb6e7b2aa25 --- /dev/null +++ b/host/commands/emugen/ApiGen.cpp @@ -0,0 +1,1584 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "ApiGen.h" +#include "android/base/EnumFlags.h" +#include "EntryPoint.h" +#include <stdio.h> +#include <stdlib.h> +#include "strUtils.h" +#include <errno.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 + +// Set to 1 to ensure buffers passed to/from EGL/GL are properly aligned. +// This prevents crashes with certain backends (e.g. OSMesa). +#define USE_ALIGNED_BUFFERS 1 + +// Set these to 1 if you want to instrument either guest's or host's code for +// time-per-call printing. +#define INSTRUMENT_TIMING_GUEST 0 +#define INSTRUMENT_TIMING_HOST 0 + +// Set to 1 to print to logcat for every GL call encoded. +#define DLOG_ALL_ENCODES 0 + +// Set to 1 to check GL errors before and after every decoder call. +#define DECODER_CHECK_GL_ERRORS 0 + +EntryPoint * ApiGen::findEntryByName(const std::string & name) +{ + EntryPoint * entry = NULL; + + size_t n = this->size(); + for (size_t i = 0; i < n; i++) { + if (at(i).name() == name) { + entry = &(at(i)); + break; + } + } + return entry; +} + +void ApiGen::printHeader(FILE *fp) const +{ + fprintf(fp, "// Generated Code - DO NOT EDIT !!\n"); + fprintf(fp, "// generated by 'emugen'\n"); +} + +int ApiGen::genProcTypes(const std::string &filename, SideType side) +{ + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return -1; + } + printHeader(fp); + + const char* basename = m_basename.c_str(); + + fprintf(fp, "#ifndef __%s_%s_proc_t_h\n", basename, sideString(side)); + fprintf(fp, "#define __%s_%s_proc_t_h\n", basename, sideString(side)); + fprintf(fp, "\n\n"); + fprintf(fp, "\n#include \"%s_types.h\"\n",basename); + fprintf(fp, "#ifndef %s_APIENTRY\n",basename); + fprintf(fp, "#define %s_APIENTRY \n",basename); + fprintf(fp, "#endif\n"); + + + for (size_t i = 0; i < size(); i++) { + EntryPoint *e = &at(i); + + fprintf(fp, "typedef "); + e->retval().printType(fp); + fprintf(fp, " (%s_APIENTRY *%s_%s_proc_t) (", basename, e->name().c_str(), sideString(side)); + if (side == CLIENT_SIDE) { fprintf(fp, "void * ctx"); } + if (e->customDecoder() && side == SERVER_SIDE) { fprintf(fp, "void *ctx"); } + + VarsArray & evars = e->vars(); + size_t n = evars.size(); + + for (size_t j = 0; j < n; j++) { + if (!evars[j].isVoid()) { + if (j != 0 || side == CLIENT_SIDE || (side == SERVER_SIDE && e->customDecoder())) fprintf(fp, ", "); + evars[j].printType(fp); + } + } + fprintf(fp, ");\n"); + + if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) { + fprintf(fp, "typedef "); + e->retval().printType(fp); + fprintf(fp, " (%s_APIENTRY *%s_dec_%s_proc_t) (", basename, e->name().c_str(), sideString(side)); + + VarsArray & evars = e->vars(); + size_t n = evars.size(); + + for (size_t j = 0; j < n; j++) { + if (!evars[j].isVoid()) { + if (j != 0) fprintf(fp, ", "); + evars[j].printType(fp); + } + } + fprintf(fp, ");\n"); + } + } + fprintf(fp, "\n\n#endif\n"); + return 0; +} + +int ApiGen::genFuncTable(const std::string &filename, SideType side) +{ + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return -1; + } + printHeader(fp); + + fprintf(fp, "#ifndef __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side)); + fprintf(fp, "#define __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side)); + fprintf(fp, "\n\n"); + fprintf(fp, "static const struct _%s_funcs_by_name {\n", m_basename.c_str()); + fprintf(fp, + "\tconst char *name;\n" \ + "\tvoid *proc;\n" \ + "} %s_funcs_by_name[] = {\n", m_basename.c_str()); + + + for (size_t i = 0; i < size(); i++) { + EntryPoint *e = &at(i); + if (e->notApi()) continue; + fprintf(fp, "\t{\"%s\", (void*)%s},\n", e->name().c_str(), e->name().c_str()); + } + fprintf(fp, "};\n"); + fprintf(fp, "static const int %s_num_funcs = sizeof(%s_funcs_by_name) / sizeof(struct _%s_funcs_by_name);\n", + m_basename.c_str(), m_basename.c_str(), m_basename.c_str()); + fprintf(fp, "\n\n#endif\n"); + return 0; +} + +int ApiGen::genContext(const std::string & filename, SideType side) +{ + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return -1; + } + printHeader(fp); + + fprintf(fp, "#ifndef __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side)); + fprintf(fp, "#define __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side)); + + fprintf(fp, "\n#include \"%s_%s_proc.h\"\n", + m_basename.c_str(), + side == CLIENT_SIDE ? "client" : "server"); + fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str()); + + StringVec & contextHeaders = side == CLIENT_SIDE ? m_clientContextHeaders : m_serverContextHeaders; + for (size_t i = 0; i < contextHeaders.size(); i++) { + fprintf(fp, "#include %s\n", contextHeaders[i].c_str()); + } + fprintf(fp, "\n"); + + fprintf(fp, "\nstruct %s_%s_context_t {\n\n", + m_basename.c_str(), sideString(side)); + + // API entry points + for (size_t i = 0; i < size(); i++) { + EntryPoint *e = &at(i); + if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) { + fprintf(fp, "\t%s_dec_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str()); + fprintf(fp, "\t%s_%s_proc_t %s_dec;\n", e->name().c_str(), sideString(side), e->name().c_str()); + } else { + fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str()); + } + } + + // virtual destructor + fprintf(fp, "\tvirtual ~%s_%s_context_t() {}\n", m_basename.c_str(), sideString(side)); + // accessor + if (side == CLIENT_SIDE || side == WRAPPER_SIDE) { + fprintf(fp, "\n\ttypedef %s_%s_context_t *CONTEXT_ACCESSOR_TYPE(void);\n", + m_basename.c_str(), sideString(side)); + fprintf(fp, "\tstatic void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);\n"); + } + + // init function + fprintf(fp, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n"); + + //client site set error virtual func + if (side == CLIENT_SIDE) { + fprintf(fp, "\tvirtual void setError(unsigned int error){ (void)error; };\n"); + fprintf(fp, "\tvirtual unsigned int getError(){ return 0; };\n"); + } + + fprintf(fp, "};\n"); + + fprintf(fp, "\n#endif\n"); + fclose(fp); + return 0; +} + +int ApiGen::genEntryPoints(const std::string & filename, SideType side) +{ + + if (side != CLIENT_SIDE && side != WRAPPER_SIDE) { + fprintf(stderr, "Entry points are only defined for Client and Wrapper components\n"); + return -999; + } + + + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return errno; + } + + printHeader(fp); + fprintf(fp, "#include <stdio.h>\n"); + fprintf(fp, "#include <stdlib.h>\n"); + fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(side)); + fprintf(fp, "\n"); + + fprintf(fp, "extern \"C\" {\n"); + + for (size_t i = 0; i < size(); i++) { + fprintf(fp, "\t"); at(i).print(fp, false); fprintf(fp, ";\n"); + } + fprintf(fp, "};\n\n"); + + fprintf(fp, "#ifndef GET_CONTEXT\n"); + fprintf(fp, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n", + m_basename.c_str(), sideString(side)); + + fprintf(fp, + "void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n", + m_basename.c_str(), sideString(side)); + fprintf(fp, "#define GET_CONTEXT %s_%s_context_t * ctx = getCurrentContext()\n", + m_basename.c_str(), sideString(side)); + fprintf(fp, "#endif\n\n"); + + + for (size_t i = 0; i < size(); i++) { + EntryPoint *e = &at(i); + e->print(fp); + fprintf(fp, "{\n"); + fprintf(fp, "\tGET_CONTEXT;\n"); + + bool shouldReturn = !e->retval().isVoid(); + bool shouldCallWithContext = (side == CLIENT_SIDE); + //param check + if (shouldCallWithContext) { + for (size_t j=0; j<e->vars().size(); j++) { + if (e->vars()[j].paramCheckExpression() != "") + fprintf(fp, "\t%s\n", e->vars()[j].paramCheckExpression().c_str()); + } + } + fprintf(fp, "\t%sctx->%s(%s", + shouldReturn ? "return " : "", + e->name().c_str(), + shouldCallWithContext ? "ctx" : ""); + size_t nvars = e->vars().size(); + + for (size_t j = 0; j < nvars; j++) { + if (!e->vars()[j].isVoid()) { + fprintf(fp, "%s %s", + j != 0 || shouldCallWithContext ? "," : "", + e->vars()[j].name().c_str()); + } + } + fprintf(fp, ");\n"); + fprintf(fp, "}\n\n"); + } + fclose(fp); + return 0; +} + + +int ApiGen::genOpcodes(const std::string &filename) +{ + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return errno; + } + + printHeader(fp); + fprintf(fp, "#ifndef __GUARD_%s_opcodes_h_\n", m_basename.c_str()); + fprintf(fp, "#define __GUARD_%s_opcodes_h_\n\n", m_basename.c_str()); + for (size_t i = 0; i < size(); i++) { + fprintf(fp, "#define OP_%s \t\t\t\t\t%u\n", at(i).name().c_str(), (unsigned int)i + m_baseOpcode); + } + fprintf(fp, "#define OP_last \t\t\t\t\t%u\n", (unsigned int)size() + m_baseOpcode); + fprintf(fp,"\n\n#endif\n"); + fclose(fp); + return 0; + +} +int ApiGen::genAttributesTemplate(const std::string &filename ) +{ + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return -1; + } + + for (size_t i = 0; i < size(); i++) { + if (at(i).hasPointers()) { + fprintf(fp, "#"); + at(i).print(fp); + fprintf(fp, "%s\n\n", at(i).name().c_str()); + } + } + fclose(fp); + return 0; +} + +int ApiGen::genEncoderHeader(const std::string &filename) +{ + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return -1; + } + + printHeader(fp); + std::string classname = m_basename + "_encoder_context_t"; + + fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str()); + fprintf(fp, "#define GUARD_%s\n\n", classname.c_str()); + + fprintf(fp, "#include \"IOStream.h\"\n"); + fprintf(fp, "#include \"ChecksumCalculator.h\"\n"); + fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(CLIENT_SIDE)); + + for (size_t i = 0; i < m_encoderHeaders.size(); i++) { + fprintf(fp, "#include %s\n", m_encoderHeaders[i].c_str()); + } + fprintf(fp, "\n"); + + fprintf(fp, "struct %s : public %s_%s_context_t {\n\n", + classname.c_str(), m_basename.c_str(), sideString(CLIENT_SIDE)); + fprintf(fp, "\tIOStream *m_stream;\n"); + fprintf(fp, "\tChecksumCalculator *m_checksumCalculator;\n\n"); + + fprintf(fp, "\t%s(IOStream *stream, ChecksumCalculator *checksumCalculator);\n", classname.c_str()); + fprintf(fp, "\tvirtual uint64_t lockAndWriteDma(void* data, uint32_t sz) { return 0; }\n"); + fprintf(fp, "};\n\n"); + + fprintf(fp, "#endif // GUARD_%s\n", classname.c_str()); + + fclose(fp); + 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 +// +enum class EncodingSizeFlags { + None = 0, + DmaPtrOnly = 1, + ExcludeOut = 2, + UseExistingVar = 4, +}; + +static int getVarEncodingSizeExpression( + Var& var, EntryPoint* e, char* buff, size_t bufflen, + EncodingSizeFlags flags) +{ + if (!var.isPointer()) { + snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes()); + return 0; + } + + if ((flags & EncodingSizeFlags::DmaPtrOnly) != 0) { + snprintf(buff, bufflen, "8"); + } else if ((flags & EncodingSizeFlags::ExcludeOut) != 0 && + !(var.pointerDir() & Var::POINTER_IN)) { + snprintf(buff, bufflen, "0"); + } else if ((flags & EncodingSizeFlags::UseExistingVar) != 0) { + snprintf(buff, bufflen, "__size_%s", var.name().c_str()); + } else { + 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 1; +} + +static int writeVarEncodingSize(Var& var, bool excludeOutVars, FILE* fp) +{ + int ret = 0; + if (!var.isPointer()) { + fprintf(fp, "%u", (unsigned int) var.type()->bytes()); + } else { + ret = 1; + if (var.isDMA()) { + fprintf(fp, "8"); + return ret; + } + + if (excludeOutVars && !(var.pointerDir() & Var::POINTER_IN)) { + fprintf(fp, "0"); + } else { + 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 + if (var.isDMA()) { + fprintf(fp, "\t*(uint64_t *)(ptr) = ctx->lockAndWriteDma(%s, __size_%s); ptr += 8;\n", varname, varname); + } else { + 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\tmemcpy(ptr, &%s, %u); ptr += %u;\n", + varname, + (unsigned) var.type()->bytes(), + (unsigned) 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); + fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(&__size_%s,4);\n", varname); + if (var.nullAllowed()) { + fprintf(fp, "\tif (%s != NULL) {\n", varname); + } + if (var.writeExpression() != "") { + fprintf(fp, "%s", var.writeExpression().c_str()); + } else { + fprintf(fp, "\t\tstream->writeFully(%s, __size_%s);\n", varname, varname); + fprintf(fp, "\t\tif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n", varname, varname); + } + if (var.nullAllowed()) fprintf(fp, "\t}\n"); +} +#endif /* WITH_LARGE_SUPPORT */ + +static void writeEncodingChecksumValidatorOnReturn(const char* funcName, FILE* fp) { + fprintf(fp, "\tif (useChecksum) {\n" + "\t\tunsigned char *checksumBufPtr = NULL;\n" + "\t\tunsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];\n" + "\t\tif (checksumSize > 0) checksumBufPtr = &checksumBuf[0];\n" + "\t\tstream->readback(checksumBufPtr, checksumSize);\n" + "\t\tif (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {\n" + "\t\t\tALOGE(\"%s: GL communication error, please report this issue to b.android.com.\\n\");\n" + "\t\t\tabort();\n" + "\t\t}\n" + "\t}\n", + funcName + ); +} + +static void addGuestTimePrinting(const EntryPoint* e, bool hasTimeBeforeReadback, + FILE* fp) { +#if INSTRUMENT_TIMING_GUEST + fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts1);\n"); + fprintf(fp, "\tlong timeDiff = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts0.tv_sec*1000000 + ts0.tv_nsec/1000);\n"); + if (hasTimeBeforeReadback) { + fprintf(fp, "\tlong timeDiff2 = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts2.tv_sec*1000000 + ts2.tv_nsec/1000);\n"); + fprintf(fp, "\tALOGW(\"%s: %%ld (%%ld) us\\n\", timeDiff, timeDiff2);\n", e->name().c_str()); + } else { + fprintf(fp, "\tALOGW(\"%s: %%ld us\\n\", timeDiff);\n", e->name().c_str()); + } +#endif +} + +int ApiGen::genEncoderImpl(const std::string &filename) +{ + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return -1; + } + + printHeader(fp); + fprintf(fp, "\n\n"); + fprintf(fp, "#include <string.h>\n"); + fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str()); + fprintf(fp, "#include \"%s_enc.h\"\n\n\n", m_basename.c_str()); + fprintf(fp, "#include <vector>\n\n"); + fprintf(fp, "#include <stdio.h>\n\n"); + fprintf(fp, "namespace {\n\n"); + + // unsupport printout + fprintf(fp, + "void enc_unsupported()\n" + "{\n" + "\tALOGE(\"Function is unsupported\\n\");\n" + "}\n\n"); + + // entry points; + std::string classname = m_basename + "_encoder_context_t"; + + size_t n = size(); + for (size_t i = 0; i < n; i++) { + EntryPoint *e = &at(i); + + if (e->unsupported()) continue; + + e->print(fp, true, "_enc", /* classname + "::" */"", "void *self"); + fprintf(fp, "{\n"); +#if DLOG_ALL_ENCODES + fprintf(fp, "ALOGD(\"%%s: enter\", __FUNCTION__);\n"); +#endif + +#if INSTRUMENT_TIMING_GUEST + fprintf(fp, "\tstruct timespec ts0, ts1;\n"); + fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts0);\n"); +#endif + +// fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str()); + fprintf(fp, "\n\t%s *ctx = (%s *)self;\n", + classname.c_str(), + classname.c_str()); + fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n" + "\tChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;\n" + "\tbool useChecksum = checksumCalculator->getVersion() > 0;\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), + EncodingSizeFlags::None); + fprintf(fp, "%s;\n", buff); + } + + bool hasLargeFields = false; +#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 (without checksum) + fprintf(fp, "\t unsigned char *ptr;\n"); + fprintf(fp, "\t unsigned char *buf;\n"); + fprintf(fp, "\t const size_t sizeWithoutChecksum = 8"); + + for (j = 0; j < maxvars; j++) { + fprintf(fp, " + "); + npointers += writeVarEncodingSize(evars[j], true, fp); + } + if (npointers > 0) { + fprintf(fp, " + %zu*4", npointers); + } + fprintf(fp, ";\n"); + + // Then, size of the checksum string + fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n"); + + // And, size of the whole thing + fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\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+checksum_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, "\tbuf = stream->alloc(totalSize);\n"); + + } else { + hasLargeFields = true; + // allocate buffer from the stream until the first large variable + fprintf(fp, "\tbuf = 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], false, fp); + } + if (npointers > 0) { + fprintf(fp, "%s%zu*4", plus, npointers); plus = " + "; + } + } + fprintf(fp,");\n"); + } + fprintf(fp, "\tptr = buf;\n"); + + // encode packet header if needed. + if (nvars == 0) { + fprintf(fp, "\tint tmp = OP_%s;memcpy(ptr, &tmp, 4); ptr += 4;\n", e->name().c_str()); + fprintf(fp, "\tmemcpy(ptr, &totalSize, 4); ptr += 4;\n\n"); + } + + if (maxvars == 0) { + fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n"); + break; + } + + // encode non-large fields in this fragment + for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) { + writeVarEncodingExpression(evars[j],fp); + } + + fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n"); + // 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, "\tunsigned char *ptr;\n"); + fprintf(fp, "\tunsigned char *buf;\n"); + fprintf(fp, "\tconst size_t sizeWithoutChecksum = 8"); + for (size_t j = 0; j < nvars; j++) { + npointers += getVarEncodingSizeExpression( + evars[j], e, buff, sizeof(buff), + (evars[j].isDMA() ? EncodingSizeFlags::DmaPtrOnly + : EncodingSizeFlags::None) | + EncodingSizeFlags::UseExistingVar | + EncodingSizeFlags::ExcludeOut); + fprintf(fp, " + %s", buff); + } + fprintf(fp, " + %u * 4;\n", (unsigned int)npointers); + // Size of checksum + fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n"); + // Size of the whole thing + fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\n"); + + // allocate buffer from the stream; + fprintf(fp, "\tptr = buf = stream->alloc(totalSize);\n\n"); + + // encode into the stream; + fprintf(fp, "\tint tmp = OP_%s; memcpy(ptr, &tmp, 4); ptr += 4;\n", e->name().c_str()); + fprintf(fp, "\tmemcpy(ptr, &totalSize, 4); ptr += 4;\n\n"); + + // out variables + for (size_t j = 0; j < nvars; j++) { + writeVarEncodingExpression(evars[j], fp); + } + + fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr - buf);\n"); +#endif /* !WITH_LARGE_SUPPORT */ + + // checksum + if (hasLargeFields) { + fprintf(fp, "\tbuf = stream->alloc(checksumSize);\n"); + fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);\n\n"); + } else { + fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;\n\n"); + } + + // in variables; + bool hasTimeBeforeReadback = false; + bool hasReadbackChecksum = false; + 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(); + const char* indent = "\t"; + +#if INSTRUMENT_TIMING_GUEST + if (!hasTimeBeforeReadback) { + hasTimeBeforeReadback = true; + // Let's flush the stream before measuring the time. + fprintf(fp, "\tstream->flush();\n"); + fprintf(fp, "\tstruct timespec ts2;\n"); + fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts2);\n"); + } +#endif + if (evars[j].nullAllowed()) { + fprintf(fp, "\tif (%s != NULL) {\n",varname); + indent = "\t\t"; + } + + if (evars[j].guestUnpackExpression() != "") { + fprintf(fp, "%s%s;\n", indent, evars[j].guestUnpackExpression().c_str()); + } else { + fprintf(fp, "%sstream->readback(%s, __size_%s);\n", + indent, varname, varname); + } + fprintf(fp, "%sif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n", + indent, varname, varname); + if (evars[j].nullAllowed()) { + fprintf(fp, "\t}\n"); + } + hasReadbackChecksum = true; + } + } + } +//XXX fprintf(fp, "\n\tDBG(\"<<<< %s\\n\");\n", e->name().c_str()); + + // todo - return value for pointers + if (e->retval().isPointer()) { + fprintf(stderr, "WARNING: %s : return value of pointer is unsupported\n", + e->name().c_str()); + if (e->flushOnEncode()) { + fprintf(fp, "\tstream->flush();\n"); + } + addGuestTimePrinting(e, hasTimeBeforeReadback, fp); + fprintf(fp, "\t return NULL;\n"); + } else if (e->retval().type()->name() != "void") { +#if INSTRUMENT_TIMING_GUEST + if (!hasTimeBeforeReadback) { + hasTimeBeforeReadback = true; + fprintf(fp, "\tstream->flush();\n"); + fprintf(fp, "\tstruct timespec ts2;\n"); + fprintf(fp, "\tclock_gettime(CLOCK_REALTIME, &ts2);\n"); + } +#endif + + fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str()); + fprintf(fp, "\tstream->readback(&retval, %u);\n",(unsigned) e->retval().type()->bytes()); + fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(&retval, %u);\n", + (unsigned) e->retval().type()->bytes()); + writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp); + addGuestTimePrinting(e, hasTimeBeforeReadback, fp); + fprintf(fp, "\treturn retval;\n"); + } else { + if (e->flushOnEncode()) fprintf(fp, "\tstream->flush();\n"); + if (hasReadbackChecksum) writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp); + addGuestTimePrinting(e, hasTimeBeforeReadback, fp); + } + fprintf(fp, "}\n\n"); + } + + fprintf(fp, "} // namespace\n\n"); + + // constructor + fprintf(fp, "%s::%s(IOStream *stream, ChecksumCalculator *checksumCalculator)\n{\n", classname.c_str(), classname.c_str()); + fprintf(fp, "\tm_stream = stream;\n"); + fprintf(fp, "\tm_checksumCalculator = checksumCalculator;\n\n"); + + for (size_t i = 0; i < n; i++) { + EntryPoint *e = &at(i); + if (e->unsupported()) { + fprintf(fp, + "\tthis->%s = (%s_%s_proc_t) &enc_unsupported;\n", + e->name().c_str(), + e->name().c_str(), + sideString(CLIENT_SIDE)); + } else { + fprintf(fp, + "\tthis->%s = &%s_enc;\n", + e->name().c_str(), + e->name().c_str()); + } + } + fprintf(fp, "}\n\n"); + + fclose(fp); + return 0; +} + + +int ApiGen::genDecoderHeader(const std::string &filename) +{ + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return -1; + } + + printHeader(fp); + std::string classname = m_basename + "_decoder_context_t"; + + fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str()); + fprintf(fp, "#define GUARD_%s\n\n", classname.c_str()); + + fprintf(fp, "#include \"OpenglRender/IOStream.h\"\n"); + fprintf(fp, "#include \"ChecksumCalculator.h\"\n"); + fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE)); + fprintf(fp, "#include \"emugl/common/logging.h\"\n"); +#if INSTRUMENT_TIMING_HOST + fprintf(fp, "#include \"time.h\"\n"); +#endif + + for (size_t i = 0; i < m_decoderHeaders.size(); i++) { + fprintf(fp, "#include %s\n", m_decoderHeaders[i].c_str()); + } + fprintf(fp, "\n"); + + fprintf(fp, "struct %s : public %s_%s_context_t {\n\n", + classname.c_str(), m_basename.c_str(), sideString(SERVER_SIDE)); + fprintf(fp, "\tsize_t decode(void *buf, size_t bufsize, IOStream *stream, ChecksumCalculator* checksumCalc);\n"); + fprintf(fp, "\n};\n\n"); + fprintf(fp, "#endif // GUARD_%s\n", classname.c_str()); + + fclose(fp); + return 0; +} + +int ApiGen::genContextImpl(const std::string &filename, SideType side) +{ + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return -1; + } + printHeader(fp); + + std::string classname = m_basename + "_" + sideString(side) + "_context_t"; + size_t n = size(); + fprintf(fp, "\n\n#include <string.h>\n"); + fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(side)); + fprintf(fp, "#include <stdio.h>\n\n"); + + fprintf(fp, "int %s::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)\n{\n", classname.c_str()); + for (size_t i = 0; i < n; i++) { + EntryPoint *e = &at(i); + if (side == SERVER_SIDE && e->customDecoder() && !e->notApi()) { + fprintf(fp, "\t%s = (%s_dec_%s_proc_t) getProc(\"%s\", userData);\n", + e->name().c_str(), + e->name().c_str(), + sideString(side), + e->name().c_str()); + } else { + fprintf(fp, "\t%s = (%s_%s_proc_t) getProc(\"%s\", userData);\n", + e->name().c_str(), + e->name().c_str(), + sideString(side), + e->name().c_str()); + } + } + fprintf(fp, "\treturn 0;\n"); + fprintf(fp, "}\n\n"); + fclose(fp); + return 0; +} + +int ApiGen::genDecoderImpl(const std::string &filename) +{ + FILE *fp = fopen(filename.c_str(), "wt"); + if (fp == NULL) { + perror(filename.c_str()); + return -1; + } + + printHeader(fp); + + std::string classname = m_basename + "_decoder_context_t"; + + size_t n = size(); + + bool changesChecksum = false; + for (size_t i = 0; i < size(); ++i) { + const EntryPoint& ep = at(i); + if (ep.name().find("SelectChecksum") != std::string::npos) { + changesChecksum = true; + break; + } + } + + fprintf(fp, "\n\n#include <string.h>\n"); + fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str()); + fprintf(fp, "#include \"%s_dec.h\"\n\n\n", m_basename.c_str()); + fprintf(fp, "#include \"ProtocolUtils.h\"\n\n"); + fprintf(fp, "#include \"ChecksumCalculatorThreadInfo.h\"\n\n"); + fprintf(fp, "#include <stdio.h>\n\n"); + fprintf(fp, "typedef unsigned int tsize_t; // Target \"size_t\", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled.\n\n"); + + // helper macros + fprintf(fp, + "#ifdef OPENGL_DEBUG_PRINTOUT\n" + "# define DEBUG(...) do { if (emugl_cxt_logger) { emugl_cxt_logger(__VA_ARGS__); } } while(0)\n" + "#else\n" + "# define DEBUG(...) ((void)0)\n" + "#endif\n\n"); + + fprintf(fp, +#if DECODER_CHECK_GL_ERRORS + "#define CHECK_GL_ERRORS\n" +#endif + "#ifdef CHECK_GL_ERRORS\n" + "# define SET_LASTCALL(name) sprintf(lastCall, #name)\n" + "#else\n" + "# define SET_LASTCALL(name)\n" + "#endif\n"); + + // helper templates + fprintf(fp, "using namespace emugl;\n\n"); + + // decoder switch; + fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream, ChecksumCalculator* checksumCalc) {\n", classname.c_str()); + fprintf(fp, +"\tif (len < 8) return 0; \n\ +#ifdef CHECK_GL_ERRORS\n\ +\tchar lastCall[256] = {0};\n\ +#endif\n\ +\tunsigned char *ptr = (unsigned char *)buf;\n\ +\tconst unsigned char* const end = (const unsigned char*)buf + len;\n"); + if (!changesChecksum) { + fprintf(fp, +R"( const size_t checksumSize = checksumCalc->checksumByteSize(); + const bool useChecksum = checksumSize > 0; +)"); + } + fprintf(fp, +"\twhile (end - ptr >= 8) {\n\ +\t\tuint32_t opcode = *(uint32_t *)ptr; \n\ +\t\tint32_t packetLen = *(int32_t *)(ptr + 4);\n\ +\t\tif (end - ptr < packetLen) return ptr - (unsigned char*)buf;\n"); + if (changesChecksum) { + fprintf(fp, +R"( // Do this on every iteration, as some commands may change the checksum + // calculation parameters. + const size_t checksumSize = checksumCalc->checksumByteSize(); + const bool useChecksum = checksumSize > 0; +)"); + } + fprintf(fp, "\t\tswitch(opcode) {\n"); + + for (size_t f = 0; f < n; f++) { + enum Pass_t { + PASS_FIRST = 0, + PASS_VariableDeclarations = PASS_FIRST, + PASS_Protocol, + PASS_TmpBuffAlloc, + PASS_MemAlloc, + PASS_DebugPrint, + PASS_FunctionCall, + PASS_FlushOutput, + PASS_Epilog, + PASS_LAST }; + EntryPoint *e = &(*this)[f]; + + // construct a printout string; + std::string printString; + for (size_t i = 0; i < e->vars().size(); i++) { + Var *v = &e->vars()[i]; + if (!v->isVoid()) printString += (v->isPointer() ? "%p(%u)" : v->type()->printFormat()) + " "; + } + + // TODO - add for return value; + fprintf(fp, "\t\tcase OP_%s: {\n", e->name().c_str()); + +#if INSTRUMENT_TIMING_HOST + fprintf(fp, "\t\t\tstruct timespec ts0, ts1, ts2;\n"); + fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts0);\n"); +#endif + bool totalTmpBuffExist = false; + std::string totalTmpBuffOffset = "0"; + std::string *tmpBufOffset = new std::string[e->vars().size()]; + + // construct retval type string + std::string retvalType; + if (!e->retval().isVoid()) { + retvalType = e->retval().type()->name(); + } + + for (int pass = PASS_FIRST; pass < PASS_LAST; pass++) { +#if INSTRUMENT_TIMING_HOST + if (pass == PASS_FunctionCall) { + fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts2);\n"); + } +#endif + if (pass == PASS_FunctionCall && + !e->retval().isVoid() && + !e->retval().isPointer()) { + fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(), + totalTmpBuffOffset.c_str()); + } + + if (pass == PASS_FunctionCall) { + if (e->customDecoder() && !e->notApi()) { + fprintf(fp, "\t\t\tthis->%s_dec(", e->name().c_str()); + } else { + fprintf(fp, "\t\t\tthis->%s(", e->name().c_str()); + } + if (e->customDecoder()) { + fprintf(fp, "this"); // add a context to the call + } + } else if (pass == PASS_DebugPrint) { + if (strstr(m_basename.c_str(), "gl")) { + fprintf(fp, "\t\t#ifdef CHECK_GL_ERRORS\n"); + fprintf(fp, "\t\tGLint err = this->glGetError();\n"); + fprintf(fp, "\t\tif (err) fprintf(stderr, \"%s Error (pre-call): 0x%%X before %s\\n\", err);\n", + m_basename.c_str(), e->name().c_str()); + fprintf(fp, "\t\t#endif\n"); + } + fprintf(fp, + "\t\t\tDEBUG(\"%s(%%p): %s(%s)\\n\", stream", + m_basename.c_str(), + e->name().c_str(), + printString.c_str()); + if (e->vars().size() > 0 && !e->vars()[0].isVoid()) { + fprintf(fp, ", "); + } + } + + std::string varoffset = "8"; // skip the header + VarsArray & evars = e->vars(); + // allocate memory for out pointers; + for (size_t j = 0; j < evars.size(); j++) { + Var *v = & evars[j]; + if (v->isVoid()) { + continue; + } + const char* var_name = v->name().c_str(); + const char* var_type_name = v->type()->name().c_str(); + const unsigned var_type_bytes = v->type()->bytes(); + + if ((pass == PASS_FunctionCall) && + (j != 0 || e->customDecoder())) { + fprintf(fp, ", "); + } + if (pass == PASS_DebugPrint && j != 0) { + fprintf(fp, ", "); + } + + if (v->isPointer() && v->isDMA()) { + if (pass == PASS_VariableDeclarations) { + fprintf(fp, + "\t\t\tuint64_t var_%s_guest_paddr = Unpack<uint64_t,uint64_t>(ptr + %s);\n" + "\t\t\t%s var_%s = stream->getDmaForReading(var_%s_guest_paddr);\n", + var_name, + varoffset.c_str(), + var_type_name, + var_name, + var_name); + } + if (pass == PASS_FunctionCall || + pass == PASS_DebugPrint) { + fprintf(fp, "var_%s", var_name); + } + varoffset += " + 8"; + } + + if (!v->isPointer()) { + if (pass == PASS_VariableDeclarations) { + fprintf(fp, + "\t\t\t%s var_%s = Unpack<%s,uint%u_t>(ptr + %s);\n", + var_type_name, + var_name, + var_type_name, + var_type_bytes * 8U, + varoffset.c_str()); + } + + if (pass == PASS_FunctionCall || + pass == PASS_DebugPrint) { + fprintf(fp, "var_%s", var_name); + } + varoffset += " + " + toString(var_type_bytes); + continue; + } + + if (pass == PASS_VariableDeclarations) { + fprintf(fp, + "\t\t\tuint32_t size_%s __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + %s);\n", + var_name, + varoffset.c_str()); + } + + if (!v->isDMA()) { + if (v->pointerDir() & Var::POINTER_IN) { + if (pass == PASS_VariableDeclarations) { + #if USE_ALIGNED_BUFFERS + fprintf(fp, + "\t\t\tInputBuffer inptr_%s(ptr + %s + 4, size_%s);\n", + var_name, + varoffset.c_str(), + var_name); + if (v->unpackExpression().size() > 0) { + fprintf(fp, + "\t\t\tvoid* inptr_%s_unpacked;\n" + "\t\t\t%s;\n", + var_name, + v->unpackExpression().c_str()); + } + + } + if (pass == PASS_FunctionCall && + v->pointerDir() == Var::POINTER_IN) { + if (v->nullAllowed()) { + fprintf(fp, + "size_%s == 0 ? nullptr : (%s)(inptr_%s.get())", + var_name, + var_type_name, + var_name); + } else { + if (v->unpackExpression().size() > 0) { + fprintf(fp, + "(%s)(inptr_%s_unpacked)", + var_type_name, + var_name); + } else { + fprintf(fp, + "(%s)(inptr_%s.get())", + var_type_name, + var_name); + } + } + } else if (pass == PASS_DebugPrint && + v->pointerDir() == Var::POINTER_IN) { + fprintf(fp, + "(%s)(inptr_%s.get()), size_%s", + var_type_name, + var_name, + var_name); + } + #else // !USE_ALIGNED_BUFFERS + fprintf(fp, + "unsigned char *inptr_%s = (ptr + %s + 4);\n", + var_name, + varoffset.c_str()); + } + if (pass == PASS_FunctionCall && + v->pointerDir() == Var::POINTER_IN) { + if (v->nullAllowed()) { + fprintf(fp, + "size_%s == 0 ? NULL : (%s)(inptr_%s)", + var_name, + var_type_name, + var_name); + } else { + fprintf(fp, + "(%s)(inptr_%s)", + var_type_name, + var_name); + } + } else if (pass == PASS_DebugPrint && + v->pointerDir() == Var::POINTER_IN) { + fprintf(fp, + "(%s)(inptr_%s), size_%s", + var_type_name, + var_name, + var_name); + } + #endif // !USE_ALIGNED_BUFFERS + varoffset += " + 4 + size_"; + varoffset += var_name; + } + if (v->pointerDir() & Var::POINTER_OUT) { // out pointer; + if (pass == PASS_TmpBuffAlloc) { + if (!totalTmpBuffExist) { + fprintf(fp, + "\t\t\tsize_t totalTmpSize = size_%s;\n", + var_name); + } else { + fprintf(fp, + "\t\t\ttotalTmpSize += size_%s;\n", + var_name); + } + tmpBufOffset[j] = totalTmpBuffOffset; + totalTmpBuffOffset += " + size_"; + totalTmpBuffOffset += var_name; + totalTmpBuffExist = true; + } else if (pass == PASS_MemAlloc) { + #if USE_ALIGNED_BUFFERS + fprintf(fp, + "\t\t\tOutputBuffer outptr_%s(&tmpBuf[%s], size_%s);\n", + var_name, + tmpBufOffset[j].c_str(), + var_name); + // If both input and output variable, initialize with the input. + if (v->pointerDir() == Var::POINTER_INOUT) { + fprintf(fp, + "\t\t\tmemcpy(outptr_%s.get(), inptr_%s.get(), size_%s);\n", + var_name, + var_name, + var_name); + } + + if (v->hostPackExpression() != "") { + fprintf(fp, "\t\t\tvoid* forPacking_%s = nullptr;\n", var_name); + } + if (v->hostPackTmpAllocExpression() != "") { + fprintf(fp, "\t\t\t%s;\n", v->hostPackTmpAllocExpression().c_str()); + } + } else if (pass == PASS_FunctionCall) { + if (v->hostPackExpression() != "") { + fprintf(fp, + "(%s)(forPacking_%s)", + var_type_name, + var_name); + } else { + if (v->nullAllowed()) { + fprintf(fp, + "size_%s == 0 ? nullptr : (%s)(outptr_%s.get())", + var_name, + var_type_name, + var_name); + } else { + fprintf(fp, + "(%s)(outptr_%s.get())", + var_type_name, + var_name); + } + } + } else if (pass == PASS_DebugPrint) { + fprintf(fp, + "(%s)(outptr_%s.get()), size_%s", + var_type_name, + var_name, + var_name); + } + if (pass == PASS_FlushOutput) { + if (v->hostPackExpression() != "") { + fprintf(fp, + "\t\t\tif (size_%s) {\n" + "\t\t\t%s; }\n", + var_name, + v->hostPackExpression().c_str()); + } + fprintf(fp, + "\t\t\toutptr_%s.flush();\n", + var_name); + } + #else // !USE_ALIGNED_BUFFERS + fprintf(fp, + "\t\t\tunsigned char *outptr_%s = &tmpBuf[%s];\n", + var_name, + tmpBufOffset[j].c_str()); + fprintf(fp, + "\t\t\tmemset(outptr_%s, 0, %s);\n", + var_name, + toString(v->type()->bytes()).c_str()); + } else if (pass == PASS_FunctionCall) { + if (v->nullAllowed()) { + fprintf(fp, + "size_%s == 0 ? NULL : (%s)(outptr_%s)", + var_name, + var_type_name, + var_name); + } else { + fprintf(fp, + "(%s)(outptr_%s)", + var_type_name, + var_name); + } + } else if (pass == PASS_DebugPrint) { + fprintf(fp, + "(%s)(outptr_%s), size_%s", + var_type_name, + var_name, + varoffset.c_str()); + } + #endif // !USE_ALIGNED_BUFFERS + if (v->pointerDir() == Var::POINTER_OUT) { + varoffset += " + 4"; + } + } + } + } + + if (pass == PASS_Protocol) { + fprintf(fp, + "\t\t\tif (useChecksum) {\n" + "\t\t\t\tChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, %s, " + "ptr + %s, checksumSize, " + "\n\t\t\t\t\t\"%s::decode," + " OP_%s: GL checksumCalculator failure\\n\");\n" + "\t\t\t}\n", + varoffset.c_str(), + varoffset.c_str(), + classname.c_str(), + e->name().c_str() + ); + + varoffset += " + 4"; + } + + if (pass == PASS_FunctionCall || + pass == PASS_DebugPrint) { + fprintf(fp, ");\n"); + + if (pass == PASS_FunctionCall) { + // unlock all dma buffers that have been passed + for (size_t j = 0; j < evars.size(); j++) { + Var *v = & evars[j]; + if (v->isVoid()) { + continue; + } + const char* var_name = v->name().c_str(); + if (v->isDMA()) { + fprintf(fp, + "\t\t\tstream->unlockDma(var_%s_guest_paddr);\n", + var_name); + } + } + } + } + + if (pass == PASS_TmpBuffAlloc) { + if (!e->retval().isVoid() && !e->retval().isPointer()) { + if (!totalTmpBuffExist) + fprintf(fp, + "\t\t\tsize_t totalTmpSize = sizeof(%s);\n", + retvalType.c_str()); + else + fprintf(fp, + "\t\t\ttotalTmpSize += sizeof(%s);\n", + retvalType.c_str()); + + totalTmpBuffExist = true; + } + if (totalTmpBuffExist) { + fprintf(fp, + "\t\t\ttotalTmpSize += checksumSize;\n" + "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n"); + } + } + + if (pass == PASS_Epilog) { + // send back out pointers data as well as retval + if (totalTmpBuffExist) { + fprintf(fp, + "\t\t\tif (useChecksum) {\n" + "\t\t\t\tChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, " + "&tmpBuf[0], totalTmpSize - checksumSize, " + "&tmpBuf[totalTmpSize - checksumSize], checksumSize);\n" + "\t\t\t}\n" + "\t\t\tstream->flush();\n"); + } + } + } // pass; + +#if INSTRUMENT_TIMING_HOST + fprintf(fp, "\t\t\tclock_gettime(CLOCK_REALTIME, &ts1);\n"); + fprintf(fp, "\t\t\tlong timeDiff = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts0.tv_sec*1000000 + ts0.tv_nsec/1000);\n"); + fprintf(fp, "\t\t\tlong timeDiff2 = ts1.tv_sec*1000000 + ts1.tv_nsec/1000 - (ts2.tv_sec*1000000 + ts2.tv_nsec/1000);\n"); + fprintf(fp, "\t\t\tprintf(\"(timing) %%4ld.%%06ld %s: %%ld (%%ld) us\\n\", " + "ts1.tv_sec, ts1.tv_nsec/1000, timeDiff, timeDiff2);\n", e->name().c_str()); +#endif + fprintf(fp, "\t\t\tSET_LASTCALL(\"%s\");\n", e->name().c_str()); + fprintf(fp, "\t\t\tbreak;\n"); + fprintf(fp, "\t\t}\n"); + + delete [] tmpBufOffset; + } + fprintf(fp, "\t\tdefault:\n"); + fprintf(fp, "\t\t\treturn ptr - (unsigned char*)buf;\n"); + fprintf(fp, "\t\t} //switch\n"); + if (strstr(m_basename.c_str(), "gl")) { + fprintf(fp, "\t\t#ifdef CHECK_GL_ERRORS\n"); + fprintf(fp, "\t\tGLint err = this->glGetError();\n"); + fprintf(fp, "\t\tif (err) fprintf(stderr, \"%s Error (post-call): 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str()); + fprintf(fp, "\t\t#endif\n"); + } + + fprintf(fp, "\t\tptr += packetLen;\n"); + fprintf(fp, "\t} // while\n"); + fprintf(fp, "\treturn ptr - (unsigned char*)buf;\n"); + fprintf(fp, "}\n"); + + fclose(fp); + return 0; +} + +int ApiGen::readSpec(const std::string & filename) +{ + FILE *specfp = fopen(filename.c_str(), "rt"); + if (specfp == NULL) { + return -1; + } + + char line[1000]; + unsigned int lc = 0; + while (fgets(line, sizeof(line), specfp) != NULL) { + lc++; + EntryPoint ref; + if (ref.parse(lc, std::string(line))) { + push_back(ref); + updateMaxEntryPointsParams(ref.vars().size()); + } + } + fclose(specfp); + return 0; +} + +int ApiGen::readAttributes(const std::string & attribFilename) +{ + enum { ST_NAME, ST_ATT } state; + + FILE *fp = fopen(attribFilename.c_str(), "rt"); + if (fp == NULL) { + perror(attribFilename.c_str()); + return -1; + } + char buf[1000]; + + state = ST_NAME; + EntryPoint *currentEntry = NULL; + size_t lc = 0; + bool globalAttributes = false; + while (fgets(buf, sizeof(buf), fp) != NULL) { + lc++; + std::string line(buf); + if (line.size() == 0) continue; // could that happen? + + if (line.at(0) == '#') continue; // comment + + size_t first = line.find_first_not_of(" \t\n"); + if (state == ST_ATT && (first == std::string::npos || first == 0)) state = ST_NAME; + + line = trim(line); + if (line.size() == 0 || line.at(0) == '#') continue; + + switch(state) { + case ST_NAME: + if (line == "GLOBAL") { + globalAttributes = true; + } else { + globalAttributes = false; + currentEntry = findEntryByName(line); + if (currentEntry == NULL) { + fprintf(stderr, "WARNING: %u: attribute of non existant entry point %s\n", (unsigned int)lc, line.c_str()); + } + } + state = ST_ATT; + break; + case ST_ATT: + if (globalAttributes) { + setGlobalAttribute(line, lc); + } else if (currentEntry != NULL) { + currentEntry->setAttribute(line, lc); + } + break; + } + } + return 0; +} + + +int ApiGen::setGlobalAttribute(const std::string & line, size_t lc) +{ + size_t pos = 0; + size_t last; + std::string token = getNextToken(line, pos, &last, WHITESPACE); + pos = last; + + if (token == "base_opcode") { + std::string str = getNextToken(line, pos, &last, WHITESPACE); + if (str.size() == 0) { + fprintf(stderr, "line %u: missing value for base_opcode\n", (unsigned) lc); + } else { + setBaseOpcode(atoi(str.c_str())); + } + } else if (token == "encoder_headers") { + std::string str = getNextToken(line, pos, &last, WHITESPACE); + pos = last; + while (str.size() != 0) { + encoderHeaders().push_back(str); + str = getNextToken(line, pos, &last, WHITESPACE); + pos = last; + } + } else if (token == "client_context_headers") { + std::string str = getNextToken(line, pos, &last, WHITESPACE); + pos = last; + while (str.size() != 0) { + clientContextHeaders().push_back(str); + str = getNextToken(line, pos, &last, WHITESPACE); + pos = last; + } + } else if (token == "server_context_headers") { + std::string str = getNextToken(line, pos, &last, WHITESPACE); + pos = last; + while (str.size() != 0) { + serverContextHeaders().push_back(str); + str = getNextToken(line, pos, &last, WHITESPACE); + pos = last; + } + } else if (token == "decoder_headers") { + std::string str = getNextToken(line, pos, &last, WHITESPACE); + pos = last; + while (str.size() != 0) { + decoderHeaders().push_back(str); + str = getNextToken(line, pos, &last, WHITESPACE); + pos = last; + } + } + else { + fprintf(stderr, "WARNING: %u : unknown global attribute %s\n", (unsigned int)lc, line.c_str()); + } + + return 0; +} diff --git a/host/commands/emugen/ApiGen.h b/host/commands/emugen/ApiGen.h new file mode 100644 index 0000000000000000000000000000000000000000..c4e87b48a1e276c472918c17e3711a211d673765 --- /dev/null +++ b/host/commands/emugen/ApiGen.h @@ -0,0 +1,97 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef __API_GEN_H_ +#define __API_GEN_H_ + +#include <vector> +#include <string.h> +#include "EntryPoint.h" + + +class ApiGen : private std::vector<EntryPoint> { + +public: + typedef std::vector<std::string> StringVec; + typedef enum { CLIENT_SIDE, SERVER_SIDE, WRAPPER_SIDE } SideType; + + ApiGen(const std::string & basename) : + m_basename(basename), + m_maxEntryPointsParams(0), + m_baseOpcode(0) + { } + virtual ~ApiGen() {} + int readSpec(const std::string & filename); + int readAttributes(const std::string & attribFilename); + size_t maxEntryPointsParams() { return m_maxEntryPointsParams; } + void updateMaxEntryPointsParams(size_t val) { + if (m_maxEntryPointsParams == 0 || val > m_maxEntryPointsParams) m_maxEntryPointsParams = val; + } + int baseOpcode() { return m_baseOpcode; } + void setBaseOpcode(int base) { m_baseOpcode = base; } + + const char *sideString(SideType side) { + const char *retval; + switch(side) { + case CLIENT_SIDE: + retval = "client"; + break; + case SERVER_SIDE: + retval = "server"; + break; + case WRAPPER_SIDE: + retval = "wrapper"; + break; + default: + retval = "unknown"; + } + return retval; + } + + StringVec & clientContextHeaders() { return m_clientContextHeaders; } + StringVec & encoderHeaders() { return m_encoderHeaders; } + StringVec & serverContextHeaders() { return m_serverContextHeaders; } + StringVec & decoderHeaders() { return m_decoderHeaders; } + + EntryPoint * findEntryByName(const std::string & name); + int genOpcodes(const std::string &filename); + int genAttributesTemplate(const std::string &filename); + int genProcTypes(const std::string &filename, SideType side); + int genFuncTable(const std::string &filename, SideType side); + + int genContext(const std::string &filename, SideType side); + int genContextImpl(const std::string &filename, SideType side); + + int genEntryPoints(const std::string &filename, SideType side); + + int genEncoderHeader(const std::string &filename); + int genEncoderImpl(const std::string &filename); + + int genDecoderHeader(const std::string &filename); + int genDecoderImpl(const std::string &filename); + +protected: + virtual void printHeader(FILE *fp) const; + std::string m_basename; + StringVec m_clientContextHeaders; + StringVec m_encoderHeaders; + StringVec m_serverContextHeaders; + StringVec m_decoderHeaders; + size_t m_maxEntryPointsParams; // record the maximum number of parameters in the entry points; + int m_baseOpcode; + int setGlobalAttribute(const std::string & line, size_t lc); +}; + +#endif diff --git a/host/commands/emugen/EntryPoint.cpp b/host/commands/emugen/EntryPoint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d7ce63566aa4294c00a5e82fdaad170140ef6dc5 --- /dev/null +++ b/host/commands/emugen/EntryPoint.cpp @@ -0,0 +1,394 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "EntryPoint.h" + +#include "Parser.h" +#include "TypeFactory.h" +#include "strUtils.h" + +#include <sstream> +#include <string> + +#include <stdio.h> + +EntryPoint::EntryPoint() +{ + reset(); +} + +EntryPoint::~EntryPoint() +{ +} + +void EntryPoint::reset() +{ + m_unsupported = false; + m_customDecoder = false; + m_notApi = false; + m_flushOnEncode = false; + m_vars.empty(); +} + +// return true for valid line (need to get into the entry points list) +bool EntryPoint::parse(unsigned int lc, const std::string & str) +{ + size_t pos, last; + std::string field; + + reset(); + std::string linestr = trim(str); + + if (linestr.size() == 0) return false; + if (linestr.at(0) == '#') return false; + + // skip PREFIX + field = getNextToken(linestr, 0, &last, "("); + pos = last + 1; + // return type + field = getNextToken(linestr, pos, &last, ",)"); + + std::string error; + std::string retTypeName; + if (!parseTypeDeclaration(field, &retTypeName, &error)) { + fprintf(stderr, + "line: %d: Parsing error in field <%s>: %s\n", + lc, + field.c_str(), + error.c_str()); + return false; + } + pos = last + 1; + const VarType *theType = TypeFactory::instance()->getVarTypeByName(retTypeName); + if (theType->name() == "UNKNOWN") { + fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str()); + } + + m_retval.init(std::string(""), + theType, + std::string(""), + Var::POINTER_OUT, + std::string(""), + std::string(""), + std::string("")); + + // function name + m_name = getNextToken(linestr, pos, &last, ",)"); + pos = last + 1; + + // parameters; + int nvars = 0; + while (pos < linestr.size() - 1) { + field = getNextToken(linestr, pos, &last, ",)"); + if (field == "void") { + // 'void' is used as a special case for functions that don't take + // parameters at all. + break; + } + std::string vartype, varname; + if (!parseParameterDeclaration(field, &vartype, &varname, &error)) { + fprintf(stderr, + "line: %d: Parsing error in field <%s> (%s)\n", + lc, + field.c_str(), + error.c_str()); + return false; + } + nvars++; + const VarType *v = TypeFactory::instance()->getVarTypeByName(vartype); + if (v->id() == 0) { + fprintf(stderr, "%d: Unknown type: %s\n", lc, vartype.c_str()); + } else { + if (varname == "" && + !(v->name() == "void" && !v->isPointer())) { + std::ostringstream oss; + oss << "var" << nvars; + varname = oss.str(); + } + + m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, "", "", "")); + } + pos = last + 1; + } + return true; +} + +void EntryPoint::print(FILE *fp, bool newline, + const std::string & name_suffix, + const std::string & name_prefix, + const std::string & ctx_param ) const +{ + fprintf(fp, "%s %s%s%s(", + m_retval.type()->name().c_str(), + name_prefix.c_str(), + m_name.c_str(), + name_suffix.c_str()); + + if (ctx_param != "") fprintf(fp, "%s ", ctx_param.c_str()); + + for (size_t i = 0; i < m_vars.size(); i++) { + if (m_vars[i].isVoid()) continue; + if (i != 0 || ctx_param != "") fprintf(fp, ", "); + fprintf(fp, "%s %s", m_vars[i].type()->name().c_str(), + m_vars[i].name().c_str()); + } + fprintf(fp, ")%s", newline? "\n" : ""); +} + +Var * EntryPoint::var(const std::string & name) +{ + Var *v = NULL; + for (size_t i = 0; i < m_vars.size(); i++) { + if (m_vars[i].name() == name) { + v = &m_vars[i]; + break; + } + } + return v; +} + +const Var * EntryPoint::var(const std::string & name) const +{ + const Var *v = NULL; + for (size_t i = 0; i < m_vars.size(); i++) { + if (m_vars[i].name() == name) { + v = &m_vars[i]; + break; + } + } + return v; +} + +bool EntryPoint::hasPointers() +{ + bool pointers = false; + if (m_retval.isPointer()) pointers = true; + if (!pointers) { + for (size_t i = 0; i < m_vars.size(); i++) { + if (m_vars[i].isPointer()) { + pointers = true; + break; + } + } + } + return pointers; +} + +int EntryPoint::validateVarAttr(const std::string& varname, size_t lc) const { + if (varname.size() == 0) { + fprintf(stderr, "ERROR: %u: Missing variable name in attribute\n", (unsigned int)lc); + return -1; + } + const Var * v = var(varname); + if (v == NULL) { + fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n", + (unsigned int)lc, varname.c_str(), name().c_str()); + return -2; + } + return 0; +} + +int EntryPoint::setAttribute(const std::string &line, size_t lc) +{ + size_t pos = 0; + size_t last; + std::string token = getNextToken(line, 0, &last, WHITESPACE); + int err = 0; + Var* v = nullptr; + + if (token == "len") { + pos = last; + std::string varname = getNextToken(line, pos, &last, WHITESPACE); + err = validateVarAttr(varname, lc); + if (err < 0) return err; + + // set the size expression into var + v = var(varname); + pos = last; + v->setLenExpression(line.substr(pos)); + } else if (token == "param_check") { + pos = last; + std::string varname = getNextToken(line, pos, &last, WHITESPACE); + err = validateVarAttr(varname, lc); + if (err < 0) return err; + + v = var(varname); + pos = last; + v->setParamCheckExpression(line.substr(pos)); + + } else if (token == "dir") { + pos = last; + std::string varname = getNextToken(line, pos, &last, WHITESPACE); + err = validateVarAttr(varname, lc); + if (err < 0) return err; + + v = var(varname); + pos = last; + + std::string pointerDirStr = getNextToken(line, pos, &last, WHITESPACE); + if (pointerDirStr.size() == 0) { + fprintf(stderr, "ERROR: %u: missing pointer directions\n", (unsigned int)lc); + return -3; + } + + if (pointerDirStr == "out") { + v->setPointerDir(Var::POINTER_OUT); + } else if (pointerDirStr == "inout") { + v->setPointerDir(Var::POINTER_INOUT); + } else if (pointerDirStr == "in") { + v->setPointerDir(Var::POINTER_IN); + } else { + fprintf(stderr, "ERROR: %u: unknown pointer direction %s\n", + (unsigned int)lc, pointerDirStr.c_str()); + } + } else if (token == "var_flag") { + pos = last; + std::string varname = getNextToken(line, pos, &last, WHITESPACE); + err = validateVarAttr(varname, lc); + if (err < 0) return err; + + v = var(varname); + 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 if (flag == "DMA") { + v->setDMA(true); + } else { + fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str()); + } + } + } else if (token == "custom_pack") { + pos = last; + std::string varname = getNextToken(line, pos, &last, WHITESPACE); + err = validateVarAttr(varname, lc); + if (err < 0) return err; + + v = var(varname); + pos = last; + v->setPackExpression(line.substr(pos)); + } else if (token == "custom_unpack") { + pos = last; + std::string varname = getNextToken(line, pos, &last, WHITESPACE); + + err = validateVarAttr(varname, lc); + if (err < 0) return err; + + v = var(varname); + pos = last; + v->setUnpackExpression(line.substr(pos)); + } else if (token == "custom_host_pack_tmp_alloc") { + pos = last; + std::string varname = getNextToken(line, pos, &last, WHITESPACE); + err = validateVarAttr(varname, lc); + if (err < 0) return err; + + v = var(varname); + if (v->pointerDir() == Var::POINTER_IN) { + fprintf(stderr, "ERROR: %u: variable %s is not an output or inout\n", + (unsigned int)lc, varname.c_str()); + return -2; + } + + pos = last; + v->setHostPackTmpAllocExpression(line.substr(pos)); + } else if (token == "custom_host_pack") { + pos = last; + std::string varname = getNextToken(line, pos, &last, WHITESPACE); + err = validateVarAttr(varname, lc); + if (err < 0) return err; + + v = var(varname); + if (v->pointerDir() == Var::POINTER_IN) { + fprintf(stderr, "ERROR: %u: variable %s is not an output or inout\n", + (unsigned int)lc, varname.c_str()); + return -2; + } + + pos = last; + v->setHostPackExpression(line.substr(pos)); + } else if (token == "custom_guest_unpack") { + pos = last; + std::string varname = getNextToken(line, pos, &last, WHITESPACE); + err = validateVarAttr(varname, lc); + if (err < 0) return err; + + v = var(varname); + if (v->pointerDir() == Var::POINTER_IN) { + fprintf(stderr, "ERROR: %u: variable %s is not an output or inout\n", + (unsigned int)lc, varname.c_str()); + return -2; + } + + pos = last; + v->setGuestUnpackExpression(line.substr(pos)); + } else if (token == "custom_write") { + pos = last; + std::string varname = getNextToken(line, pos, &last, WHITESPACE); + err = validateVarAttr(varname, lc); + if (err < 0) return err; + + // set the size expression into var + v = var(varname); + pos = last; + v->setWriteExpression(line.substr(pos)); + } else if (token == "flag") { + 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 -4; + } + + if (flag == "unsupported") { + setUnsupported(true); + } else if (flag == "custom_decoder") { + setCustomDecoder(true); + } else if (flag == "not_api") { + setNotApi(true); + } else if (flag == "flushOnEncode") { + setFlushOnEncode(true); + } else { + fprintf(stderr, "WARNING: %u: unknown flag %s\n", (unsigned int)lc, flag.c_str()); + } + } else { + fprintf(stderr, "WARNING: %u: unknown attribute %s\n", (unsigned int)lc, token.c_str()); + } + + return 0; +} diff --git a/host/commands/emugen/EntryPoint.h b/host/commands/emugen/EntryPoint.h new file mode 100644 index 0000000000000000000000000000000000000000..bc3fd693787cf201c8e8b300c4ece353036914b7 --- /dev/null +++ b/host/commands/emugen/EntryPoint.h @@ -0,0 +1,71 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef __EntryPoint__H__ +#define __EntryPoint__H__ + +#include <string> +#include <vector> +#include <stdio.h> + +#include "Var.h" + +//--------------------------------------------------- + +typedef std::vector<Var> VarsArray; + +class EntryPoint { +public: + EntryPoint(); + virtual ~EntryPoint(); + bool parse(unsigned int lc, const std::string & str); + void reset(); // reset the class to empty; + void print(FILE *fp = stdout, bool newline = true, + const std::string & name_suffix = std::string(""), + const std::string & name_prefix = std::string(""), + const std::string & ctx_param = std::string("")) const; + const std::string & name() const { return m_name; } + VarsArray & vars() { return m_vars; } + Var & retval() { return m_retval; } + Var * var(const std::string & name); + const Var * var(const std::string & name) const; + bool hasPointers(); + bool unsupported() const { return m_unsupported; } + void setUnsupported(bool state) { m_unsupported = state; } + bool customDecoder() { return m_customDecoder; } + void setCustomDecoder(bool state) { m_customDecoder = state; } + bool notApi() const { return m_notApi; } + void setNotApi(bool state) { m_notApi = state; } + bool flushOnEncode() const { return m_flushOnEncode; } + void setFlushOnEncode(bool state) { m_flushOnEncode = state; } + int validateVarAttr(const std::string& varname, size_t lc) const; + int setAttribute(const std::string &line, size_t lc); + +private: + std::string m_name; + Var m_retval; + VarsArray m_vars; + bool m_unsupported; + bool m_customDecoder; + bool m_notApi; + bool m_flushOnEncode; + + void err(unsigned int lc, const char *msg) { + fprintf(stderr, "line %d: %s\n", lc, msg); + } +}; + + +#endif diff --git a/host/commands/emugen/Parser.cpp b/host/commands/emugen/Parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0839f20234a33496b0c0a73b514e83ba85e5f52c --- /dev/null +++ b/host/commands/emugen/Parser.cpp @@ -0,0 +1,191 @@ +/* +* Copyright 2014 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "Parser.h" + +#include <vector> + +#define WHITESPACE " \t\n" + +// Parse the |input| string as a list of type-specific tokens. +// This tokenizes the input, using whitespace as separators and '*' as +// a single token too. On success, return true and sets |*out| to the +// list of tokens. On failure, return false. +// +// Example: 'const char**foo' -> ['const', 'char', '*', '*', 'foo'] +// +static bool parseTypeTokens(const std::string& input, + std::vector<std::string>* out, + std::string* error) { + out->clear(); + size_t pos = 0U; + + // Parse all tokens in the input, treat '*' as a single token. + // I.e. + for (;;) { + // skip leading whitespace. + pos = input.find_first_not_of(WHITESPACE, pos); + if (pos == std::string::npos) { + break; // end of parse. + } + + // If this is a star, ensure it follows a type name. + // otherwise treat it as part of the final type. + if (input[pos] == '*') { + out->push_back(std::string("*")); + pos += 1U; + continue; + } + + // find end of type/token. + size_t end = input.find_first_of(WHITESPACE "*", pos); + if (end == std::string::npos) { + end = input.size(); + } + + std::string str = input.substr(pos, end - pos); + if (str.size() == 0) { + // Sanity check: should not happen. + if (error != NULL) { + *error = "Unexpected empty token !?"; + } + return false; + } + + out->push_back(str); + pos = end; + } + + if (error != NULL) { + // Sanity check: require non-empty input + if (out->empty()) { + *error = "Empty parameter declaration!"; + return false; + } + + // Sanity check: There must be base type name before any '*' + for (size_t n = 0; n < out->size(); ++n) { + std::string& token = (*out)[n]; + if (token == "*") { + *error = "Unexpected '*' before type name"; + return false; + } else if (token != "const") { + break; + } + } + } + + return true; +} + +// Given |tokens|, an input vector of strings, join the first |count| items +// into a normalized type string, and return it. +static std::string buildTypeString(const std::vector<std::string>& tokens, + size_t count) { + std::string result; + + for (size_t n = 0; n < count; ++n) { + const std::string& token = tokens[n]; + if (n > 0 && token != "*") { + result.append(" "); + } + result.append(token); + } + return result; +} + + +std::string normalizeTypeDeclaration(const std::string& input) { + std::vector<std::string> tokens; + if (!parseTypeTokens(input, &tokens, NULL)) { + return ""; + } + return buildTypeString(tokens, tokens.size()); +} + +bool parseTypeDeclaration(const std::string& input, + std::string* typeName, + std::string* error) { + // The type name can be made of several tokens, e.g. 'unsigned int' + // use an array to store them, and a count variable. Each item can be + // one of '*', 'const' or a type name component (e.g. 'struct', 'unsigned') + std::vector<std::string> tokens; + + if (!parseTypeTokens(input, &tokens, error)) { + return false; + } + + // Sanity check, there must be a least one non-special tokens. + size_t nonSpecialCount = 0; + for (size_t n = 0; n < tokens.size(); ++n) { + if (tokens[n] != "*" && tokens[n] != "const") { + nonSpecialCount++; + } + } + if (nonSpecialCount == 0) { + *error = "Missing type name"; + return false; + } + // Build the type name from all tokens before it. + *typeName = buildTypeString(tokens, tokens.size()); + return true; +} + + +bool parseParameterDeclaration(const std::string& param, + std::string* typeName, + std::string* variableName, + std::string* error) { + std::vector<std::string> tokens; + + if (!parseTypeTokens(param, &tokens, error)) { + return false; + } + + // Sanity check, there must be a least two non-special tokens. + size_t nonSpecialCount = 0; + for (size_t n = 0; n < tokens.size(); ++n) { + if (tokens[n] != "*" && tokens[n] != "const") { + nonSpecialCount++; + } + } + if (nonSpecialCount == 0) { + *error = "Missing type name"; + return false; + } + if (nonSpecialCount == 1) { + *error = "Missing variable name"; + return false; + } + + // Sanity check: variable name must not be followed by 'const' or '*' + const std::string& lastToken = tokens[tokens.size() - 1U]; + if (lastToken == "*") { + *error = "Extra '*' after variable name"; + return false; + } + if (lastToken == "const") { + *error = "Extra 'const' after variable name"; + return false; + } + + // Extract the variable name as the last token. + if (variableName) { + *variableName = lastToken; + } + // Build the type name from all tokens before it. + *typeName = buildTypeString(tokens, tokens.size() - 1U); + return true; +} diff --git a/host/commands/emugen/Parser.h b/host/commands/emugen/Parser.h new file mode 100644 index 0000000000000000000000000000000000000000..f62c0763bac039f16847bd36479909cfb4dd1338 --- /dev/null +++ b/host/commands/emugen/Parser.h @@ -0,0 +1,68 @@ +/* +* Copyright 2014 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef PARSER_H +#define PARSER_H + +#include <string> + +// Normalize a type declaration. This gets rid of leading/trailing whitespace +// as well as ensure there is a single space separating all input tokens, +// with the exception of '*' which is treated specially by never being +// prepended with a space. +// |input| is the input type declaration. Return normalized form. +// Note that this doesn't try to validate the input. +std::string normalizeTypeDeclaration(const std::string& input); + +// Parse a return type declaration. |input| is the type declaration +// (e.g. 'const char**'). On success return true and sets |*typeName| to +// the appropriate normalized type string. On failure, return false and +// sets |*error| with a human-friendly message explaining the reason for +// failure. +// +// Note that the returned type string is normalized, see comment for +// parseParameterDeclaration() for examples. +// +// NOTE: This does not support declarations of arrays or functions! +// +bool parseTypeDeclaration(const std::string& input, + std::string* typeName, + std::string* error); + +// Parse a function parameter declaration and extract the type and variable +// name from it. |param| is the individual parameter declaration from the +// function's signature (e.g. 'const char *items') +// +// On success, returns true and sets |*vartype| and |*varname| to the +// appropriate type name and variable name. |varname| can be NULL if the caller +// isn't interested in the variable name. +// +// On failure, return false and sets |*error| to a human-friendly message +// explaining the reason for failure. +// +// Note that the returned type name is normalized with regards to whitespace +// and star location, e.g.: +// +// const void *items -> 'const void*' +// char* *items -> 'char**' +// const void * const * items -> 'const void* const*' +// unsigned int *const data -> 'unsigned int* const' +// +bool parseParameterDeclaration(const std::string& param, + std::string* typeName, + std::string* variableName, + std::string* error); + +#endif // PARSER_H diff --git a/host/commands/emugen/Parser_unittest.cpp b/host/commands/emugen/Parser_unittest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..904b247372c0167cbf9ce0748eb95f53ab987844 --- /dev/null +++ b/host/commands/emugen/Parser_unittest.cpp @@ -0,0 +1,120 @@ +/* +* Copyright 2014 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "Parser.h" + +#include <gtest/gtest.h> + +#define ARRAYLEN(x) (sizeof(x) / sizeof(x[0])) + +TEST(ParserTest, normalizeTypeDeclaration) { + static const struct { + const char* expected; + const char* input; + } kData[] = { + { "char", "char" }, + { "const unsigned int", " const unsigned\tint\n" }, + { "char* const**", "char *const* *" }, + }; + const size_t kDataSize = ARRAYLEN(kData); + for (size_t n = 0; n < kDataSize; ++n) { + std::string result; + std::string text = "When parsing '"; + text += kData[n].input; + text += "'"; + + result = normalizeTypeDeclaration(kData[n].input); + EXPECT_STREQ(kData[n].expected, result.c_str()) << text; + } +} + +TEST(ParserTest, parseTypeDeclaration) { + static const struct { + const char* input; + bool expected; + const char* expectedType; + const char* expectedError; + } kData[] = { + { "const", false, NULL, "Missing type name" }, + { "const const", false, NULL, "Missing type name" }, + { "foo", true, "foo", NULL }, + { "void", true, "void", NULL }, + { "const foo", true, "const foo", NULL }, + { "foo *", true, "foo*", NULL }, + { "char foo", true, "char foo", NULL }, + { "\tunsigned \t int\n", true, "unsigned int", NULL }, + { "const * char", false, NULL, "Unexpected '*' before type name" }, + { "const char * ", true, "const char*", NULL }, + { "const void*const * *", true, "const void* const**", NULL }, + }; + const size_t kDataSize = ARRAYLEN(kData); + for (size_t n = 0; n < kDataSize; ++n) { + std::string varname, vartype, error; + std::string text = "When parsing '"; + text += kData[n].input; + text += "'"; + + EXPECT_EQ(kData[n].expected, + parseTypeDeclaration(kData[n].input, + &vartype, + &error)) << text; + if (kData[n].expected) { + EXPECT_STREQ(kData[n].expectedType, vartype.c_str()) << text; + } else { + EXPECT_STREQ(kData[n].expectedError, error.c_str()) << text; + } + } +} + +TEST(ParserTest, parseParameterDeclaration) { + static const struct { + const char* input; + bool expected; + const char* expectedType; + const char* expectedVariable; + const char* expectedError; + } kData[] = { + { "foo", false, NULL, NULL, "Missing variable name" }, + { "const", false, NULL, NULL, "Missing type name" }, + { "const foo", false, NULL, NULL, "Missing variable name" }, + { "const const", false, NULL, NULL, "Missing type name" }, + { "char foo", true, "char", "foo", NULL }, + { "unsigned int\t bar\n", true, "unsigned int", "bar", NULL }, + { "const * char foo", false, NULL, NULL, "Unexpected '*' before type name" }, + { "const char * foo", true, "const char*", "foo", NULL }, + { "const void*const *data", true, "const void* const*", "data", NULL }, + { "char foo const", false, NULL, NULL, "Extra 'const' after variable name" }, + { "int bar*", false, NULL, NULL, "Extra '*' after variable name" }, + }; + const size_t kDataSize = ARRAYLEN(kData); + for (size_t n = 0; n < kDataSize; ++n) { + std::string varname, vartype, error; + std::string text = "When parsing '"; + text += kData[n].input; + text += "'"; + + EXPECT_EQ(kData[n].expected, + parseParameterDeclaration(kData[n].input, + &vartype, + &varname, + &error)) << text; + if (kData[n].expected) { + EXPECT_STREQ(kData[n].expectedType, vartype.c_str()) << text; + EXPECT_STREQ(kData[n].expectedVariable, varname.c_str()) << text; + } else { + EXPECT_STREQ(kData[n].expectedError, error.c_str()) << text; + } + } +} diff --git a/host/commands/emugen/README b/host/commands/emugen/README new file mode 100644 index 0000000000000000000000000000000000000000..0fe85f941282b4d2986a0c3ecb9bcec936251a8a --- /dev/null +++ b/host/commands/emugen/README @@ -0,0 +1,332 @@ +Introduction: +------------- +The emugen tool is a tool to generate a wire protocol implementation +based on provided API. The tool generates c++ encoder code that takes +API calls and encodes them into the wire and decoder code that decodes +the wire stream and calls server matching API. +The emugen tool includes additional functionality that enables to +generate an wrapper library. The wrapper library provides entry points +for the specified API, where each entry routes the call via a dispatch +table. The dispatch table may be initialized as required by a specific application. + +The following paragraphs includes the following: + * Wire Protocol Description + * Input files description & format + * Generated code description. + + +Note: In this document, the caller is referred to as Encoder or Client +and the callee is referred to as the Decoder or Server. These terms +are used interchangeably by the context. + + + +Wire Protocol packet structure: +------------------------------- +A general Encoder->Decoder packet is structured as following: +struct Packet { + unsigned int opcode; + unsigned int packet_len; + … parameter 1 + … parameter 2 +}; +A general Decoder->Encoder reply is expected to be received in the +context of the ‘call’ that triggered it, thus it includes the reply +data only, with no context headers. In precise term terms, a reply +packet will look like: + +struct { + ...// reply data +}; + +consider the following function call: +int foo(int p1, short s1) +will be encoded into : +{ + 101, // foo opcode + 14, // sizeof(opcode) + sizeof(packet_len) + sizeof(int) + sizeof(short) + p1, // 4 bytes + s1 // 2 bytes +} + +Since ‘foo’ returns value, the caller is expected to read back the return packet from the server->client stream. The return value in this example is in thus the return packet is: +{ + int retval; +} + + +Pointer decoding: +---------------- +The wire protocol also allows exchanging of pointer data +(arrays). Pointers are defined with directions: + + in : Data is sent from the caller to the calle + out: Data is sent from the callee to the caller + in_out: data is sent from the caller and return in place. + +‘in’ and ‘in_out’ encoded with their len: +{ + unsinged int pointer_data_len; + unsigned char data[pointer_data_len];… // pointer data +} + +‘out’ pointers are encoded by data length only: +{ +unsigned int pointer_data_len; +} + +‘out’ and ‘in_out’ pointer’s data is returned in the return +packet. For example, consider the following call: + +int foo(int n, int *ptr); // assume that ‘data’ is in_out pointer which contains ‘n’ ints + +The caller packet will have the following form: +{ + 101, // foo opcode + xx, sizeof(opcode) + sizeof(datalen) + sizeof(int) + sizeof(unsigned int) + n * sizeof(int); + n, // the n parameter + n * sizeof(int), // size of the data in ptr + … // n* sizeof(int) bytes +} + +The return packet is; +{ + …. // n * sizeof(int) bytes of data return in ptr + retval // sizeof(int) - the return value of the function; +} + +Endianess +--------- +The Wire protocol is designed to impose minimum overhead on the client +side. Thus, the data endianness that is sent across the wire is +determined by the ‘client’ side. It is up to the server side to +determine the client endianess and marshal the packets as required. + + + +Emugen input files - protocol specification +------------------------------------------- +The protocol generated by emugen consists of two input files: + +1. basename.in - A sepcification of the protocol RPC procedures. This +part of the specification is expected to be generated automatically +from c/c++ header files or similar. + +‘basename’ is the basename for the protocol and will be used to prefix +the files that are generated for this protocol. A line in the .in +file has the following format: + +[prefix](retvalType, FuncName, <param type> [param name],...) +where + retvalType - The function return value type + FuncName - function name + <param type> mandatory parameter type + [param name] - optional parameter name +Examples: +GL_ENTRY(void, glVertex1f, float v) +XXX(int *, foo, int n, float, short) +XXX(void, glFlush, void) + +Note: Empty lines in the file are ignored. A line starts with # is a comment + +2. basename.attrib - Attributes information of the API. +This file includes additional flags, pointers datalen information and +global attributes of the protocol. For uptodate format of the file, +please refer to the specification file in the project source +tree. The format of the .attrib file is described below. + +3. basename.types - Types information + +This files describes the types that are described by the API. A type +is defined as follows: +<type name> <size in bits> <print format string> <is a pointer? true|false> +where: +<type name> is the name of the type as described in the API +<size in bits> 0, 8, 16, 32 sizes are accepted +<print format string> a string to format the value of the type, as +acceted by printf(3) +<is pointer?> true or false string species whether the type should be +treated as a pointer. + +example: +GLint 32 %d false +GLint* 32 %p true +GLptr 32 %p true + +Encoder generated code files +---------------------------- +In order to generate the encoder files, one should run the ‘emugen’ +tool as follows: + +emugen -i <input directory> -E <encoder files output directory> <basename> +where: + <input directory> containes the api specification files (basename.in + basename.attrib) + <encoder directory> - a directory name to generate the encoder output files + basename - The basename for the api. + +Assuming the basename is ‘api’, The following files are generated: + +api_opcodes.h - defines the protocol opcodes. The first opcode value +is 0, unless defined otherwise in the .attrib file + +api_entry.cpp - defines entry points for the functions that are +defined by the protocol. this File also includes a function call +‘setContextAccessor(void *(*f)()). This function should be used to +provide a callback function that is used by the functions to access +the encoder context. For example, such callback could fetch the +context from a Thread Local Storage (TLS) location. + +api_client_proc.h - type defintions for the protocol procedures. + +api_client_context.h - defines the client side dispatch table data +structure that stores the encoding functions. This data structure also +includes ‘accessors’ methods such that library user can override +default entries for special case handling. + +api_client_context.cpp - defines an initialization function for +dispatch table + +api_enc.h - This header file defines the encoder data strcuture. The +encoder data structure inherits its functionality from the +‘client_context’ class above and adds encoding and streaming +functionality. + +api_enc.cpp - Encoder implementation. + +Decoder generated files +----------------------- +In order to generate the decoder files, one should run the ‘emugen’ +tool as follows: +emugen -i <input directory> -D <decoder files output directory> basename +where: + <input directory> containes the api specification files (basename.in + basename.attrib) + <decoder directory> - a directory name to generate the decoder output files + basename - The basename for the api. + +With resepct to the example above, Emugen will generate the following +files: + +api_opcodes.h - Protocol opcodes + +api_server_proc.h - type definitions for the server side procedures + +api_server_context.h - dispatch table the decoder functions + +api_server_context.cpp - dispatch table initialization function +api_dec.h - Decoder header file + +api_dec.cpp - Decoder implementation. In addtion, this file includes +an intiailization function that uses a user provided callback to +initialize the API server implementation. An example for such +initialization is loading a set of functions from a shared library +module. + +Wrapper generated files +----------------------- +In order to generate a wrapper library files, one should run the +'emugen' tool as follows: + +emugen -i <input directory> -W <wrapper files output directory> basename +where: + <input directory> containes the api specification files (basename.in + basename.attrib) + <wrapper directory> - a directory name to generate the wrapper output files + basename - The basename for the api. + +With resepct to the example above, Emugen will generate the following +files: + +api_wrapper_proc.h - type definitions for the wrapper procedures + +api_wrapper_context.h - dispatch table the wrapper functions + +api_wrapper_context.cpp - dispatch table initialization function +api_wrapper_entry.cpp - entry points for the API + + +.attrib file format description: +------------------------------- +The .attrib file is an input file to emugen and is used to provide + additional information that is required for the code generation. +The file format is as follows: + +a line that starts with # is ignored (comment) +a empty line just whitespace of (" " "\t" "\n") is ignored. + +The file is divided into 'sections', each describes a specific API +function call. A section starts with the name of the function in +column 0. + +A section that starts with the reserved word 'GLOBAL' provides global +attributes. + +below are few sections examples: + +GLOBAL + encoder_headers string.h kuku.h + +glVertex3fv + len data (size) +glTexImage2D + len pixels (pixels == NULL? 0 : (format_pixel_size(internalformat) * width * height * type_size(type))) + + +Global section flags description: + +base_opcode + set the base opcode value for this api + format: base_opcode 100 + +encoder_headers + a list of headers that will be included in the encoder header file + format: encoder_headers <stdio.h> "kuku.h" + +client_context_headers + a list of headers that will be included in the client context header file + format: client_context_headers <stdio.h> "kuku.h" + +decoder_headers + a list of headers that will be included in the decoder header file + format: decoder_headers <stdio.h> "kuku.h" + +server_context_headers + a list of headers that will be included in the server context header file + format: server_context_headers <stdio.h> "kuku.h" + + +Entry point flags description: + + len + desciption : provide an expression to calcualte an expression data len + format: len <var name> <c expression that calcluates the data len> + +custom_pack + description: provide an expression to pack data into the stream. + format: custom_pack <var name> <c++ expression that pack data from var into the stream> + The stream is represented by a (unsigned char *)ptr. The expression may also refer + to other function parameters. In addition, the expression may refer to 'void *self' which + is the encoding context as provided by the caller. + + dir + description : set a pointer direction (in - for data that goes + to the codec, out from data that returns from the codec. + format: dir <varname> <[in | out | inout]> + + var_flag + description : set variable flags + 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 + description: set entry point flag; + format: flag < unsupported | ... > + supported flags are: + unsupported - The encoder side implementation is pointed to "unsuppored reporting function". + custom_decoder - The decoder is expected to be provided with + custom implementation. The call to the + deocder function includes a pointer to the + context + not_api - the function is not native gl api + + diff --git a/host/commands/emugen/README.md b/host/commands/emugen/README.md new file mode 100644 index 0000000000000000000000000000000000000000..dfc130aa075b0d8b31a1a2aaed6645500f13875c --- /dev/null +++ b/host/commands/emugen/README.md @@ -0,0 +1,17 @@ +# emugen (cuttlefish) + +This directory contains a fork of the emugen tool from the external/qemu project +on the emu-master-dev branch. The tool is unmodified except for the following +changes: + +1) The android/base/EnumFlags.h header has been forked, to avoid having to copy + over all of the host-side android-base port. + +2) The unittest infrastructure and all unittests have been removed. + +3) This README.md file replaces the upstream README file. + +4) The binary builds to `emugen_cuttlefish` so as to avoid conflicts. + +Do not contribute change only to this project; contribute them to external/qemu +upstream, then cherry-pick them over. diff --git a/host/commands/emugen/TypeFactory.cpp b/host/commands/emugen/TypeFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e0cc96e0517cdc3cbe61d9d75eee1e4be0b67d6 --- /dev/null +++ b/host/commands/emugen/TypeFactory.cpp @@ -0,0 +1,157 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "TypeFactory.h" + +#include "Parser.h" +#include "VarType.h" +#include "strUtils.h" + +#include <map> +#include <string> + +#include <stdio.h> +#include <stdlib.h> + + +TypeFactory * TypeFactory::m_instance = NULL; + +typedef std::map<std::string, VarType> TypeMap; +static TypeMap g_varMap; +static bool g_initialized = false; +static int g_typeId = 0; + + +#define ADD_TYPE(name, size, printformat,ispointer) \ + g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, (size + 7) >> 3, printformat , ispointer))); + +void TypeFactory::initBaseTypes() +{ + g_initialized = true; + ADD_TYPE("UNKNOWN", 0, "0x%x", false); + ADD_TYPE("void", 0, "0x%x", false); + ADD_TYPE("char", 8, "%c", false); + ADD_TYPE("int", 32, "%d", false); + ADD_TYPE("float", 32, "%d", false); + ADD_TYPE("short", 16, "%d", false); +} + +int TypeFactory::initFromFile(const std::string &filename) +{ + if (!g_initialized) { + initBaseTypes(); + } + + FILE *fp = fopen(filename.c_str(), "rt"); + if (fp == NULL) { + perror(filename.c_str()); + return -1; + } + char line[1000]; + int lc = 0; + while(fgets(line, sizeof(line), fp) != NULL) { + lc++; + std::string str = trim(line); + if (str.size() == 0 || str.at(0) == '#') { + continue; + } + size_t pos = 0, last; + std::string name; + name = getNextToken(str, pos, &last, WHITESPACE); + name = normalizeTypeDeclaration(name); + if (name.size() == 0) { + fprintf(stderr, "Error: %d : missing type name\n", lc); + return -2; + } + pos = last + 1; + std::string size; + size = getNextToken(str, pos, &last, WHITESPACE); + if (size.size() == 0) { + fprintf(stderr, "Error: %d : missing type width\n", lc); + return -2; + } + pos = last + 1; + std::string printString; + printString = getNextToken(str, pos, &last, WHITESPACE); + if (printString.size() == 0) { + fprintf(stderr, "Error: %d : missing print-string\n", lc); + return -2; + } + + // The ispointer definition is optional since we can just + // look at the type name, and determine it is a pointer if + // it ends with '*'. + bool isPointer = (name[name.size() - 1U] == '*'); + + pos = last + 1; + std::string pointerDef; + pointerDef = getNextToken(str, pos, &last, WHITESPACE); + if (pointerDef.size() != 0) { + // Just a little sanity check. + if (std::string("true")==pointerDef) { + if (!isPointer) { + fprintf(stderr, "Error: %d: invalid isPointer definition: 'true' but name does not end with '*'!\n", lc); + return -2; + } + } else if (std::string("false")==pointerDef) { + if (isPointer) { + fprintf(stderr, "Error: %d: invalid isPointer definition: 'false' but name does end with '*'!\n", lc); + return -2; + } + } else { + fprintf(stderr, "Error: %d : invalid isPointer definition, must be either \"true\" or \"false\"\n", lc); + return -2; + } + } + + size_t bitSize = atoi(size.c_str()); + size_t byteSize = (bitSize + 7) >> 3; + + if (getVarTypeByName(name)->id() != 0) { + fprintf(stderr, + "Warining: %d : type %s is already known, definition in line %d is taken\n", + lc, name.c_str(), lc); + } + g_varMap.insert(std::pair<std::string, VarType>( + name, VarType(g_typeId++, + name, + byteSize, + printString, + isPointer))); + std::string constName = "const " + name; + g_varMap.insert(std::pair<std::string, VarType>( + constName, VarType(g_typeId++, + constName, + byteSize, + printString, + isPointer))); //add a const type + } + g_initialized = true; + return 0; +} + + +const VarType * TypeFactory::getVarTypeByName(const std::string & type) +{ + if (!g_initialized) { + initBaseTypes(); + } + TypeMap::iterator i = g_varMap.find(type); + if (i == g_varMap.end()) { + i = g_varMap.find("UNKNOWN"); + } + return &(i->second); +} + diff --git a/host/commands/emugen/TypeFactory.h b/host/commands/emugen/TypeFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..deee2ca49f3ec500e35ae14adf4a7f7ee3df8b01 --- /dev/null +++ b/host/commands/emugen/TypeFactory.h @@ -0,0 +1,37 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef __TYPE__FACTORY__H__ +#define __TYPE__FACTORY__H__ + +#include <string> +#include "VarType.h" + +class TypeFactory { +public: + static TypeFactory *instance() { + if (m_instance == NULL) { + m_instance = new TypeFactory; + } + return m_instance; + } + const VarType * getVarTypeByName(const std::string &type); + int initFromFile(const std::string &filename); +private: + static TypeFactory *m_instance; + void initBaseTypes(); + TypeFactory() {} +}; +#endif diff --git a/host/commands/emugen/Var.h b/host/commands/emugen/Var.h new file mode 100644 index 0000000000000000000000000000000000000000..823058d6e914e368e4a37e775a98113d8308e884 --- /dev/null +++ b/host/commands/emugen/Var.h @@ -0,0 +1,118 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef __VAR__H__ +#define __VAR__H__ + +#include "VarType.h" +#include <string> +#include <stdio.h> + +class Var { +public: + // pointer data direction - from the client point of view. + typedef enum { POINTER_OUT = 0x1, POINTER_IN = 0x2, POINTER_INOUT = 0x3 } PointerDir; + Var() = default; + + Var(const std::string & name, + const VarType * vartype, + const std::string & lenExpression, + PointerDir dir, + const std::string &packExpression, + const std::string &unpackExpression, + const std::string &writeExpression) : + m_name(name), + m_type(const_cast<VarType *>(vartype)), + m_lenExpression(lenExpression), + m_pointerDir(dir), + m_packExpression(packExpression), + m_unpackExpression(unpackExpression), + m_host_packTmpAllocExpression(""), + m_host_packExpression(""), + m_guest_unpackExpression(""), + m_writeExpression(writeExpression) + { + } + + void init(const std::string name, const VarType * vartype, + std::string lenExpression, + PointerDir dir, + std::string packExpression, + std::string unpackExpression, + std::string writeExpression) { + m_name = name; + m_type = vartype; + m_lenExpression = lenExpression; + m_packExpression = packExpression; + m_unpackExpression = unpackExpression; + m_host_packTmpAllocExpression = ""; + m_host_packExpression = ""; + m_guest_unpackExpression = ""; + m_writeExpression = writeExpression; + m_pointerDir = dir; + m_nullAllowed = false; + m_isLarge = false; + + } + + const std::string & name() const { return m_name; } + const VarType * type() const { return m_type; } + bool isPointer() const { return m_type->isPointer(); } + bool isVoid() const { return ((m_type->bytes() == 0) && (!m_type->isPointer())); } + const std::string & lenExpression() const { return m_lenExpression; } + const std::string & packExpression() const { return(m_packExpression); } + const std::string & unpackExpression() const { return(m_unpackExpression); } + const std::string & hostPackTmpAllocExpression() const { return(m_host_packTmpAllocExpression); } + const std::string & hostPackExpression() const { return(m_host_packExpression); } + const std::string & guestUnpackExpression() const { return(m_guest_unpackExpression); } + const std::string & writeExpression() const { return(m_writeExpression); } + const std::string & paramCheckExpression() const { return m_paramCheckExpression; } + void setLenExpression(const std::string & lenExpression) { m_lenExpression = lenExpression; } + void setPackExpression(const std::string & packExpression) { m_packExpression = packExpression; } + void setUnpackExpression(const std::string & unpackExpression) { m_unpackExpression = unpackExpression; } + void setHostPackTmpAllocExpression(const std::string & expr) { m_host_packTmpAllocExpression = expr; } + void setHostPackExpression(const std::string & expr) { m_host_packExpression = expr; } + void setGuestUnpackExpression(const std::string & expr) { m_guest_unpackExpression = expr; } + void setWriteExpression(const std::string & writeExpression) { m_writeExpression = writeExpression; } + void setParamCheckExpression(const std::string & paramCheckExpression) { m_paramCheckExpression = paramCheckExpression; } + 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; } + void setDMA(bool state) { m_isDMA = state; } + bool nullAllowed() const { return m_nullAllowed; } + bool isLarge() const { return m_isLarge; } + bool isDMA() const { return m_isDMA; } + 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()); } + +private: + std::string m_name; + const VarType * m_type = nullptr; + std::string m_lenExpression; // an expression to calcualte a pointer data size + PointerDir m_pointerDir = POINTER_IN; + bool m_nullAllowed = false; + bool m_isLarge = false; + bool m_isDMA = false; + std::string m_packExpression; // an expression to pack data into the stream + std::string m_unpackExpression; // an expression to unpack data that has arrived from the stream + std::string m_host_packTmpAllocExpression; // an expression to create temporaries for getting into packed form for readbacks + std::string m_host_packExpression; // an expression to pack data into the stream but for readbacks + std::string m_guest_unpackExpression; // an expression to unpack readbacks on the guest + std::string m_writeExpression; // an expression to write data into the stream + std::string m_paramCheckExpression; //an expression to check parameter value +}; + +#endif diff --git a/host/commands/emugen/VarType.h b/host/commands/emugen/VarType.h new file mode 100644 index 0000000000000000000000000000000000000000..b6937a002cfa7d828a8b4d26227194898aff56f5 --- /dev/null +++ b/host/commands/emugen/VarType.h @@ -0,0 +1,62 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef __VARTYPE__H__ +#define __VARTYPE__H__ + +#include <string> + +// VarType models the types of values used on the wire protocol by +// both encoders and decoders. Each type is identified by a unique id, +// and a name, and provides a size in bytes for the values, a printf-like +// formatter string, and a flag telling if the value corresponds to a +// pointer. +class VarType { +public: + VarType() : + m_id(0), + m_name("default_constructed"), + m_byteSize(0), + m_printFormat("0x%x"), + m_isPointer(false) {} + + VarType(size_t id, + const std::string& name, + size_t byteSize, + const std::string& printFormat, + bool isPointer) : + m_id(id), + m_name(name), + m_byteSize(byteSize), + m_printFormat(printFormat), + m_isPointer(isPointer) {} + + ~VarType() {} + + size_t id() const { return m_id; } + const std::string& name() const { return m_name; } + size_t bytes() const { return m_byteSize; } + const std::string& printFormat() const { return m_printFormat; } + bool isPointer() const { return m_isPointer; } + +private: + size_t m_id; + std::string m_name; + size_t m_byteSize; + std::string m_printFormat; + bool m_isPointer; +}; + +#endif diff --git a/host/commands/emugen/android/base/EnumFlags.h b/host/commands/emugen/android/base/EnumFlags.h new file mode 100644 index 0000000000000000000000000000000000000000..fec56b9282796c68878241754bd3859638836b34 --- /dev/null +++ b/host/commands/emugen/android/base/EnumFlags.h @@ -0,0 +1,117 @@ +// Copyright 2015 The Android Open Source Project +// +// This software is licensed under the terms of the GNU General Public +// License version 2, as published by the Free Software Foundation, and +// may be copied, distributed, and modified under those terms. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +#pragma once + +#include <type_traits> + +// This header defines some utitily methods to manipulate scoped enums as flags +// C++11 scoped enums by default don't support flag operations (e.g. if (a & b)) +// We need to define bitwise operations for them to be able to have strongly +// typed flags in our code. +// +// To enable the flag operators for your enum, most probably you just need to +// include this file. The only exception is if your enum is located in some +// namespace other than android, android::base or global. In that case you also +// need to add the following using to bring in the operators: +// +// using namespace ::android::base::EnumFlags; + +namespace android { +namespace base { +namespace EnumFlags { + +// A predicate which checks if template agument is a scoped enum +template<class E> +using is_scoped_enum = std::integral_constant< + bool, + std::is_enum<E>::value && !std::is_convertible<E, int>::value>; + +template <class E> +using underlying_enum_type = typename std::underlying_type<E>::type; + +template <class E, class Res = E> +using enable_if_scoped_enum = + typename std::enable_if<is_scoped_enum<E>::value, Res>::type; + +template <class E> +enable_if_scoped_enum<E> operator|(E l, E r) { + return static_cast<E>(static_cast<underlying_enum_type<E>>(l) + | static_cast<underlying_enum_type<E>>(r)); +} + +template <class E> +enable_if_scoped_enum<E> operator&(E l, E r) { + return static_cast<E>(static_cast<underlying_enum_type<E>>(l) + & static_cast<underlying_enum_type<E>>(r)); +} + +template <class E> +enable_if_scoped_enum<E> operator~(E e) { + return static_cast<E>(~static_cast<underlying_enum_type<E>>(e)); +} + +template <class E> +enable_if_scoped_enum<E> operator|=(E& l, E r) { + return l = (l | r); +} + +template <class E> +enable_if_scoped_enum<E> operator&=(E& l, E r) { + return l = (l & r); +} + +template <class E> +enable_if_scoped_enum<E, bool> operator!(E e) { + return !static_cast<underlying_enum_type<E>>(e); +} + +template <class E> +enable_if_scoped_enum<E, bool> operator!=(E e, int val) { + return static_cast<underlying_enum_type<E>>(e) != + static_cast<underlying_enum_type<E>>(val); +} + +template <class E> +enable_if_scoped_enum<E, bool> operator!=(int val, E e) { + return e != val; +} + +template <class E> +enable_if_scoped_enum<E, bool> operator==(E e, int val) { + return static_cast<underlying_enum_type<E>>(e) == + static_cast<underlying_enum_type<E>>(val); +} + +template <class E> +enable_if_scoped_enum<E, bool> operator==(int val, E e) { + return e == val; +} + +template <class E> +enable_if_scoped_enum<E, bool> nonzero(E e) { + return static_cast<underlying_enum_type<E>>(e) != 0; +} + +} // namespace EnumFlags + +// For the ADL to kick in let's make sure we bring all the operators into our +// main AndroidEmu namespaces... +using namespace ::android::base::EnumFlags; + +} // namespace base + +using namespace ::android::base::EnumFlags; + +} // namespace android + +// ... and into the global one, where most of the client functions are +using namespace ::android::base::EnumFlags; diff --git a/host/commands/emugen/errors.h b/host/commands/emugen/errors.h new file mode 100644 index 0000000000000000000000000000000000000000..d09c292910549d6986bddf57b4df1d4485e17cb4 --- /dev/null +++ b/host/commands/emugen/errors.h @@ -0,0 +1,24 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef _ERRORS_H_ +#define _ERRORS_H_ + +#define BAD_USAGE -1 +#define BAD_SPEC_FILE -2 +#define BAD_TYPES_FILE -3 +#define BAD_ATTRIBUTES_FILE -4 + +#endif diff --git a/host/commands/emugen/getopt.c b/host/commands/emugen/getopt.c new file mode 100644 index 0000000000000000000000000000000000000000..d11be644b5feeec87410f56841d92d8d2043c805 --- /dev/null +++ b/host/commands/emugen/getopt.c @@ -0,0 +1,76 @@ +#include "getopt.h" + +#include <stdio.h> +#include <string.h> + +#define _getprogname() nargv[0] + +int opterr = 1; +int optind = 1; +int optopt = 0; +char* optarg; + +int getopt(int argc, char* const argv[], const char* ostr) { + static const char kEmpty[] = ""; + static const char* place = kEmpty; + if (!*place) { + if (optind >= argc) + return -1; + + const char* arg = argv[optind]; + if (arg[0] != '-') { + // Not an option. + return -1; + } + if (arg[1] == '-' && !arg[2]) { + // '--' -> end of options. + return -1; + } + if (!arg[1]) { + // Single '-', If the program wants it, treat it as an option. + // Otherwise, it's the end of options. + if (!strchr(ostr, '-')) { + return -1; + } + optopt = '-'; + place = arg + 1; + } else { + optopt = arg[1]; + place = arg + 2; + } + }; + + char* oindex = strchr(ostr, optopt); + if (!oindex) { + // Unsupported option. + (void)fprintf(stderr, "%s: illegal option -- %c\n", argv[0], optopt); + return '?'; + } + if (oindex[1] != ':') { + // No argument needed. + optarg = NULL; + if (!*place) + optind++; + return optopt; + } + + // This option needs an argument. Either after the option character, + // or the argument that follows. + if (*place) { + optarg = (char *)place; + } else if (argc > ++optind) { + optarg = (char *)argv[optind++]; + } else if (oindex[2] == ':') { + // Optional argument is missing. + place = kEmpty; + optarg = NULL; + return optopt; + } else { + // Missing argument. + place = kEmpty; + (void)fprintf(stderr, "%s: option requires an argument --%c\n", + argv[0], optopt); + return ':'; + } + return optopt; +} diff --git a/host/commands/emugen/getopt.h b/host/commands/emugen/getopt.h new file mode 100644 index 0000000000000000000000000000000000000000..cc04850a22c4cc112e8f3c68d6391341b1486813 --- /dev/null +++ b/host/commands/emugen/getopt.h @@ -0,0 +1,18 @@ +#ifndef GETOPT_H +#define GETOPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern int optind; +extern char* optarg; +extern int optopt; + +int getopt(int argc, char* const argv[], const char* ostr); + +#ifdef __cplusplus +} +#endif + +#endif // GETOPT_H diff --git a/host/commands/emugen/main.cpp b/host/commands/emugen/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6200349f7fc85608b7e57010e36ed359edb4b15d --- /dev/null +++ b/host/commands/emugen/main.cpp @@ -0,0 +1,164 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include <stdio.h> +#include <stdlib.h> +#include "errors.h" +#include "EntryPoint.h" +#include "strUtils.h" +#include "ApiGen.h" +#include "TypeFactory.h" +#include "getopt.h" + +const std::string SPEC_EXTENSION = std::string(".in"); +const std::string ATTRIB_EXTENSION = std::string(".attrib"); +const std::string TYPES_EXTENTION = std::string(".types"); + + +void usage(const char *filename) +{ + fprintf(stderr, "Usage: %s [options] <base name>\n", filename); + fprintf(stderr, "\t-h: This message\n"); + fprintf(stderr, "\t-E <dir>: generate encoder into dir\n"); + fprintf(stderr, "\t-D <dir>: generate decoder into dir\n"); + fprintf(stderr, "\t-i: input dir, local directory by default\n"); + fprintf(stderr, "\t-T : generate attribute template into the input directory\n\t\tno other files are generated\n"); + fprintf(stderr, "\t-W : generate wrapper into dir\n"); +} + +int main(int argc, char *argv[]) +{ + std::string encoderDir = ""; + std::string decoderDir = ""; + std::string wrapperDir = ""; + std::string inDir = "."; + bool generateAttributesTemplate = false; + + int c; + while((c = getopt(argc, argv, "TE:D:i:hW:")) != -1) { + switch(c) { + case 'W': + wrapperDir = std::string(optarg); + break; + case 'T': + generateAttributesTemplate = true; + break; + case 'h': + usage(argv[0]); + exit(0); + break; + case 'E': + encoderDir = std::string(optarg); + break; + case 'D': + decoderDir = std::string(optarg); + break; + case 'i': + inDir = std::string(optarg); + break; + case ':': + fprintf(stderr, "Missing argument !!\n"); + [[fallthrough]]; + default: + usage(argv[0]); + exit(0); + } + } + + if (optind >= argc) { + fprintf(stderr, "Usage: %s [options] <base name> \n", argv[0]); + return BAD_USAGE; + } + + if (encoderDir.size() == 0 && + decoderDir.size() == 0 && + generateAttributesTemplate == false && + wrapperDir.size() == 0) { + fprintf(stderr, "No output specified - aborting\n"); + return BAD_USAGE; + } + + std::string baseName = std::string(argv[optind]); + ApiGen apiEntries(baseName); + + // init types; + std::string typesFilename = inDir + "/" + baseName + TYPES_EXTENTION; + + if (TypeFactory::instance()->initFromFile(typesFilename) < 0) { + fprintf(stderr, "missing or error reading types file: %s...ignored\n", typesFilename.c_str()); + } + + std::string filename = inDir + "/" + baseName + SPEC_EXTENSION; + if (apiEntries.readSpec(filename) < 0) { + perror(filename.c_str()); + return BAD_SPEC_FILE; + } + + + if (generateAttributesTemplate) { + apiEntries.genAttributesTemplate(inDir + "/" + baseName + ATTRIB_EXTENSION); + exit(0); + } + + std::string attribFileName = inDir + "/" + baseName + ATTRIB_EXTENSION; + if (apiEntries.readAttributes(attribFileName) < 0) { + perror(attribFileName.c_str()); + fprintf(stderr, "failed to parse attributes\n"); + exit(1); + } + + if (encoderDir.size() != 0) { + + apiEntries.genOpcodes(encoderDir + "/" + baseName + "_opcodes.h"); + apiEntries.genContext(encoderDir + "/" + baseName + "_client_context.h", ApiGen::CLIENT_SIDE); + apiEntries.genContextImpl(encoderDir + "/" + baseName + "_client_context.cpp", ApiGen::CLIENT_SIDE); + + apiEntries.genProcTypes(encoderDir + "/" + baseName + "_client_proc.h", ApiGen::CLIENT_SIDE); + apiEntries.genFuncTable(encoderDir + "/" + baseName + "_ftable.h", ApiGen::CLIENT_SIDE); + + apiEntries.genEntryPoints(encoderDir + "/" + baseName + "_entry.cpp", ApiGen::CLIENT_SIDE); + apiEntries.genEncoderHeader(encoderDir + "/" + baseName + "_enc.h"); + apiEntries.genEncoderImpl(encoderDir + "/" + baseName + "_enc.cpp"); + } + + if (decoderDir.size() != 0) { + apiEntries.genOpcodes(decoderDir + "/" + baseName + "_opcodes.h"); + apiEntries.genProcTypes(decoderDir + "/" + baseName + "_server_proc.h", ApiGen::SERVER_SIDE); + apiEntries.genContext(decoderDir + "/" + baseName + "_server_context.h", ApiGen::SERVER_SIDE); + apiEntries.genContextImpl(decoderDir + "/" + baseName + "_server_context.cpp", ApiGen::SERVER_SIDE); + apiEntries.genDecoderHeader(decoderDir + "/" + baseName + "_dec.h"); + apiEntries.genDecoderImpl(decoderDir + "/" + baseName + "_dec.cpp"); + } + + if (wrapperDir.size() != 0) { + apiEntries.genProcTypes(wrapperDir + "/" + baseName + "_wrapper_proc.h", ApiGen::WRAPPER_SIDE); + apiEntries.genContext(wrapperDir + "/" + baseName + "_wrapper_context.h", ApiGen::WRAPPER_SIDE); + apiEntries.genContextImpl(wrapperDir + "/" + baseName + "_wrapper_context.cpp", ApiGen::WRAPPER_SIDE); + apiEntries.genEntryPoints(wrapperDir + "/" + baseName + "_wrapper_entry.cpp", ApiGen::WRAPPER_SIDE); + } + +#ifdef DEBUG_DUMP + int withPointers = 0; + printf("%d functions found\n", int(apiEntries.size())); + for (int i = 0; i < apiEntries.size(); i++) { + if (apiEntries[i].hasPointers()) { + withPointers++; + apiEntries[i].print(); + } + } + fprintf(stdout, "%d entries has poitners\n", withPointers); +#endif + +} diff --git a/host/commands/emugen/strUtils.cpp b/host/commands/emugen/strUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..357054b5c686b90f6380df425d0c65322bc36c96 --- /dev/null +++ b/host/commands/emugen/strUtils.cpp @@ -0,0 +1,49 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "strUtils.h" + +using namespace std; + + +std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim) +{ + if (str.size() == 0 || pos >= str.size()) return ""; + + pos = str.find_first_not_of(WHITESPACE, pos); + if (pos == std::string::npos) return ""; + + *last = str.find_first_of(delim, pos); + if (*last == std::string::npos) *last = str.size(); + std::string retval = str.substr(pos, *last - pos); + retval = trim(retval); + return retval; +} + + +std::string trim(const string & str) +{ + string result; + string::size_type start = str.find_first_not_of(WHITESPACE, 0); + string::size_type end = str.find_last_not_of(WHITESPACE); + if (start == string::npos || end == string::npos) { + result = string(""); + } else { + result = str.substr(start, end - start + 1); + } + return result; +} + + diff --git a/host/commands/emugen/strUtils.h b/host/commands/emugen/strUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..3fa0908d3d86131bac47eb6da0cf2dce89916e2f --- /dev/null +++ b/host/commands/emugen/strUtils.h @@ -0,0 +1,33 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef STR_UTILS_H_ +#define STR_UTILS_H_ + +#include <string> +#include <sstream> + +#define WHITESPACE " \t\n" + +std::string trim(const std::string & str); +std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim); +template <class T> std::string inline toString(const T& t) { + std::stringstream ss; + ss << t; + return ss.str(); + +} + +#endif diff --git a/host/commands/emugen/tests/run-tests.sh b/host/commands/emugen/tests/run-tests.sh new file mode 100755 index 0000000000000000000000000000000000000000..67409edcc2353f64787b6b88e47db8255b2a70f6 --- /dev/null +++ b/host/commands/emugen/tests/run-tests.sh @@ -0,0 +1,129 @@ +#!/bin/sh + +# Copyright 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -e + +export LANG=C +export LC_ALL=C + +PROGDIR=$(dirname "$0") +PROGNAME=$(basename "$0") + +fatal () { + echo "ERROR: $@" + exit 1 +} + +OPT_EMUGEN= +OPT_HELP= +OPT_OUT_DIR= +OPT_TOOL= + +for OPT; do + OPTARG=$(expr "x$OPT" : "x[^=]*=\\(.*\\)" || true) + case $OPT in + --help|-h|-?) + OPT_HELP=true + ;; + --emugen=*) + OPT_EMUGEN=$OPTARG + ;; + --out-dir=*) + OPT_OUT_DIR=$OPTARG + ;; + --tool=*) + OPT_TOOL=$OPTARG + ;; + -*) + fatal "Invalid option '$OPT', see --help." + ;; + *) + fatal "This script doesn't take arguments, see --help." + ;; + esac +done + +if [ "$OPT_HELP" ]; then + cat <<EOF +Usage: $PROGNAME [options] + +Run the emugen test suite. This scripts looks for sub-directories +named t.<number>/input, and uses them as input to 'emugen'. It then +compares the output to t.<number>/expected/ content. + +Valid options: + --help|-h|-? Print this help. + --out-dir=<dir> Generate outputs into <dir>. + --emugen=<program> Emugen program path, if not in path. + --tool=<tool> Launch visual diff tool in case of differences. +EOF + exit 0 +fi + +# Find emugen program +EMUGEN= +if [ "$OPT_EMUGEN" ]; then + EMUGEN=$OPT_EMUGEN +else + EMUGEN=$(which emugen 2>/dev/null || true) + if [ -z "$EMUGEN" ]; then + fatal "Cannot find 'emugen' program in PATH, use --emugen=<program> option." + fi + echo "Auto-config: --emugen=$EMUGEN" +fi +if [ ! -f "$EMUGEN" ]; then + fatal "Emugen program doesn't exist: $EMUGEN" +fi + +# Create output directory. +OUT_DIR= +if [ "$OPT_OUT_DIR" ]; then + OUT_DIR=$OPT_OUT_DIR +else + OUT_DIR=/tmp/$USER-emugen-testing + echo "Auto-config: --out-dir=$OUT_DIR" +fi +mkdir -p "$OUT_DIR" && rm -rf "$OUT_DIR/emugen" + +OUT_DIR=$OUT_DIR/emugen + +# Find test directories +TEST_DIRS=$(cd "$PROGDIR" && find . -name "t.*" | sed -e 's|^\./||') +for TEST_DIR in $TEST_DIRS; do + IN=$PROGDIR/$TEST_DIR/input + PREFIXES=$(cd $IN && find . -name "*.in" | sed -e 's|^\./||g' -e 's|\.in$||g') + OUT=$OUT_DIR/$TEST_DIR + mkdir -p "$OUT/encoder" + mkdir -p "$OUT/decoder" + mkdir -p "$OUT/wrapper" + for PREFIX in $PREFIXES; do + echo "Processing $IN/foo.*" + $EMUGEN -i "$PROGDIR/$TEST_DIR/input" -D "$OUT/decoder" -E "$OUT/encoder" -W "$OUT/wrapper" $PREFIX + done + if ! diff -qr "$PROGDIR/$TEST_DIR/expected" "$OUT"; then + if [ "$OPT_TOOL" ]; then + $OPT_TOOL "$PROGDIR/$TEST_DIR/expected" "$OUT" + else + echo "ERROR: Invalid differences between actual and expected output!" + diff -burN "$PROGDIR/$TEST_DIR/expected" "$OUT" + exit 1 + fi + fi +done + +echo "All good!" +exit 0 diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.cpp b/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec16b177fcf65bcf0f710207ab6d11d82c083d10 --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.cpp @@ -0,0 +1,178 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' + + +#include <string.h> +#include "foo_opcodes.h" + +#include "foo_dec.h" + + +#include "ProtocolUtils.h" + +#include "ChecksumCalculatorThreadInfo.h" + +#include <stdio.h> + +typedef unsigned int tsize_t; // Target "size_t", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled. + +#ifdef OPENGL_DEBUG_PRINTOUT +# define DEBUG(...) do { if (emugl_cxt_logger) { emugl_cxt_logger(__VA_ARGS__); } } while(0) +#else +# define DEBUG(...) ((void)0) +#endif + +#ifdef CHECK_GL_ERRORS +# define SET_LASTCALL(name) sprintf(lastCall, #name) +#else +# define SET_LASTCALL(name) +#endif +using namespace emugl; + +size_t foo_decoder_context_t::decode(void *buf, size_t len, IOStream *stream, ChecksumCalculator* checksumCalc) { + if (len < 8) return 0; +#ifdef CHECK_GL_ERRORS + char lastCall[256] = {0}; +#endif + unsigned char *ptr = (unsigned char *)buf; + const unsigned char* const end = (const unsigned char*)buf + len; + const size_t checksumSize = checksumCalc->checksumByteSize(); + const bool useChecksum = checksumSize > 0; + while (end - ptr >= 8) { + uint32_t opcode = *(uint32_t *)ptr; + int32_t packetLen = *(int32_t *)(ptr + 4); + if (end - ptr < packetLen) return ptr - (unsigned char*)buf; + switch(opcode) { + case OP_fooAlphaFunc: { + FooInt var_func = Unpack<FooInt,uint32_t>(ptr + 8); + FooFloat var_ref = Unpack<FooFloat,uint32_t>(ptr + 8 + 4); + if (useChecksum) { + ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + 4, ptr + 8 + 4 + 4, checksumSize, + "foo_decoder_context_t::decode, OP_fooAlphaFunc: GL checksumCalculator failure\n"); + } + DEBUG("foo(%p): fooAlphaFunc(%d %f )\n", stream, var_func, var_ref); + this->fooAlphaFunc(var_func, var_ref); + SET_LASTCALL("fooAlphaFunc"); + break; + } + case OP_fooIsBuffer: { + uint32_t size_stuff __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8); + InputBuffer inptr_stuff(ptr + 8 + 4, size_stuff); + if (useChecksum) { + ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + size_stuff, ptr + 8 + 4 + size_stuff, checksumSize, + "foo_decoder_context_t::decode, OP_fooIsBuffer: GL checksumCalculator failure\n"); + } + size_t totalTmpSize = sizeof(FooBoolean); + totalTmpSize += checksumSize; + unsigned char *tmpBuf = stream->alloc(totalTmpSize); + DEBUG("foo(%p): fooIsBuffer(%p(%u) )\n", stream, (void*)(inptr_stuff.get()), size_stuff); + *(FooBoolean *)(&tmpBuf[0]) = this->fooIsBuffer((void*)(inptr_stuff.get())); + if (useChecksum) { + ChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, &tmpBuf[0], totalTmpSize - checksumSize, &tmpBuf[totalTmpSize - checksumSize], checksumSize); + } + stream->flush(); + SET_LASTCALL("fooIsBuffer"); + break; + } + case OP_fooUnsupported: { + uint32_t size_params __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8); + InputBuffer inptr_params(ptr + 8 + 4, size_params); + if (useChecksum) { + ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + size_params, ptr + 8 + 4 + size_params, checksumSize, + "foo_decoder_context_t::decode, OP_fooUnsupported: GL checksumCalculator failure\n"); + } + DEBUG("foo(%p): fooUnsupported(%p(%u) )\n", stream, (void*)(inptr_params.get()), size_params); + this->fooUnsupported((void*)(inptr_params.get())); + SET_LASTCALL("fooUnsupported"); + break; + } + case OP_fooDoEncoderFlush: { + FooInt var_param = Unpack<FooInt,uint32_t>(ptr + 8); + if (useChecksum) { + ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4, ptr + 8 + 4, checksumSize, + "foo_decoder_context_t::decode, OP_fooDoEncoderFlush: GL checksumCalculator failure\n"); + } + DEBUG("foo(%p): fooDoEncoderFlush(%d )\n", stream, var_param); + this->fooDoEncoderFlush(var_param); + SET_LASTCALL("fooDoEncoderFlush"); + break; + } + case OP_fooTakeConstVoidPtrConstPtr: { + uint32_t size_param __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8); + InputBuffer inptr_param(ptr + 8 + 4, size_param); + if (useChecksum) { + ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + size_param, ptr + 8 + 4 + size_param, checksumSize, + "foo_decoder_context_t::decode, OP_fooTakeConstVoidPtrConstPtr: GL checksumCalculator failure\n"); + } + DEBUG("foo(%p): fooTakeConstVoidPtrConstPtr(%p(%u) )\n", stream, (const void* const*)(inptr_param.get()), size_param); + this->fooTakeConstVoidPtrConstPtr((const void* const*)(inptr_param.get())); + SET_LASTCALL("fooTakeConstVoidPtrConstPtr"); + break; + } + case OP_fooSetComplexStruct: { + uint32_t size_obj __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8); + InputBuffer inptr_obj(ptr + 8 + 4, size_obj); + void* inptr_obj_unpacked; + FooStruct unpacked; inptr_obj_unpacked = (void*)(&unpacked); fooStructUnpack((unsigned char*)(inptr_obj.get()), size_obj, inptr_obj_unpacked); + if (useChecksum) { + ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + size_obj, ptr + 8 + 4 + size_obj, checksumSize, + "foo_decoder_context_t::decode, OP_fooSetComplexStruct: GL checksumCalculator failure\n"); + } + DEBUG("foo(%p): fooSetComplexStruct(%p(%u) )\n", stream, (const FooStruct*)(inptr_obj.get()), size_obj); + this->fooSetComplexStruct((const FooStruct*)(inptr_obj_unpacked)); + SET_LASTCALL("fooSetComplexStruct"); + break; + } + case OP_fooGetComplexStruct: { + uint32_t size_obj __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8); + if (useChecksum) { + ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4, ptr + 8 + 4, checksumSize, + "foo_decoder_context_t::decode, OP_fooGetComplexStruct: GL checksumCalculator failure\n"); + } + size_t totalTmpSize = size_obj; + totalTmpSize += checksumSize; + unsigned char *tmpBuf = stream->alloc(totalTmpSize); + OutputBuffer outptr_obj(&tmpBuf[0], size_obj); + void* forPacking_obj = nullptr; + FooStruct tmp; forPacking_obj = (void*)tmp; + DEBUG("foo(%p): fooGetComplexStruct(%p(%u) )\n", stream, (FooStruct*)(outptr_obj.get()), size_obj); + this->fooGetComplexStruct((FooStruct*)(forPacking_obj)); + if (size_obj) { + fooStructPack((unsigned char*)outptr_obj.get(), (FooStruct*)forPacking_obj); } + outptr_obj.flush(); + if (useChecksum) { + ChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, &tmpBuf[0], totalTmpSize - checksumSize, &tmpBuf[totalTmpSize - checksumSize], checksumSize); + } + stream->flush(); + SET_LASTCALL("fooGetComplexStruct"); + break; + } + case OP_fooInout: { + uint32_t size_count __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8); + InputBuffer inptr_count(ptr + 8 + 4, size_count); + if (useChecksum) { + ChecksumCalculatorThreadInfo::validOrDie(checksumCalc, ptr, 8 + 4 + size_count, ptr + 8 + 4 + size_count, checksumSize, + "foo_decoder_context_t::decode, OP_fooInout: GL checksumCalculator failure\n"); + } + size_t totalTmpSize = size_count; + totalTmpSize += checksumSize; + unsigned char *tmpBuf = stream->alloc(totalTmpSize); + OutputBuffer outptr_count(&tmpBuf[0], size_count); + memcpy(outptr_count.get(), inptr_count.get(), size_count); + DEBUG("foo(%p): fooInout(%p(%u) )\n", stream, (uint32_t*)(outptr_count.get()), size_count); + this->fooInout((uint32_t*)(outptr_count.get())); + outptr_count.flush(); + if (useChecksum) { + ChecksumCalculatorThreadInfo::writeChecksum(checksumCalc, &tmpBuf[0], totalTmpSize - checksumSize, &tmpBuf[totalTmpSize - checksumSize], checksumSize); + } + stream->flush(); + SET_LASTCALL("fooInout"); + break; + } + default: + return ptr - (unsigned char*)buf; + } //switch + ptr += packetLen; + } // while + return ptr - (unsigned char*)buf; +} diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.h b/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.h new file mode 100644 index 0000000000000000000000000000000000000000..d02509070b6d12b67f197f773a5eecfeef5c137f --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_dec.h @@ -0,0 +1,20 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' + +#ifndef GUARD_foo_decoder_context_t +#define GUARD_foo_decoder_context_t + +#include "OpenglRender/IOStream.h" +#include "ChecksumCalculator.h" +#include "foo_server_context.h" + + +#include "emugl/common/logging.h" + +struct foo_decoder_context_t : public foo_server_context_t { + + size_t decode(void *buf, size_t bufsize, IOStream *stream, ChecksumCalculator* checksumCalc); + +}; + +#endif // GUARD_foo_decoder_context_t diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_opcodes.h b/host/commands/emugen/tests/t.001/expected/decoder/foo_opcodes.h new file mode 100644 index 0000000000000000000000000000000000000000..ee453406f4e144dd9a1e74ec60ad1e22755fbb3e --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_opcodes.h @@ -0,0 +1,17 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#ifndef __GUARD_foo_opcodes_h_ +#define __GUARD_foo_opcodes_h_ + +#define OP_fooAlphaFunc 200 +#define OP_fooIsBuffer 201 +#define OP_fooUnsupported 202 +#define OP_fooDoEncoderFlush 203 +#define OP_fooTakeConstVoidPtrConstPtr 204 +#define OP_fooSetComplexStruct 205 +#define OP_fooGetComplexStruct 206 +#define OP_fooInout 207 +#define OP_last 208 + + +#endif diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.cpp b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5371fff2f6b2094decfaab39be999c3087afdd4e --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.cpp @@ -0,0 +1,23 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' + + +#include <string.h> +#include "foo_server_context.h" + + +#include <stdio.h> + +int foo_server_context_t::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData) +{ + fooAlphaFunc = (fooAlphaFunc_server_proc_t) getProc("fooAlphaFunc", userData); + fooIsBuffer = (fooIsBuffer_server_proc_t) getProc("fooIsBuffer", userData); + fooUnsupported = (fooUnsupported_server_proc_t) getProc("fooUnsupported", userData); + fooDoEncoderFlush = (fooDoEncoderFlush_server_proc_t) getProc("fooDoEncoderFlush", userData); + fooTakeConstVoidPtrConstPtr = (fooTakeConstVoidPtrConstPtr_server_proc_t) getProc("fooTakeConstVoidPtrConstPtr", userData); + fooSetComplexStruct = (fooSetComplexStruct_server_proc_t) getProc("fooSetComplexStruct", userData); + fooGetComplexStruct = (fooGetComplexStruct_server_proc_t) getProc("fooGetComplexStruct", userData); + fooInout = (fooInout_server_proc_t) getProc("fooInout", userData); + return 0; +} + diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.h b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.h new file mode 100644 index 0000000000000000000000000000000000000000..4f44919259e171bed1d994b20634ddd8b2e59628 --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_context.h @@ -0,0 +1,25 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#ifndef __foo_server_context_t_h +#define __foo_server_context_t_h + +#include "foo_server_proc.h" + +#include "foo_types.h" + + +struct foo_server_context_t { + + fooAlphaFunc_server_proc_t fooAlphaFunc; + fooIsBuffer_server_proc_t fooIsBuffer; + fooUnsupported_server_proc_t fooUnsupported; + fooDoEncoderFlush_server_proc_t fooDoEncoderFlush; + fooTakeConstVoidPtrConstPtr_server_proc_t fooTakeConstVoidPtrConstPtr; + fooSetComplexStruct_server_proc_t fooSetComplexStruct; + fooGetComplexStruct_server_proc_t fooGetComplexStruct; + fooInout_server_proc_t fooInout; + virtual ~foo_server_context_t() {} + int initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData); +}; + +#endif diff --git a/host/commands/emugen/tests/t.001/expected/decoder/foo_server_proc.h b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_proc.h new file mode 100644 index 0000000000000000000000000000000000000000..593e4c41142723ce21b081b9181d27e725a14026 --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/decoder/foo_server_proc.h @@ -0,0 +1,22 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#ifndef __foo_server_proc_t_h +#define __foo_server_proc_t_h + + + +#include "foo_types.h" +#ifndef foo_APIENTRY +#define foo_APIENTRY +#endif +typedef void (foo_APIENTRY *fooAlphaFunc_server_proc_t) (FooInt, FooFloat); +typedef FooBoolean (foo_APIENTRY *fooIsBuffer_server_proc_t) (void*); +typedef void (foo_APIENTRY *fooUnsupported_server_proc_t) (void*); +typedef void (foo_APIENTRY *fooDoEncoderFlush_server_proc_t) (FooInt); +typedef void (foo_APIENTRY *fooTakeConstVoidPtrConstPtr_server_proc_t) (const void* const*); +typedef void (foo_APIENTRY *fooSetComplexStruct_server_proc_t) (const FooStruct*); +typedef void (foo_APIENTRY *fooGetComplexStruct_server_proc_t) (FooStruct*); +typedef void (foo_APIENTRY *fooInout_server_proc_t) (uint32_t*); + + +#endif diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.cpp b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d28b5a0547f681b77136a0d1849b20370e889a58 --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.cpp @@ -0,0 +1,23 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' + + +#include <string.h> +#include "foo_client_context.h" + + +#include <stdio.h> + +int foo_client_context_t::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData) +{ + fooAlphaFunc = (fooAlphaFunc_client_proc_t) getProc("fooAlphaFunc", userData); + fooIsBuffer = (fooIsBuffer_client_proc_t) getProc("fooIsBuffer", userData); + fooUnsupported = (fooUnsupported_client_proc_t) getProc("fooUnsupported", userData); + fooDoEncoderFlush = (fooDoEncoderFlush_client_proc_t) getProc("fooDoEncoderFlush", userData); + fooTakeConstVoidPtrConstPtr = (fooTakeConstVoidPtrConstPtr_client_proc_t) getProc("fooTakeConstVoidPtrConstPtr", userData); + fooSetComplexStruct = (fooSetComplexStruct_client_proc_t) getProc("fooSetComplexStruct", userData); + fooGetComplexStruct = (fooGetComplexStruct_client_proc_t) getProc("fooGetComplexStruct", userData); + fooInout = (fooInout_client_proc_t) getProc("fooInout", userData); + return 0; +} + diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.h b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.h new file mode 100644 index 0000000000000000000000000000000000000000..d1c1675c0615a7df8928f30c994682e37f012a7d --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_context.h @@ -0,0 +1,30 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#ifndef __foo_client_context_t_h +#define __foo_client_context_t_h + +#include "foo_client_proc.h" + +#include "foo_types.h" + + +struct foo_client_context_t { + + fooAlphaFunc_client_proc_t fooAlphaFunc; + fooIsBuffer_client_proc_t fooIsBuffer; + fooUnsupported_client_proc_t fooUnsupported; + fooDoEncoderFlush_client_proc_t fooDoEncoderFlush; + fooTakeConstVoidPtrConstPtr_client_proc_t fooTakeConstVoidPtrConstPtr; + fooSetComplexStruct_client_proc_t fooSetComplexStruct; + fooGetComplexStruct_client_proc_t fooGetComplexStruct; + fooInout_client_proc_t fooInout; + virtual ~foo_client_context_t() {} + + typedef foo_client_context_t *CONTEXT_ACCESSOR_TYPE(void); + static void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f); + int initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData); + virtual void setError(unsigned int error){ (void)error; }; + virtual unsigned int getError(){ return 0; }; +}; + +#endif diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_client_proc.h b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_proc.h new file mode 100644 index 0000000000000000000000000000000000000000..d9bbcb6663a088357bc3e242ecf85236c3e83286 --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_client_proc.h @@ -0,0 +1,22 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#ifndef __foo_client_proc_t_h +#define __foo_client_proc_t_h + + + +#include "foo_types.h" +#ifndef foo_APIENTRY +#define foo_APIENTRY +#endif +typedef void (foo_APIENTRY *fooAlphaFunc_client_proc_t) (void * ctx, FooInt, FooFloat); +typedef FooBoolean (foo_APIENTRY *fooIsBuffer_client_proc_t) (void * ctx, void*); +typedef void (foo_APIENTRY *fooUnsupported_client_proc_t) (void * ctx, void*); +typedef void (foo_APIENTRY *fooDoEncoderFlush_client_proc_t) (void * ctx, FooInt); +typedef void (foo_APIENTRY *fooTakeConstVoidPtrConstPtr_client_proc_t) (void * ctx, const void* const*); +typedef void (foo_APIENTRY *fooSetComplexStruct_client_proc_t) (void * ctx, const FooStruct*); +typedef void (foo_APIENTRY *fooGetComplexStruct_client_proc_t) (void * ctx, FooStruct*); +typedef void (foo_APIENTRY *fooInout_client_proc_t) (void * ctx, uint32_t*); + + +#endif diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.cpp b/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13a4dd56b26fd4cb0d8ff2cfe3909031af78d62f --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.cpp @@ -0,0 +1,263 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' + + +#include <string.h> +#include "foo_opcodes.h" + +#include "foo_enc.h" + + +#include <vector> + +#include <stdio.h> + +namespace { + +void enc_unsupported() +{ + ALOGE("Function is unsupported\n"); +} + +void fooAlphaFunc_enc(void *self , FooInt func, FooFloat ref) +{ + + foo_encoder_context_t *ctx = (foo_encoder_context_t *)self; + IOStream *stream = ctx->m_stream; + ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator; + bool useChecksum = checksumCalculator->getVersion() > 0; + + unsigned char *ptr; + unsigned char *buf; + const size_t sizeWithoutChecksum = 8 + 4 + 4; + const size_t checksumSize = checksumCalculator->checksumByteSize(); + const size_t totalSize = sizeWithoutChecksum + checksumSize; + buf = stream->alloc(totalSize); + ptr = buf; + int tmp = OP_fooAlphaFunc;memcpy(ptr, &tmp, 4); ptr += 4; + memcpy(ptr, &totalSize, 4); ptr += 4; + + memcpy(ptr, &func, 4); ptr += 4; + memcpy(ptr, &ref, 4); ptr += 4; + + if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf); + if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize; + +} + +FooBoolean fooIsBuffer_enc(void *self , void* stuff) +{ + + foo_encoder_context_t *ctx = (foo_encoder_context_t *)self; + IOStream *stream = ctx->m_stream; + ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator; + bool useChecksum = checksumCalculator->getVersion() > 0; + + const unsigned int __size_stuff = (4 * sizeof(float)); + unsigned char *ptr; + unsigned char *buf; + const size_t sizeWithoutChecksum = 8 + __size_stuff + 1*4; + const size_t checksumSize = checksumCalculator->checksumByteSize(); + const size_t totalSize = sizeWithoutChecksum + checksumSize; + buf = stream->alloc(totalSize); + ptr = buf; + int tmp = OP_fooIsBuffer;memcpy(ptr, &tmp, 4); ptr += 4; + memcpy(ptr, &totalSize, 4); ptr += 4; + + *(unsigned int *)(ptr) = __size_stuff; ptr += 4; + memcpy(ptr, stuff, __size_stuff);ptr += __size_stuff; + + if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf); + if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize; + + + FooBoolean retval; + stream->readback(&retval, 1); + if (useChecksum) checksumCalculator->addBuffer(&retval, 1); + if (useChecksum) { + unsigned char *checksumBufPtr = NULL; + unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize]; + if (checksumSize > 0) checksumBufPtr = &checksumBuf[0]; + stream->readback(checksumBufPtr, checksumSize); + if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) { + ALOGE("fooIsBuffer: GL communication error, please report this issue to b.android.com.\n"); + abort(); + } + } + return retval; +} + +void fooDoEncoderFlush_enc(void *self , FooInt param) +{ + + foo_encoder_context_t *ctx = (foo_encoder_context_t *)self; + IOStream *stream = ctx->m_stream; + ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator; + bool useChecksum = checksumCalculator->getVersion() > 0; + + unsigned char *ptr; + unsigned char *buf; + const size_t sizeWithoutChecksum = 8 + 4; + const size_t checksumSize = checksumCalculator->checksumByteSize(); + const size_t totalSize = sizeWithoutChecksum + checksumSize; + buf = stream->alloc(totalSize); + ptr = buf; + int tmp = OP_fooDoEncoderFlush;memcpy(ptr, &tmp, 4); ptr += 4; + memcpy(ptr, &totalSize, 4); ptr += 4; + + memcpy(ptr, ¶m, 4); ptr += 4; + + if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf); + if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize; + + stream->flush(); +} + +void fooTakeConstVoidPtrConstPtr_enc(void *self , const void* const* param) +{ + + foo_encoder_context_t *ctx = (foo_encoder_context_t *)self; + IOStream *stream = ctx->m_stream; + ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator; + bool useChecksum = checksumCalculator->getVersion() > 0; + + const unsigned int __size_param = ; + unsigned char *ptr; + unsigned char *buf; + const size_t sizeWithoutChecksum = 8 + __size_param + 1*4; + const size_t checksumSize = checksumCalculator->checksumByteSize(); + const size_t totalSize = sizeWithoutChecksum + checksumSize; + buf = stream->alloc(totalSize); + ptr = buf; + int tmp = OP_fooTakeConstVoidPtrConstPtr;memcpy(ptr, &tmp, 4); ptr += 4; + memcpy(ptr, &totalSize, 4); ptr += 4; + + *(unsigned int *)(ptr) = __size_param; ptr += 4; + memcpy(ptr, param, __size_param);ptr += __size_param; + + if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf); + if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize; + +} + +void fooSetComplexStruct_enc(void *self , const FooStruct* obj) +{ + + foo_encoder_context_t *ctx = (foo_encoder_context_t *)self; + IOStream *stream = ctx->m_stream; + ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator; + bool useChecksum = checksumCalculator->getVersion() > 0; + + const unsigned int __size_obj = fooStructEncodingSize(obj); + unsigned char *ptr; + unsigned char *buf; + const size_t sizeWithoutChecksum = 8 + __size_obj + 1*4; + const size_t checksumSize = checksumCalculator->checksumByteSize(); + const size_t totalSize = sizeWithoutChecksum + checksumSize; + buf = stream->alloc(totalSize); + ptr = buf; + int tmp = OP_fooSetComplexStruct;memcpy(ptr, &tmp, 4); ptr += 4; + memcpy(ptr, &totalSize, 4); ptr += 4; + + *(unsigned int *)(ptr) = __size_obj; ptr += 4; + fooStructPack(ptr, obj);ptr += __size_obj; + + if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf); + if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize; + +} + +void fooGetComplexStruct_enc(void *self , FooStruct* obj) +{ + + foo_encoder_context_t *ctx = (foo_encoder_context_t *)self; + IOStream *stream = ctx->m_stream; + ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator; + bool useChecksum = checksumCalculator->getVersion() > 0; + + const unsigned int __size_obj = fooStructEncodingSize(obj); + unsigned char *ptr; + unsigned char *buf; + const size_t sizeWithoutChecksum = 8 + 0 + 1*4; + const size_t checksumSize = checksumCalculator->checksumByteSize(); + const size_t totalSize = sizeWithoutChecksum + checksumSize; + buf = stream->alloc(totalSize); + ptr = buf; + int tmp = OP_fooGetComplexStruct;memcpy(ptr, &tmp, 4); ptr += 4; + memcpy(ptr, &totalSize, 4); ptr += 4; + + *(unsigned int *)(ptr) = __size_obj; ptr += 4; + + if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf); + if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize; + + std::vector<unsigned char> forUnpacking_obj(__size_obj); stream->readback(&forUnpacking_obj[0], __size_obj); fooStructUnpack(&forUnpacking_obj[0], obj); + if (useChecksum) checksumCalculator->addBuffer(obj, __size_obj); + if (useChecksum) { + unsigned char *checksumBufPtr = NULL; + unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize]; + if (checksumSize > 0) checksumBufPtr = &checksumBuf[0]; + stream->readback(checksumBufPtr, checksumSize); + if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) { + ALOGE("fooGetComplexStruct: GL communication error, please report this issue to b.android.com.\n"); + abort(); + } + } +} + +void fooInout_enc(void *self , uint32_t* count) +{ + + foo_encoder_context_t *ctx = (foo_encoder_context_t *)self; + IOStream *stream = ctx->m_stream; + ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator; + bool useChecksum = checksumCalculator->getVersion() > 0; + + const unsigned int __size_count = sizeof(uint32_t); + unsigned char *ptr; + unsigned char *buf; + const size_t sizeWithoutChecksum = 8 + __size_count + 1*4; + const size_t checksumSize = checksumCalculator->checksumByteSize(); + const size_t totalSize = sizeWithoutChecksum + checksumSize; + buf = stream->alloc(totalSize); + ptr = buf; + int tmp = OP_fooInout;memcpy(ptr, &tmp, 4); ptr += 4; + memcpy(ptr, &totalSize, 4); ptr += 4; + + *(unsigned int *)(ptr) = __size_count; ptr += 4; + memcpy(ptr, count, __size_count);ptr += __size_count; + + if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf); + if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize; + + stream->readback(count, __size_count); + if (useChecksum) checksumCalculator->addBuffer(count, __size_count); + if (useChecksum) { + unsigned char *checksumBufPtr = NULL; + unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize]; + if (checksumSize > 0) checksumBufPtr = &checksumBuf[0]; + stream->readback(checksumBufPtr, checksumSize); + if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) { + ALOGE("fooInout: GL communication error, please report this issue to b.android.com.\n"); + abort(); + } + } +} + +} // namespace + +foo_encoder_context_t::foo_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator) +{ + m_stream = stream; + m_checksumCalculator = checksumCalculator; + + this->fooAlphaFunc = &fooAlphaFunc_enc; + this->fooIsBuffer = &fooIsBuffer_enc; + this->fooUnsupported = (fooUnsupported_client_proc_t) &enc_unsupported; + this->fooDoEncoderFlush = &fooDoEncoderFlush_enc; + this->fooTakeConstVoidPtrConstPtr = &fooTakeConstVoidPtrConstPtr_enc; + this->fooSetComplexStruct = &fooSetComplexStruct_enc; + this->fooGetComplexStruct = &fooGetComplexStruct_enc; + this->fooInout = &fooInout_enc; +} + diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.h b/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.h new file mode 100644 index 0000000000000000000000000000000000000000..beaabd43ff69fc7949465338a33cb49073f71c35 --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_enc.h @@ -0,0 +1,24 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' + +#ifndef GUARD_foo_encoder_context_t +#define GUARD_foo_encoder_context_t + +#include "IOStream.h" +#include "ChecksumCalculator.h" +#include "foo_client_context.h" + + +#include "fooUtils.h" +#include "fooBase.h" + +struct foo_encoder_context_t : public foo_client_context_t { + + IOStream *m_stream; + ChecksumCalculator *m_checksumCalculator; + + foo_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator); + virtual uint64_t lockAndWriteDma(void* data, uint32_t sz) { return 0; } +}; + +#endif // GUARD_foo_encoder_context_t diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_entry.cpp b/host/commands/emugen/tests/t.001/expected/encoder/foo_entry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92e8ef43a9fa71cc033b6ebd306691fe57ddcbcd --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_entry.cpp @@ -0,0 +1,72 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#include <stdio.h> +#include <stdlib.h> +#include "foo_client_context.h" + +extern "C" { + void fooAlphaFunc(FooInt func, FooFloat ref); + FooBoolean fooIsBuffer(void* stuff); + void fooUnsupported(void* params); + void fooDoEncoderFlush(FooInt param); + void fooTakeConstVoidPtrConstPtr(const void* const* param); + void fooSetComplexStruct(const FooStruct* obj); + void fooGetComplexStruct(FooStruct* obj); + void fooInout(uint32_t* count); +}; + +#ifndef GET_CONTEXT +static foo_client_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL; +void foo_client_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; } +#define GET_CONTEXT foo_client_context_t * ctx = getCurrentContext() +#endif + +void fooAlphaFunc(FooInt func, FooFloat ref) +{ + GET_CONTEXT; + ctx->fooAlphaFunc(ctx, func, ref); +} + +FooBoolean fooIsBuffer(void* stuff) +{ + GET_CONTEXT; + if (n == NULL) { LOG(ERROR) << "NULL stuff"; return; } + return ctx->fooIsBuffer(ctx, stuff); +} + +void fooUnsupported(void* params) +{ + GET_CONTEXT; + ctx->fooUnsupported(ctx, params); +} + +void fooDoEncoderFlush(FooInt param) +{ + GET_CONTEXT; + ctx->fooDoEncoderFlush(ctx, param); +} + +void fooTakeConstVoidPtrConstPtr(const void* const* param) +{ + GET_CONTEXT; + ctx->fooTakeConstVoidPtrConstPtr(ctx, param); +} + +void fooSetComplexStruct(const FooStruct* obj) +{ + GET_CONTEXT; + ctx->fooSetComplexStruct(ctx, obj); +} + +void fooGetComplexStruct(FooStruct* obj) +{ + GET_CONTEXT; + ctx->fooGetComplexStruct(ctx, obj); +} + +void fooInout(uint32_t* count) +{ + GET_CONTEXT; + ctx->fooInout(ctx, count); +} + diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_ftable.h b/host/commands/emugen/tests/t.001/expected/encoder/foo_ftable.h new file mode 100644 index 0000000000000000000000000000000000000000..0b759b52ca2537692870bf2652cabf579f900f71 --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_ftable.h @@ -0,0 +1,23 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#ifndef __foo_client_ftable_t_h +#define __foo_client_ftable_t_h + + +static const struct _foo_funcs_by_name { + const char *name; + void *proc; +} foo_funcs_by_name[] = { + {"fooAlphaFunc", (void*)fooAlphaFunc}, + {"fooIsBuffer", (void*)fooIsBuffer}, + {"fooUnsupported", (void*)fooUnsupported}, + {"fooDoEncoderFlush", (void*)fooDoEncoderFlush}, + {"fooTakeConstVoidPtrConstPtr", (void*)fooTakeConstVoidPtrConstPtr}, + {"fooSetComplexStruct", (void*)fooSetComplexStruct}, + {"fooGetComplexStruct", (void*)fooGetComplexStruct}, + {"fooInout", (void*)fooInout}, +}; +static const int foo_num_funcs = sizeof(foo_funcs_by_name) / sizeof(struct _foo_funcs_by_name); + + +#endif diff --git a/host/commands/emugen/tests/t.001/expected/encoder/foo_opcodes.h b/host/commands/emugen/tests/t.001/expected/encoder/foo_opcodes.h new file mode 100644 index 0000000000000000000000000000000000000000..ee453406f4e144dd9a1e74ec60ad1e22755fbb3e --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/encoder/foo_opcodes.h @@ -0,0 +1,17 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#ifndef __GUARD_foo_opcodes_h_ +#define __GUARD_foo_opcodes_h_ + +#define OP_fooAlphaFunc 200 +#define OP_fooIsBuffer 201 +#define OP_fooUnsupported 202 +#define OP_fooDoEncoderFlush 203 +#define OP_fooTakeConstVoidPtrConstPtr 204 +#define OP_fooSetComplexStruct 205 +#define OP_fooGetComplexStruct 206 +#define OP_fooInout 207 +#define OP_last 208 + + +#endif diff --git a/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.cpp b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8781cccb15d340a59e7ef00dcb468f860b53429 --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.cpp @@ -0,0 +1,23 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' + + +#include <string.h> +#include "foo_wrapper_context.h" + + +#include <stdio.h> + +int foo_wrapper_context_t::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData) +{ + fooAlphaFunc = (fooAlphaFunc_wrapper_proc_t) getProc("fooAlphaFunc", userData); + fooIsBuffer = (fooIsBuffer_wrapper_proc_t) getProc("fooIsBuffer", userData); + fooUnsupported = (fooUnsupported_wrapper_proc_t) getProc("fooUnsupported", userData); + fooDoEncoderFlush = (fooDoEncoderFlush_wrapper_proc_t) getProc("fooDoEncoderFlush", userData); + fooTakeConstVoidPtrConstPtr = (fooTakeConstVoidPtrConstPtr_wrapper_proc_t) getProc("fooTakeConstVoidPtrConstPtr", userData); + fooSetComplexStruct = (fooSetComplexStruct_wrapper_proc_t) getProc("fooSetComplexStruct", userData); + fooGetComplexStruct = (fooGetComplexStruct_wrapper_proc_t) getProc("fooGetComplexStruct", userData); + fooInout = (fooInout_wrapper_proc_t) getProc("fooInout", userData); + return 0; +} + diff --git a/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.h b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.h new file mode 100644 index 0000000000000000000000000000000000000000..c9853d29820135c47a21fc60b14d98bf9b0d4491 --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_context.h @@ -0,0 +1,28 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#ifndef __foo_wrapper_context_t_h +#define __foo_wrapper_context_t_h + +#include "foo_server_proc.h" + +#include "foo_types.h" + + +struct foo_wrapper_context_t { + + fooAlphaFunc_wrapper_proc_t fooAlphaFunc; + fooIsBuffer_wrapper_proc_t fooIsBuffer; + fooUnsupported_wrapper_proc_t fooUnsupported; + fooDoEncoderFlush_wrapper_proc_t fooDoEncoderFlush; + fooTakeConstVoidPtrConstPtr_wrapper_proc_t fooTakeConstVoidPtrConstPtr; + fooSetComplexStruct_wrapper_proc_t fooSetComplexStruct; + fooGetComplexStruct_wrapper_proc_t fooGetComplexStruct; + fooInout_wrapper_proc_t fooInout; + virtual ~foo_wrapper_context_t() {} + + typedef foo_wrapper_context_t *CONTEXT_ACCESSOR_TYPE(void); + static void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f); + int initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData); +}; + +#endif diff --git a/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_entry.cpp b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_entry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..733c8248d1e2f39b4f83803adc66db9fc9bf194f --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_entry.cpp @@ -0,0 +1,71 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#include <stdio.h> +#include <stdlib.h> +#include "foo_wrapper_context.h" + +extern "C" { + void fooAlphaFunc(FooInt func, FooFloat ref); + FooBoolean fooIsBuffer(void* stuff); + void fooUnsupported(void* params); + void fooDoEncoderFlush(FooInt param); + void fooTakeConstVoidPtrConstPtr(const void* const* param); + void fooSetComplexStruct(const FooStruct* obj); + void fooGetComplexStruct(FooStruct* obj); + void fooInout(uint32_t* count); +}; + +#ifndef GET_CONTEXT +static foo_wrapper_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL; +void foo_wrapper_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; } +#define GET_CONTEXT foo_wrapper_context_t * ctx = getCurrentContext() +#endif + +void fooAlphaFunc(FooInt func, FooFloat ref) +{ + GET_CONTEXT; + ctx->fooAlphaFunc( func, ref); +} + +FooBoolean fooIsBuffer(void* stuff) +{ + GET_CONTEXT; + return ctx->fooIsBuffer( stuff); +} + +void fooUnsupported(void* params) +{ + GET_CONTEXT; + ctx->fooUnsupported( params); +} + +void fooDoEncoderFlush(FooInt param) +{ + GET_CONTEXT; + ctx->fooDoEncoderFlush( param); +} + +void fooTakeConstVoidPtrConstPtr(const void* const* param) +{ + GET_CONTEXT; + ctx->fooTakeConstVoidPtrConstPtr( param); +} + +void fooSetComplexStruct(const FooStruct* obj) +{ + GET_CONTEXT; + ctx->fooSetComplexStruct( obj); +} + +void fooGetComplexStruct(FooStruct* obj) +{ + GET_CONTEXT; + ctx->fooGetComplexStruct( obj); +} + +void fooInout(uint32_t* count) +{ + GET_CONTEXT; + ctx->fooInout( count); +} + diff --git a/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_proc.h b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_proc.h new file mode 100644 index 0000000000000000000000000000000000000000..66ced3138818e131ac8abfede4ddd417ad5cf7f4 --- /dev/null +++ b/host/commands/emugen/tests/t.001/expected/wrapper/foo_wrapper_proc.h @@ -0,0 +1,22 @@ +// Generated Code - DO NOT EDIT !! +// generated by 'emugen' +#ifndef __foo_wrapper_proc_t_h +#define __foo_wrapper_proc_t_h + + + +#include "foo_types.h" +#ifndef foo_APIENTRY +#define foo_APIENTRY +#endif +typedef void (foo_APIENTRY *fooAlphaFunc_wrapper_proc_t) (FooInt, FooFloat); +typedef FooBoolean (foo_APIENTRY *fooIsBuffer_wrapper_proc_t) (void*); +typedef void (foo_APIENTRY *fooUnsupported_wrapper_proc_t) (void*); +typedef void (foo_APIENTRY *fooDoEncoderFlush_wrapper_proc_t) (FooInt); +typedef void (foo_APIENTRY *fooTakeConstVoidPtrConstPtr_wrapper_proc_t) (const void* const*); +typedef void (foo_APIENTRY *fooSetComplexStruct_wrapper_proc_t) (const FooStruct*); +typedef void (foo_APIENTRY *fooGetComplexStruct_wrapper_proc_t) (FooStruct*); +typedef void (foo_APIENTRY *fooInout_wrapper_proc_t) (uint32_t*); + + +#endif diff --git a/host/commands/emugen/tests/t.001/input/foo.attrib b/host/commands/emugen/tests/t.001/input/foo.attrib new file mode 100644 index 0000000000000000000000000000000000000000..9b66c57966f004ecd926241cd6e47a574c3e5c15 --- /dev/null +++ b/host/commands/emugen/tests/t.001/input/foo.attrib @@ -0,0 +1,32 @@ +GLOBAL + base_opcode 200 + encoder_headers "fooUtils.h" "fooBase.h" + +fooIsBuffer + dir stuff in + len stuff (4 * sizeof(float)) + param_check stuff if (n == NULL) { LOG(ERROR) << "NULL stuff"; return; } + +fooUnsupported + dir params in + flag unsupported + +fooDoEncoderFlush + flag flushOnEncode + +fooSetComplexStruct + dir obj in + len obj fooStructEncodingSize(obj) + custom_pack obj fooStructPack(ptr, obj) + custom_unpack obj FooStruct unpacked; inptr_obj_unpacked = (void*)(&unpacked); fooStructUnpack((unsigned char*)(inptr_obj.get()), size_obj, inptr_obj_unpacked) + +fooGetComplexStruct + dir obj out + len obj fooStructEncodingSize(obj) + custom_host_pack_tmp_alloc obj FooStruct tmp; forPacking_obj = (void*)tmp + custom_host_pack obj fooStructPack((unsigned char*)outptr_obj.get(), (FooStruct*)forPacking_obj) + custom_guest_unpack obj std::vector<unsigned char> forUnpacking_obj(__size_obj); stream->readback(&forUnpacking_obj[0], __size_obj); fooStructUnpack(&forUnpacking_obj[0], obj) + +fooInout + dir count inout + len count sizeof(uint32_t) diff --git a/host/commands/emugen/tests/t.001/input/foo.in b/host/commands/emugen/tests/t.001/input/foo.in new file mode 100644 index 0000000000000000000000000000000000000000..b12ad99f9f79ec418c9a193d7cec791f263d21b3 --- /dev/null +++ b/host/commands/emugen/tests/t.001/input/foo.in @@ -0,0 +1,8 @@ +FOO_ENTRY(void, fooAlphaFunc, FooInt func, FooFloat ref) +FOO_ENTRY(FooBoolean, fooIsBuffer, void* stuff) +FOO_ENTRY(void, fooUnsupported, void* params) +FOO_ENTRY(void, fooDoEncoderFlush, FooInt param) +FOO_ENTRY(void, fooTakeConstVoidPtrConstPtr, const void* const* param) +FOO_ENTRY(void, fooSetComplexStruct, const FooStruct* obj) +FOO_ENTRY(void, fooGetComplexStruct, FooStruct* obj) +FOO_ENTRY(void, fooInout, uint32_t* count) diff --git a/host/commands/emugen/tests/t.001/input/foo.types b/host/commands/emugen/tests/t.001/input/foo.types new file mode 100644 index 0000000000000000000000000000000000000000..45e17c913de241fe952dc890ff6d87204fcba8ff --- /dev/null +++ b/host/commands/emugen/tests/t.001/input/foo.types @@ -0,0 +1,12 @@ +FooBoolean 8 %d +FooInt 32 %d +FooShort 16 %d +FooFloat 32 %f +FooEnum 32 %08x +FooVoid 0 %x +FooChar 8 %d +FooChar* 32 0x%08x +void* 32 0x%08x +void*const* 32 0x%08x +FooStruct* 32 0x%08x +uint32_t* 32 0x%08x diff --git a/host/commands/gen_entries.py b/host/commands/gen_entries.py new file mode 100755 index 0000000000000000000000000000000000000000..fbfdb4dafbb7b297f36075118b08929cf299fda9 --- /dev/null +++ b/host/commands/gen_entries.py @@ -0,0 +1,317 @@ +#!/usr/bin/env python + +# Copyright 2015 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Utility functions used to parse a list of DLL entry points. +# Expected format: +# +# <empty-line> -> ignored +# #<comment> -> ignored +# %<verbatim> -> verbatim output for header files. +# !<prefix> -> prefix name for header files. +# <return-type> <function-name> <signature> ; -> entry point declaration. +# +# Anything else is an error. + +import re +import sys +import argparse + +re_func = re.compile(r"""^(.*[\* ])([A-Za-z_][A-Za-z0-9_]*)\((.*)\);$""") +re_param = re.compile(r"""^(.*[\* ])([A-Za-z_][A-Za-z0-9_]*)$""") + +class Entry: + """Small class used to model a single DLL entry point.""" + def __init__(self, func_name, return_type, parameters): + """Initialize Entry instance. |func_name| is the function name, + |return_type| its return type, and |parameters| is a list of + (type,name) tuples from the entry's signature. + """ + self.func_name = func_name + self.return_type = return_type + self.parameters = "" + self.vartypes = [] + self.varnames = [] + self.call = "" + comma = "" + for param in parameters: + self.vartypes.append(param[0]) + self.varnames.append(param[1]) + self.parameters += "%s%s %s" % (comma, param[0], param[1]) + self.call += "%s%s" % (comma, param[1]) + comma = ", " + +def banner_command(argv): + """Return sanitized command-line description. + |argv| must be a list of command-line parameters, e.g. sys.argv. + Return a string corresponding to the command, with platform-specific + paths removed.""" + + # Remove path from first parameter + argv = argv[:] + argv[0] = "host/commands/gen-entries.py" + return ' '.join(argv) + +def parse_entries_file(lines): + """Parse an .entries file and return a tuple of: + entries: list of Entry instances from the file. + prefix_name: prefix name from the file, or None. + verbatim: list of verbatim lines from the file. + errors: list of errors in the file, prefixed by line number. + """ + entries = [] + verbatim = [] + errors = [] + lineno = 0 + prefix_name = None + for line in lines: + lineno += 1 + line = line.strip() + if len(line) == 0: # Ignore empty lines + continue + if line[0] == '#': # Ignore comments + continue + if line[0] == '!': # Prefix name + prefix_name = line[1:] + continue + if line[0] == '%': # Verbatim line copy + verbatim.append(line[1:]) + continue + # Must be a function signature. + m = re_func.match(line) + if not m: + errors.append("%d: '%s'" % (lineno, line)) + continue + + return_type, func_name, parameters = m.groups() + return_type = return_type.strip() + parameters = parameters.strip() + params = [] + failure = False + if parameters != "void": + for parameter in parameters.split(','): + parameter = parameter.strip() + m = re_param.match(parameter) + if not m: + errors.append("%d: parameter '%s'" % (lineno, parameter)) + failure = True + break + else: + param_type, param_name = m.groups() + params.append((param_type.strip(), param_name.strip())) + + if not failure: + entries.append(Entry(func_name, return_type, params)) + + return (entries, prefix_name, verbatim, errors) + + +def gen_functions_header(entries, prefix_name, verbatim, filename, with_args): + """Generate a C header containing a macro listing all entry points. + |entries| is a list of Entry instances. + |prefix_name| is a prefix-name, it will be converted to upper-case. + |verbatim| is a list of verbatim lines that must appear before the + macro declaration. Useful to insert #include <> statements. + |filename| is the name of the original file. + """ + prefix_name = prefix_name.upper() + + print "// Auto-generated with: %s" % banner_command(sys.argv) + print "// DO NOT EDIT THIS FILE" + print "" + print "#ifndef %s_FUNCTIONS_H" % prefix_name + print "#define %s_FUNCTIONS_H" % prefix_name + print "" + for line in verbatim: + print line + + print "#define LIST_%s_FUNCTIONS(X) \\" % prefix_name + for entry in entries: + if with_args: + print " X(%s, %s, (%s), (%s)) \\" % \ + (entry.return_type, entry.func_name, entry.parameters, + entry.call) + else: + print " X(%s, %s, (%s)) \\" % \ + (entry.return_type, entry.func_name, entry.parameters) + + print "" + print "" + print "#endif // %s_FUNCTIONS_H" % prefix_name + +def gen_dll_wrapper(entries, prefix_name, verbatim, filename): + """Generate a C source file that contains functions that act as wrappers + for entry points located in another shared library. This allows the + code that calls these functions to perform lazy-linking to system + libraries. + |entries|, |prefix_name|, |verbatim| and |filename| are the same as + for gen_functions_header() above. + """ + upper_name = prefix_name.upper() + + ENTRY_PREFIX = "__dll_" + + print "// Auto-generated with: %s" % banner_command(sys.argv) + print "// DO NOT EDIT THIS FILE" + print "" + print "#include <dlfcn.h>" + for line in verbatim: + print line + + print "" + print "///" + print "/// W R A P P E R P O I N T E R S" + print "///" + print "" + for entry in entries: + ptr_name = ENTRY_PREFIX + entry.func_name + print "static %s (*%s)(%s) = 0;" % \ + (entry.return_type, ptr_name, entry.parameters) + + print "" + print "///" + print "/// W R A P P E R F U N C T I O N S" + print "///" + print "" + + for entry in entries: + print "%s %s(%s) {" % \ + (entry.return_type, entry.func_name, entry.parameters) + ptr_name = ENTRY_PREFIX + entry.func_name + if entry.return_type != "void": + print " return %s(%s);" % (ptr_name, entry.call) + else: + print " %s(%s);" % (ptr_name, entry.call) + print "}\n" + + print "" + print "///" + print "/// I N I T I A L I Z A T I O N F U N C T I O N" + print "///" + print "" + + print "int %s_dynlink_init(void* lib) {" % prefix_name + for entry in entries: + ptr_name = ENTRY_PREFIX + entry.func_name + print " %s = (%s(*)(%s))dlsym(lib, \"%s\");" % \ + (ptr_name, + entry.return_type, + entry.parameters, + entry.func_name) + print " if (!%s) return -1;" % ptr_name + print " return 0;" + print "}" + + +def gen_windows_def_file(entries): + """Generate a windows DLL .def file. |entries| is a list of Entry instances. + """ + print "EXPORTS" + for entry in entries: + print " %s" % entry.func_name + + +def gen_unix_sym_file(entries): + """Generate an ELF linker version file. |entries| is a list of Entry + instances. + """ + print "VERSION {" + print "\tglobal:" + for entry in entries: + print "\t\t%s;" % entry.func_name + print "\tlocal:" + print "\t\t*;" + print "};" + +def gen_symbols(entries, underscore): + """Generate a list of symbols from |entries|, a list of Entry instances. + |underscore| is a boolean. If True, then prepend an underscore to each + symbol name. + """ + prefix = "" + if underscore: + prefix = "_" + for entry in entries: + print "%s%s" % (prefix, entry.func_name) + +def parse_file(filename, lines, mode): + """Generate one of possible outputs from |filename|. |lines| must be a list + of text lines from the file, and |mode| is one of the --mode option + values. + """ + entries, prefix_name, verbatim, errors = parse_entries_file(lines) + if errors: + for error in errors: + print >> sys.stderr, "ERROR: %s:%s" % (filename, error) + sys.exit(1) + + if not prefix_name: + prefix_name = "unknown" + + if mode == 'def': + gen_windows_def_file(entries) + elif mode == 'sym': + gen_unix_sym_file(entries) + elif mode == 'wrapper': + gen_dll_wrapper(entries, prefix_name, verbatim, filename) + elif mode == 'symbols': + gen_symbols(entries, False) + elif mode == '_symbols': + gen_symbols(entries, True) + elif mode == 'functions': + gen_functions_header(entries, prefix_name, verbatim, filename, False) + elif mode == 'funcargs': + gen_functions_header(entries, prefix_name, verbatim, filename, True) + + +# List of valid --mode option values. +mode_list = [ + 'def', 'sym', 'wrapper', 'symbols', '_symbols', 'functions', 'funcargs' +] + +# Argument parsing. +parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""\ +A script used to parse an .entries input file containing a list of function +declarations, and generate various output files depending on the value of +the --mode option, which can be: + + def Generate a windows DLL .def file. + sym Generate a Unix .so linker script. + wrapper Generate a C source file containing wrapper functions. + symbols Generate a simple list of symbols, one per line. + _symbols Generate a simple list of symbols, prefixed with _. + functions Generate a C header containing a macro listing all functions. + funcargs Like 'functions', but adds function call arguments to listing. + +""") +parser.add_argument("--mode", help="Output mode", choices=mode_list) +parser.add_argument("--output", help="output file") +parser.add_argument("file", help=".entries file path") + +args = parser.parse_args() + +if not args.mode: + print >> sys.stderr, "ERROR: Please use --mode=<name>, see --help." + sys.exit(1) + +if args.output: + sys.stdout = open(args.output, "w+") + +if args.file == '--': + parse_file("<stdin>", sys.stdin, args.mode) +else: + parse_file(args.file, open(args.file), args.mode) diff --git a/host/libs/Android.bp b/host/libs/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..65e458da7963ca1b0d701c7f070788cb89a382a5 --- /dev/null +++ b/host/libs/Android.bp @@ -0,0 +1,18 @@ +// +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +subdirs = [ + "virglrenderer", +] diff --git a/host/libs/virglrenderer/.clang-format b/host/libs/virglrenderer/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..4b84118833995dbfbcc71f82f50b8d8809ac2833 --- /dev/null +++ b/host/libs/virglrenderer/.clang-format @@ -0,0 +1,17 @@ +BasedOnStyle: Google +AccessModifierOffset: -2 +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ColumnLimit: 100 +CommentPragmas: NOLINT:.* +Cpp11BracedListStyle: false +DerivePointerAlignment: false +IndentWidth: 4 +PointerAlignment: Left +TabWidth: 4 +UseTab: Never +PenaltyExcessCharacter: 32 diff --git a/host/libs/virglrenderer/.gitignore b/host/libs/virglrenderer/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..562939a074129f1af8922a855f471d2f913e1ecc --- /dev/null +++ b/host/libs/virglrenderer/.gitignore @@ -0,0 +1,3 @@ +renderControl_dec/renderControl_server_context.cpp +GLESv1_dec/gles1_server_context.cpp +GLESv3_dec/gles3_server_context.cpp diff --git a/host/libs/virglrenderer/AVDVirglRenderer.cpp b/host/libs/virglrenderer/AVDVirglRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..973e14442ee1da262a82e3694ba670746fd8a7a2 --- /dev/null +++ b/host/libs/virglrenderer/AVDVirglRenderer.cpp @@ -0,0 +1,1100 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#undef NDEBUG + +extern "C" { +#include <linux/virtio_gpu.h> +#include <virglrenderer.h> +#include <virgl_hw.h> +} + +#include <sys/uio.h> + +#include <dlfcn.h> +#include <algorithm> +#include <cassert> +#include <cerrno> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <deque> +#include <map> +#include <mutex> +#include <string> +#include <vector> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES3/gl31.h> +#include <GLES3/gl3ext.h> + +#include <drm/drm_fourcc.h> + +#include <OpenGLESDispatch/EGLDispatch.h> +#include <OpenGLESDispatch/GLESv1Dispatch.h> +#include <OpenGLESDispatch/GLESv3Dispatch.h> + +#include "OpenglRender/IOStream.h" + +#include "Context.h" +#include "EglConfig.h" +#include "EglContext.h" +#include "EglSurface.h" +#include "EglSync.h" +#include "Resource.h" + +#include <VirtioGpuCmd.h> + +// for debug only +#include <sys/syscall.h> +#include <unistd.h> +#define gettid() (int)syscall(__NR_gettid) + +#ifndef PAGE_SIZE +#define PAGE_SIZE 0x1000 +#endif + +#define MAX_CMDRESPBUF_SIZE (10 * PAGE_SIZE) + +#define ALIGN(A, B) (((A) + (B)-1) / (B) * (B)) + +// Enable passing scanout buffers as texture names to sdl2 backend +#define QEMU_HARDWARE_GL_INTEROP + +#ifdef QEMU_HARDWARE_GL_INTEROP +typedef GLenum (*PFNGLGETERROR)(void); +typedef void (*PFNGLBINDTEXTURE)(GLenum target, GLuint texture); +typedef void (*PFNGLGENTEXTURES)(GLsizei n, GLuint* textures); +typedef void (*PFNGLTEXPARAMETERI)(GLenum target, GLenum pname, GLint param); +typedef void (*PFNGLPIXELSTOREI)(GLenum pname, GLint param); +typedef void (*PFNGLTEXIMAGE2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, + GLsizei height, GLint border, GLenum format, GLenum type, + const void* pixels); +static PFNGLBINDTEXTURE g_glBindTexture; +static PFNGLGENTEXTURES g_glGenTextures; +static PFNGLTEXPARAMETERI g_glTexParameteri; +static PFNGLPIXELSTOREI g_glPixelStorei; +static PFNGLTEXIMAGE2D g_glTexImage2D; +static virgl_renderer_gl_context g_ctx0_alt; +#endif + +// Global state +std::map<uint32_t, EglContext*> EglContext::map; +std::map<uint32_t, EglSurface*> EglSurface::map; +std::map<uint32_t, EglImage*> EglImage::map; +std::map<uint32_t, Resource*> Resource::map; +std::map<uint64_t, EglSync*> EglSync::map; +std::map<uint32_t, Context*> Context::map; +std::vector<EglConfig*> EglConfig::vec; +static virgl_renderer_callbacks* g_cb; +const EGLint EglConfig::kAttribs[]; +uint32_t EglContext::nextId = 1U; +uint32_t EglSurface::nextId = 1U; +uint32_t EglImage::nextId = 1U; +uint64_t EglSync::nextId = 1U; +static void* g_cookie; + +// Fence queue, must be thread safe +static std::mutex g_fence_deque_mutex; +static std::deque<int> g_fence_deque; + +// Other GPU context and state +static EGLSurface g_ctx0_surface; +static EGLContext g_ctx0_es1; +static EGLContext g_ctx0_es2; +static EGLDisplay g_dpy; + +// Last context receiving a command. Allows us to find the context a fence is +// being created for. Works around the poorly designed virgl interface. +static Context* g_last_submit_cmd_ctx; + +#ifdef OPENGL_DEBUG_PRINTOUT + +#include "emugl/common/logging.h" + +// For logging from the protocol decoders + +void default_logger(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +emugl_logger_t emugl_cxt_logger = default_logger; + +#endif + +static void dump_global_state(void) { + printf("AVDVIRGLRENDERER GLOBAL STATE\n\n"); + + printf("Resources:\n"); + for (auto const& it : Resource::map) { + Resource const* res = it.second; + + printf( + " Resource %u: %ux%u 0x%x %p (%zub) t=%u b=%u d=%u a=%u l=%u " + "n=%u f=%u\n", + res->args.handle, res->args.width, res->args.height, res->args.format, + res->iov ? res->iov[0].iov_base : nullptr, res->iov ? res->iov[0].iov_len : 0, + res->args.target, res->args.bind, res->args.depth, res->args.array_size, + res->args.last_level, res->args.nr_samples, res->args.flags); + + for (auto const& it : res->context_map) { + Context const* ctx = it.second; + + printf(" Context %u, pid=%d, tid=%d\n", ctx->handle, ctx->pid, ctx->tid); + } + } + + printf("Contexts:\n"); + for (auto const& it : Context::map) { + Context const* ctx = it.second; + + printf(" Context %u: %s pid=%u tid=%u\n", ctx->handle, ctx->name.c_str(), ctx->pid, + ctx->tid); + + for (auto const& it : ctx->resource_map) { + Resource const* res = it.second; + + printf(" Resource %u\n", res->args.handle); + } + } +} + +static int sync_linear_to_iovec(Resource* res, uint64_t offset, const virgl_box* box) { + uint32_t bpp; + switch (res->args.format) { + case VIRGL_FORMAT_R8_UNORM: + bpp = 1U; + break; + case VIRGL_FORMAT_B5G6R5_UNORM: + bpp = 2U; + break; + default: + bpp = 4U; + break; + } + + if (box->x > res->args.width || box->y > res->args.height) + return 0; + if (box->w == 0U || box->h == 0U) + return 0; + uint32_t w = std::min(box->w, res->args.width - box->x); + uint32_t h = std::min(box->h, res->args.height - box->y); + uint32_t stride = ALIGN(res->args.width * bpp, 16U); + offset += box->y * stride + box->x * bpp; + size_t length = (h - 1U) * stride + w * bpp; + if (offset + length > res->linearSize) + return EINVAL; + + if (res->num_iovs > 1) { + const char* linear = static_cast<const char*>(res->linear); + for (uint32_t i = 0, iovOffset = 0U; length && i < res->num_iovs; i++) { + if (iovOffset + res->iov[i].iov_len > offset) { + char* iov_base = static_cast<char*>(res->iov[i].iov_base); + size_t copyLength = std::min(length, res->iov[i].iov_len); + memcpy(iov_base + offset - iovOffset, linear, copyLength); + linear += copyLength; + offset += copyLength; + length -= copyLength; + } + iovOffset += res->iov[i].iov_len; + } + } + + return 0; +} + +static int sync_iovec_to_linear(Resource* res, uint64_t offset, const virgl_box* box) { + uint32_t bpp; + switch (res->args.format) { + case VIRGL_FORMAT_R8_UNORM: + bpp = 1U; + break; + case VIRGL_FORMAT_B5G6R5_UNORM: + bpp = 2U; + break; + default: + bpp = 4U; + break; + } + + if (box->x > res->args.width || box->y > res->args.height) + return 0; + if (box->w == 0U || box->h == 0U) + return 0; + uint32_t w = std::min(box->w, res->args.width - box->x); + uint32_t h = std::min(box->h, res->args.height - box->y); + uint32_t stride = ALIGN(res->args.width * bpp, 16U); + offset += box->y * stride + box->x * bpp; + size_t length = (h - 1U) * stride + w * bpp; + if (offset + length > res->linearSize) + return EINVAL; + + if (res->num_iovs > 1) { + char* linear = static_cast<char*>(res->linear); + for (uint32_t i = 0, iovOffset = 0U; length && i < res->num_iovs; i++) { + if (iovOffset + res->iov[i].iov_len > offset) { + const char* iov_base = static_cast<const char*>(res->iov[i].iov_base); + size_t copyLength = std::min(length, res->iov[i].iov_len); + memcpy(linear, iov_base + offset - iovOffset, copyLength); + linear += copyLength; + offset += copyLength; + length -= copyLength; + } + iovOffset += res->iov[i].iov_len; + } + } + + return 0; +} + +// The below API was defined by virglrenderer 'master', but does not seem to +// be used by QEMU, so just ignore it for now.. +// +// virgl_renderer_get_rect +// virgl_renderer_get_fd_for_texture +// virgl_renderer_cleanup +// virgl_renderer_reset +// virgl_renderer_get_poll_fd + +int virgl_renderer_init(void* cookie, int flags, virgl_renderer_callbacks* cb) { + if (!cookie || !cb) + return EINVAL; + + if (flags != 0) + return ENOSYS; + + if (cb->version != 1) + return ENOSYS; + +#ifdef QEMU_HARDWARE_GL_INTEROP + // FIXME: If we just use "libGL.so" here, mesa's interception library returns + // stub dlsyms that do nothing at runtime, even after binding.. + void* handle = dlopen( + "/usr/lib/x86_64-linux-gnu/nvidia/" + "current/libGL.so.384.111", + RTLD_NOW); + assert(handle != nullptr); + g_glBindTexture = (PFNGLBINDTEXTURE)dlsym(handle, "glBindTexture"); + assert(g_glBindTexture != nullptr); + g_glGenTextures = (PFNGLGENTEXTURES)dlsym(handle, "glGenTextures"); + assert(g_glGenTextures != nullptr); + g_glTexParameteri = (PFNGLTEXPARAMETERI)dlsym(handle, "glTexParameteri"); + assert(g_glTexParameteri != nullptr); + g_glPixelStorei = (PFNGLPIXELSTOREI)dlsym(handle, "glPixelStorei"); + assert(g_glPixelStorei != nullptr); + g_glTexImage2D = (PFNGLTEXIMAGE2D)dlsym(handle, "glTexImage2D"); + assert(g_glTexImage2D != nullptr); +#endif + + if (!egl_dispatch_init()) + return ENOENT; + + if (!gles1_dispatch_init()) + return ENOENT; + + if (!gles3_dispatch_init()) + return ENOENT; + + g_dpy = s_egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (g_dpy == EGL_NO_DISPLAY) { + printf("Failed to open default EGL display\n"); + return ENOENT; + } + + if (!s_egl.eglInitialize(g_dpy, nullptr, nullptr)) { + printf("Failed to initialize EGL display\n"); + g_dpy = EGL_NO_DISPLAY; + return ENOENT; + } + + EGLint nConfigs; + if (!s_egl.eglGetConfigs(g_dpy, nullptr, 0, &nConfigs)) { + printf("Failed to retrieve number of EGL configs\n"); + s_egl.eglTerminate(g_dpy); + g_dpy = EGL_NO_DISPLAY; + return ENOENT; + } + + EGLConfig configs[nConfigs]; + if (!s_egl.eglGetConfigs(g_dpy, configs, nConfigs, &nConfigs)) { + printf("Failed to retrieve EGL configs\n"); + s_egl.eglTerminate(g_dpy); + g_dpy = EGL_NO_DISPLAY; + return ENOENT; + } + + // Our static analyzer sees the `new`ing of `config` below without any sort + // of attempt to free it, and warns about it. Normally, it would catch that + // we're pushing it into a vector in the constructor, but it hits an + // internal evaluation limit when trying to evaluate the loop inside of the + // ctor. So, it never gets to see that we escape our newly-allocated + // `config` instance. Silence the warning, since it's incorrect. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) + for (EGLint c = 0; c < nConfigs; c++) { + EGLint configId; + if (!s_egl.eglGetConfigAttrib(g_dpy, configs[c], EGL_CONFIG_ID, &configId)) { + printf("Failed to retrieve EGL config ID\n"); + s_egl.eglTerminate(g_dpy); + g_dpy = EGL_NO_DISPLAY; + return ENOENT; + } + EglConfig* config = + new (std::nothrow) EglConfig(g_dpy, configs[c], s_egl.eglGetConfigAttrib); + if (!config) + return ENOMEM; + } + + // clang-format off + EGLint const attrib_list[] = { + EGL_CONFORMANT, EGL_OPENGL_ES_BIT | EGL_OPENGL_ES3_BIT_KHR, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_NONE, + }; + // clang-format on + EGLint num_config = 0; + EGLConfig config; + if (!s_egl.eglChooseConfig(g_dpy, attrib_list, &config, 1, &num_config) || num_config != 1) { + printf("Failed to select ES1 & ES3 capable EGL config\n"); + s_egl.eglTerminate(g_dpy); + g_dpy = EGL_NO_DISPLAY; + return ENOENT; + } + + // clang-format off + EGLint const pbuffer_attrib_list[] = { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_NONE + }; + // clang-format on + g_ctx0_surface = s_egl.eglCreatePbufferSurface(g_dpy, config, pbuffer_attrib_list); + if (!g_ctx0_surface) { + printf("Failed to create pbuffer surface for context 0\n"); + s_egl.eglTerminate(g_dpy); + g_dpy = EGL_NO_DISPLAY; + return ENOENT; + } + + // clang-format off + EGLint const es1_attrib_list[] = { + EGL_CONTEXT_CLIENT_VERSION, 1, + EGL_NONE + }; + // clang-format on + g_ctx0_es1 = s_egl.eglCreateContext(g_dpy, config, EGL_NO_CONTEXT, es1_attrib_list); + if (g_ctx0_es1 == EGL_NO_CONTEXT) { + printf("Failed to create ES1 context 0\n"); + s_egl.eglDestroySurface(g_dpy, g_ctx0_surface); + s_egl.eglTerminate(g_dpy); + g_dpy = EGL_NO_DISPLAY; + return ENOENT; + } + + // clang-format off + EGLint const es2_attrib_list[] = { + EGL_CONTEXT_CLIENT_VERSION, 3, // yes, 3 + EGL_NONE + }; + // clang-format on + g_ctx0_es2 = s_egl.eglCreateContext(g_dpy, config, EGL_NO_CONTEXT, es2_attrib_list); + if (g_ctx0_es2 == EGL_NO_CONTEXT) { + printf("Failed to create ES2 context 0\n"); + s_egl.eglDestroySurface(g_dpy, g_ctx0_surface); + s_egl.eglDestroyContext(g_dpy, g_ctx0_es1); + g_ctx0_es1 = EGL_NO_CONTEXT; + s_egl.eglTerminate(g_dpy); + g_dpy = EGL_NO_DISPLAY; + } + +#ifdef QEMU_HARDWARE_GL_INTEROP + // This is the hardware GPU context. In future, this code should probably + // be removed and SwiftShader be used for all presentation blits. + virgl_renderer_gl_ctx_param ctx_params = { + .major_ver = 3, + .minor_ver = 0, + }; + g_ctx0_alt = cb->create_gl_context(cookie, 0, &ctx_params); + if (!g_ctx0_alt) { + printf("Failed to create hardware GL context 0\n"); + s_egl.eglDestroySurface(g_dpy, g_ctx0_surface); + s_egl.eglDestroyContext(g_dpy, g_ctx0_es1); + g_ctx0_es1 = EGL_NO_CONTEXT; + s_egl.eglTerminate(g_dpy); + g_dpy = EGL_NO_DISPLAY; + } + + // Test we can actually make it current; otherwise, bail + if (cb->make_current(cookie, 0, g_ctx0_alt)) { + printf("Failed to make hardware GL context 0 current\n"); + cb->destroy_gl_context(cookie, g_ctx0_alt); + g_ctx0_alt = nullptr; + s_egl.eglDestroySurface(g_dpy, g_ctx0_surface); + s_egl.eglDestroyContext(g_dpy, g_ctx0_es1); + g_ctx0_es1 = EGL_NO_CONTEXT; + s_egl.eglTerminate(g_dpy); + g_dpy = EGL_NO_DISPLAY; + } +#endif + + EglContext::nextId = 1U; + g_cookie = cookie; + g_cb = cb; + return 0; +} + +void virgl_renderer_poll(void) { + std::lock_guard<std::mutex> lk(g_fence_deque_mutex); + for (auto fence : g_fence_deque) + g_cb->write_fence(g_cookie, fence); + g_fence_deque.clear(); +} + +void* virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t* width, uint32_t* height) { + if (!width || !height) + return nullptr; + + std::map<uint32_t, Resource*>::iterator it; + it = Resource::map.find(resource_id); + if (it == Resource::map.end()) + return nullptr; + + Resource* res = it->second; + if (res->args.bind != VIRGL_RES_BIND_CURSOR) + return nullptr; + + void* pixels = malloc(res->linearSize); + memcpy(pixels, res->linear, res->linearSize); + *height = res->args.height; + *width = res->args.width; + return pixels; +} + +// NOTE: This function is called from thread context. Do not touch anything +// without a mutex to protect it from concurrent access. Everything else in +// libvirglrenderer is designed to be single-threaded *only*. + +// Hack to serialize all calls into EGL or GLES functions due to bugs in +// swiftshader. This should be removed as soon as possible. +static std::mutex swiftshader_wa_mutex; + +static void process_cmd(Context* ctx, char* buf, size_t bufSize, int fence) { + VirtioGpuCmd* cmd_resp = reinterpret_cast<VirtioGpuCmd*>(ctx->cmd_resp->linear); + + IOStream stream(cmd_resp->buf, MAX_CMDRESPBUF_SIZE - sizeof(*cmd_resp)); + + { + std::lock_guard<std::mutex> lk(swiftshader_wa_mutex); + size_t decodedBytes; + + decodedBytes = ctx->render_control.decode(buf, bufSize, &stream, &ctx->checksum_calc); + bufSize -= decodedBytes; + buf += decodedBytes; + + decodedBytes = ctx->gles1.decode(buf, bufSize, &stream, &ctx->checksum_calc); + bufSize -= decodedBytes; + buf += decodedBytes; + + decodedBytes = ctx->gles3.decode(buf, bufSize, &stream, &ctx->checksum_calc); + bufSize -= decodedBytes; + buf += decodedBytes; + } + + assert(bufSize == 0); + + cmd_resp->cmdSize += stream.getFlushSize(); + + printf("(tid %d) ctx %d: cmd %u, size %zu, fence %d\n", gettid(), ctx->handle, cmd_resp->op, + cmd_resp->cmdSize - sizeof(*cmd_resp), fence); + if (cmd_resp->cmdSize - sizeof(*cmd_resp) > 0) { + printf("(tid %d) ", gettid()); + for (size_t i = 0; i < cmd_resp->cmdSize - sizeof(*cmd_resp); i++) { + printf("%.2x ", (unsigned char)cmd_resp->buf[i]); + } + printf("\n"); + } + + virgl_box box = { + .w = cmd_resp->cmdSize, + .h = 1, + }; + sync_linear_to_iovec(ctx->cmd_resp, 0, &box); + + { + std::lock_guard<std::mutex> lk(g_fence_deque_mutex); + g_fence_deque.push_back(fence); + } +} + +int virgl_renderer_submit_cmd(void* buffer, int ctx_id, int ndw) { + VirtioGpuCmd* cmd = static_cast<VirtioGpuCmd*>(buffer); + size_t bufSize = sizeof(uint32_t) * ndw; + + if (bufSize < sizeof(*cmd)) { + printf("bad buffer size, bufSize=%zu, ctx=%d\n", bufSize, ctx_id); + return -1; + } + + printf("ctx %d: cmd %u, size %zu\n", ctx_id, cmd->op, cmd->cmdSize - sizeof(*cmd)); + + for (size_t i = 0; i < bufSize - sizeof(*cmd); i++) { + printf("%.2x ", (unsigned char)cmd->buf[i]); + } + printf("\n"); + + if (cmd->cmdSize < bufSize) { + printf("ignoring short command, cmdSize=%u, bufSize=%zu\n", cmd->cmdSize, bufSize); + return 0; + } + + if (cmd->cmdSize > bufSize) { + printf("command would overflow buffer, cmdSize=%u, bufSize=%zu\n", cmd->cmdSize, bufSize); + return -1; + } + + std::map<uint32_t, Context*>::iterator it; + it = Context::map.find((uint32_t)ctx_id); + if (it == Context::map.end()) { + printf("command submit from invalid context %d, ignoring\n", ctx_id); + return 0; + } + + Context* ctx = it->second; + + // When the context is created, the remote side should send a test command + // (op == 0) which we use to set up our link to this context's 'response + // buffer'. Only apps using EGL or GLES have this. Gralloc contexts will + // never hit this path because they do not submit 3D commands. + if (cmd->op == 0) { + std::map<uint32_t, Resource*>::iterator it; + it = Resource::map.find(*(uint32_t*)cmd->buf); + if (it != Resource::map.end()) { + Resource* res = it->second; + size_t cmdRespBufSize = 0U; + for (size_t i = 0; i < res->num_iovs; i++) + cmdRespBufSize += res->iov[i].iov_len; + if (cmdRespBufSize == MAX_CMDRESPBUF_SIZE) + ctx->cmd_resp = res; + } + } + + if (!ctx->cmd_resp) { + printf("context command response page not set up, ctx=%d\n", ctx_id); + return -1; + } + + VirtioGpuCmd* cmd_resp = reinterpret_cast<VirtioGpuCmd*>(ctx->cmd_resp->linear); + + // We can configure bits of the response now. The size, and any message, will + // be updated later. This must be done even for the dummy 'op == 0' command. + cmd_resp->op = cmd->op; + cmd_resp->cmdSize = sizeof(*cmd_resp); + + if (cmd->op == 0) { + // Send back a no-op response, just to keep the protocol in check + virgl_box box = { + .w = cmd_resp->cmdSize, + .h = 1, + }; + sync_linear_to_iovec(ctx->cmd_resp, 0, &box); + } else { + // If the rcSetPuid command was already processed, this command will be + // processed by another thread. If not, the command data will be copied + // here and responded to when ctx->setFence() is called later. + ctx->submitCommand(buffer, bufSize); + } + + g_last_submit_cmd_ctx = ctx; + return 0; +} + +void virgl_renderer_get_cap_set(uint32_t set, uint32_t* max_ver, uint32_t* max_size) { + if (!max_ver || !max_size) + return; + + printf("Request for caps version %u\n", set); + + switch (set) { + case 1: + *max_ver = 1; + *max_size = sizeof(virgl_caps_v1); + break; + case 2: + *max_ver = 2; + *max_size = sizeof(virgl_caps_v2); + break; + default: + *max_ver = 0; + *max_size = 0; + break; + } +} + +void virgl_renderer_fill_caps(uint32_t set, uint32_t, void* caps_) { + union virgl_caps* caps = static_cast<union virgl_caps*>(caps_); + EGLSurface old_read_surface, old_draw_surface; + GLfloat range[2] = { 0.0f, 0.0f }; + bool fill_caps_v2 = false; + EGLContext old_context; + GLint max = 0; + + if (!caps) + return; + + // We don't need to handle caps yet, because our guest driver's features + // should be as close as possible to the host driver's. But maybe some day + // we'll support gallium shaders and the virgl control stream, so it seems + // like a good idea to set up the driver caps correctly.. + + // If this is broken, nothing will work properly + old_read_surface = s_egl.eglGetCurrentSurface(EGL_READ); + old_draw_surface = s_egl.eglGetCurrentSurface(EGL_DRAW); + old_context = s_egl.eglGetCurrentContext(); + if (!s_egl.eglMakeCurrent(g_dpy, g_ctx0_surface, g_ctx0_surface, g_ctx0_es1)) { + printf("Failed to make ES1 context current\n"); + return; + } + + // Don't validate 'version' because it looks like this was misdesigned + // upstream and won't be set; instead, 'set' was bumped from 1->2. + + switch (set) { + case 0: + case 1: + memset(caps, 0, sizeof(virgl_caps_v1)); + caps->max_version = 1; + break; + case 2: + memset(caps, 0, sizeof(virgl_caps_v2)); + caps->max_version = 2; + fill_caps_v2 = true; + break; + default: + caps->max_version = 0; + return; + } + + if (fill_caps_v2) { + printf("Will probe and fill caps version 2.\n"); + } + + // Formats supported for textures + + caps->v1.sampler.bitmask[0] = (1 << (VIRGL_FORMAT_B8G8R8A8_UNORM - (0 * 32))) | + (1 << (VIRGL_FORMAT_B5G6R5_UNORM - (0 * 32))); + caps->v1.sampler.bitmask[2] = (1 << (VIRGL_FORMAT_R8G8B8A8_UNORM - (2 * 32))); + caps->v1.sampler.bitmask[4] = (1 << (VIRGL_FORMAT_R8G8B8X8_UNORM - (4 * 32))); + + // Formats supported for rendering + + caps->v1.render.bitmask[0] = (1 << (VIRGL_FORMAT_B8G8R8A8_UNORM - (0 * 32))) | + (1 << (VIRGL_FORMAT_B5G6R5_UNORM - (0 * 32))); + caps->v1.render.bitmask[2] = (1 << (VIRGL_FORMAT_R8G8B8A8_UNORM - (2 * 32))); + caps->v1.render.bitmask[4] = (1 << (VIRGL_FORMAT_R8G8B8X8_UNORM - (4 * 32))); + + // Could parse s_gles1.glGetString(GL_SHADING_LANGUAGE_VERSION, ...)? + caps->v1.glsl_level = 300; // OpenGL ES GLSL 3.00 + + // Call with any API (v1, v3) bound + + caps->v1.max_viewports = 1; + + s_gles1.glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max); + caps->v1.max_render_targets = max; + + s_gles1.glGetIntegerv(GL_MAX_SAMPLES_EXT, &max); + caps->v1.max_samples = max; + + if (fill_caps_v2) { + s_gles1.glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, range); + caps->v2.min_aliased_point_size = range[0]; + caps->v2.max_aliased_point_size = range[1]; + + s_gles1.glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range); + caps->v2.min_aliased_line_width = range[0]; + caps->v2.max_aliased_line_width = range[1]; + + // An extension, but everybody has it + s_gles1.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max); + caps->v2.max_vertex_attribs = max; + + // Call with ES 1.0 bound *only* + + s_gles1.glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, range); + caps->v2.min_smooth_point_size = range[0]; + caps->v2.max_smooth_point_size = range[1]; + + s_gles1.glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, range); + caps->v2.min_smooth_line_width = range[0]; + caps->v2.max_smooth_line_width = range[1]; + } + + if (!s_egl.eglMakeCurrent(g_dpy, g_ctx0_surface, g_ctx0_surface, g_ctx0_es2)) { + s_egl.eglMakeCurrent(g_dpy, old_draw_surface, old_read_surface, old_context); + printf("Failed to make ES3 context current\n"); + return; + } + + // Call with ES 3.0 bound *only* + + caps->v1.bset.primitive_restart = 1; + caps->v1.bset.seamless_cube_map = 1; + caps->v1.bset.occlusion_query = 1; + caps->v1.bset.instanceid = 1; + caps->v1.bset.ubo = 1; + + s_gles1.glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &max); + caps->v1.max_texture_array_layers = max; + + s_gles1.glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &max); + caps->v1.max_uniform_blocks = max + 1; + + if (fill_caps_v2) { + s_gles1.glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &caps->v2.max_texture_lod_bias); + + s_gles1.glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &max); + caps->v2.max_vertex_outputs = max / 4; + + s_gles1.glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &caps->v2.min_texel_offset); + s_gles1.glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &caps->v2.max_texel_offset); + + s_gles1.glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &max); + caps->v2.uniform_buffer_offset_alignment = max; + } + + // ES 2.0 extensions (fixme) + + // Gallium compatibility; not usable currently. + caps->v1.prim_mask = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); + + if (!s_egl.eglMakeCurrent(g_dpy, old_draw_surface, old_read_surface, old_context)) { + printf("Failed to make no context current\n"); + } +} + +int virgl_renderer_create_fence(int client_fence_id, uint32_t cmd_type) { + switch (cmd_type) { + case VIRTIO_GPU_CMD_SUBMIT_3D: + if (g_last_submit_cmd_ctx) { + g_last_submit_cmd_ctx->setFence(client_fence_id); + break; + } + [[fallthrough]]; + default: { + std::lock_guard<std::mutex> lk(g_fence_deque_mutex); + g_fence_deque.push_back(client_fence_id); + break; + } + } + return 0; +} + +void virgl_renderer_force_ctx_0(void) { +#ifdef QEMU_HARDWARE_GL_INTEROP + if (!g_ctx0_alt) + return; + + if (g_cb->make_current(g_cookie, 0, g_ctx0_alt)) { + printf("Failed to make hardware GL context 0 current\n"); + g_cb->destroy_gl_context(g_cookie, g_ctx0_alt); + g_ctx0_alt = nullptr; + } +#endif +} + +int virgl_renderer_resource_create(virgl_renderer_resource_create_args* args, iovec* iov, + uint32_t num_iovs) { + if (!args) + return EINVAL; + + if (args->bind == VIRGL_RES_BIND_CURSOR) { + // Enforce limitation of current virtio-gpu-3d implementation + if (args->width != 64 || args->height != 64 || args->format != VIRGL_FORMAT_B8G8R8A8_UNORM) + return EINVAL; + } + + assert(!Resource::map.count(args->handle) && "Can't insert same resource twice!"); + + Resource* res = new (std::nothrow) Resource(args, num_iovs, iov); + if (!res) + return ENOMEM; + + printf("Creating Resource %u (num_iovs=%u)\n", args->handle, num_iovs); + return 0; +} + +void virgl_renderer_resource_unref(uint32_t res_handle) { + std::map<uint32_t, Resource*>::iterator it; + + it = Resource::map.find(res_handle); + if (it == Resource::map.end()) + return; + + Resource* res = it->second; + + for (auto const& it : Context::map) { + Context const* ctx = it.second; + + virgl_renderer_ctx_detach_resource(ctx->handle, res->args.handle); + } + + assert(res->context_map.empty() && "Deleted resource was associated with contexts"); + + printf("Deleting Resource %u\n", res_handle); + delete res; +} + +int virgl_renderer_resource_attach_iov(int res_handle, iovec* iov, int num_iovs) { + std::map<uint32_t, Resource*>::iterator it; + + it = Resource::map.find((uint32_t)res_handle); + if (it == Resource::map.end()) + return ENOENT; + + Resource* res = it->second; + + if (!res->iov) { + printf( + "Attaching backing store for Resource %d " + "(num_iovs=%d)\n", + res_handle, num_iovs); + + res->num_iovs = num_iovs; + res->iov = iov; + + res->reallocLinear(); + + // Assumes that when resources are attached, they contain junk, and we + // don't need to synchronize with the linear buffer + } + + return 0; +} + +void virgl_renderer_resource_detach_iov(int res_handle, iovec** iov, int* num_iovs) { + std::map<uint32_t, Resource*>::iterator it; + + it = Resource::map.find((uint32_t)res_handle); + if (it == Resource::map.end()) + return; + + Resource* res = it->second; + + printf("Detaching backing store for Resource %d\n", res_handle); + + // Synchronize our linear buffer, if any, with the iovec that we are about + // to give up. Most likely this is not required, but it seems cleaner. + virgl_box box = { + .w = res->args.width, + .h = res->args.height, + }; + sync_linear_to_iovec(res, 0, &box); + + if (num_iovs) + *num_iovs = res->num_iovs; + res->num_iovs = 0U; + + if (iov) + *iov = res->iov; + res->iov = nullptr; + + res->reallocLinear(); +} + +int virgl_renderer_resource_get_info(int res_handle, virgl_renderer_resource_info* info) { + if (!info) + return EINVAL; + + std::map<uint32_t, Resource*>::iterator it; + + it = Resource::map.find((uint32_t)res_handle); + if (it == Resource::map.end()) + return ENOENT; + + Resource* res = it->second; + + uint32_t bpp = 4U; + switch (res->args.format) { + case VIRGL_FORMAT_B8G8R8A8_UNORM: + info->drm_fourcc = DRM_FORMAT_BGRA8888; + break; + case VIRGL_FORMAT_B5G6R5_UNORM: + info->drm_fourcc = DRM_FORMAT_BGR565; + bpp = 2U; + break; + case VIRGL_FORMAT_R8G8B8A8_UNORM: + info->drm_fourcc = DRM_FORMAT_RGBA8888; + break; + case VIRGL_FORMAT_R8G8B8X8_UNORM: + info->drm_fourcc = DRM_FORMAT_RGBX8888; + break; + default: + return EINVAL; + } + +#ifdef QEMU_HARDWARE_GL_INTEROP + GLenum type = GL_UNSIGNED_BYTE; + GLenum format = GL_RGBA; + switch (res->args.format) { + case VIRGL_FORMAT_B8G8R8A8_UNORM: + format = 0x80E1; // GL_BGRA + break; + case VIRGL_FORMAT_B5G6R5_UNORM: + type = GL_UNSIGNED_SHORT_5_6_5; + format = GL_RGB; + break; + case VIRGL_FORMAT_R8G8B8X8_UNORM: + format = GL_RGB; + break; + } + + if (!res->tex_id) { + g_glGenTextures(1, &res->tex_id); + g_glBindTexture(GL_TEXTURE_2D, res->tex_id); + g_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + g_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + g_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + g_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + g_glBindTexture(GL_TEXTURE_2D, res->tex_id); + } + + g_glPixelStorei(GL_UNPACK_ROW_LENGTH, ALIGN(res->args.width, 16)); + g_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, res->args.width, res->args.height, 0, format, type, + res->linear); +#endif + + info->stride = ALIGN(res->args.width * bpp, 16U); + info->virgl_format = res->args.format; + info->handle = res->args.handle; + info->height = res->args.height; + info->width = res->args.width; + info->depth = res->args.depth; + info->flags = res->args.flags; + info->tex_id = res->tex_id; + + printf("Scanning out Resource %d\n", res_handle); + dump_global_state(); + + return 0; +} + +int virgl_renderer_context_create(uint32_t handle, uint32_t nlen, const char* name) { + assert(!Context::map.count(handle) && "Can't insert same context twice!"); + + Context* ctx = new (std::nothrow) Context(handle, name, nlen, process_cmd, g_dpy); + if (!ctx) + return ENOMEM; + + printf("Creating Context %u (%.*s)\n", handle, (int)nlen, name); + return 0; +} + +void virgl_renderer_context_destroy(uint32_t handle) { + std::map<uint32_t, Context*>::iterator it; + it = Context::map.find(handle); + if (it == Context::map.end()) + return; + + Context* ctx = it->second; + printf("Destroying Context %u\n", handle); + delete ctx; +} + +int virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t, uint32_t, uint32_t, uint32_t, + virgl_box* box, uint64_t offset, iovec*, int) { + // stride, layer_stride and level are not set by minigbm, so don't try to + // validate them right now. iov and iovec_cnt are always passed as nullptr + // and 0 by qemu, so ignore those too + + std::map<uint32_t, Resource*>::iterator it; + it = Resource::map.find((uint32_t)handle); + if (it == Resource::map.end()) + return EINVAL; + + return sync_linear_to_iovec(it->second, offset, box); +} + +int virgl_renderer_transfer_write_iov(uint32_t handle, uint32_t, int, uint32_t, uint32_t, + virgl_box* box, uint64_t offset, iovec*, unsigned int) { + // stride, layer_stride and level are not set by minigbm, so don't try to + // validate them right now. iov and iovec_cnt are always passed as nullptr + // and 0 by qemu, so ignore those too + + std::map<uint32_t, Resource*>::iterator it; + it = Resource::map.find((uint32_t)handle); + if (it == Resource::map.end()) + return EINVAL; + + return sync_iovec_to_linear(it->second, offset, box); +} + +void virgl_renderer_ctx_attach_resource(int ctx_id, int res_handle) { + std::map<uint32_t, Context*>::iterator ctx_it; + + ctx_it = Context::map.find((uint32_t)ctx_id); + if (ctx_it == Context::map.end()) + return; + + Context* ctx = ctx_it->second; + + assert(!ctx->resource_map.count((uint32_t)res_handle) && + "Can't attach resource to context twice!"); + + std::map<uint32_t, Resource*>::iterator res_it; + + res_it = Resource::map.find((uint32_t)res_handle); + if (res_it == Resource::map.end()) + return; + + Resource* res = res_it->second; + + printf("Attaching Resource %d to Context %d\n", res_handle, ctx_id); + res->context_map.emplace((uint32_t)ctx_id, ctx); + ctx->resource_map.emplace((uint32_t)res_handle, res); +} + +void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) { + std::map<uint32_t, Context*>::iterator ctx_it; + + ctx_it = Context::map.find((uint32_t)ctx_id); + if (ctx_it == Context::map.end()) + return; + + Context* ctx = ctx_it->second; + + std::map<uint32_t, Resource*>::iterator res_it; + + res_it = ctx->resource_map.find((uint32_t)res_handle); + if (res_it == ctx->resource_map.end()) + return; + + Resource* res = res_it->second; + + ctx_it = res->context_map.find((uint32_t)ctx_id); + if (ctx_it == res->context_map.end()) + return; + + printf("Detaching Resource %d from Context %d\n", res_handle, ctx_id); + if (ctx->cmd_resp && ctx->cmd_resp->args.handle == (uint32_t)res_handle) + ctx->cmd_resp = nullptr; + ctx->resource_map.erase(res_it); + res->context_map.erase(ctx_it); +} diff --git a/host/libs/virglrenderer/Android.bp b/host/libs/virglrenderer/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..6c31b7a02c087448fcb88c3af58e610949e3d548 --- /dev/null +++ b/host/libs/virglrenderer/Android.bp @@ -0,0 +1,208 @@ +// +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +genrule { + name: "glesv1_dec_cuttlefish_gensrc", + srcs: ["GLESv1_dec/*"], + tools: ["emugen_cuttlefish"], + cmd: "$(location emugen_cuttlefish) " + + "-i device/generic/opengl-transport/host/libs/virglrenderer/GLESv1_dec " + + "-D $(genDir) gles1", + out: ["gles1_dec.cpp"], +} + +genrule { + name: "glesv1_dec_cuttlefish_genhdr", + srcs: ["GLESv1_dec/*"], + tools: ["emugen_cuttlefish"], + cmd: "$(location emugen_cuttlefish) " + + "-i device/generic/opengl-transport/host/libs/virglrenderer/GLESv1_dec " + + "-D $(genDir) gles1", + out: [ + "gles1_dec.h", + "gles1_opcodes.h", + "gles1_server_context.h", + "gles1_server_proc.h", + ], +} + +genrule { + name: "glesv3_dec_cuttlefish_gensrc", + srcs: ["GLESv3_dec/*"], + tools: ["emugen_cuttlefish"], + cmd: "$(location emugen_cuttlefish) " + + "-i device/generic/opengl-transport/host/libs/virglrenderer/GLESv3_dec " + + "-D $(genDir) gles3", + out: ["gles3_dec.cpp"], +} + +genrule { + name: "glesv3_dec_cuttlefish_genhdr", + srcs: ["GLESv3_dec/*"], + tools: ["emugen_cuttlefish"], + cmd: "$(location emugen_cuttlefish) " + + "-i device/generic/opengl-transport/host/libs/virglrenderer/GLESv3_dec " + + "-D $(genDir) gles3", + out: [ + "gles3_dec.h", + "gles3_opcodes.h", + "gles3_server_context.h", + "gles3_server_proc.h", + ], +} + +genrule { + name: "rendercontrol_dec_cuttlefish_gensrc", + srcs: ["renderControl_dec/*"], + tools: ["emugen_cuttlefish"], + cmd: "$(location emugen_cuttlefish) " + + "-i device/generic/opengl-transport/host/libs/virglrenderer/renderControl_dec " + + "-D $(genDir) renderControl", + out: ["renderControl_dec.cpp"], +} + +genrule { + name: "rendercontrol_dec_cuttlefish_genhdr", + srcs: ["renderControl_dec/*"], + tools: ["emugen_cuttlefish"], + cmd: "$(location emugen_cuttlefish) " + + "-i device/generic/opengl-transport/host/libs/virglrenderer/renderControl_dec " + + "-D $(genDir) renderControl", + out: [ + "renderControl_dec.h", + "renderControl_opcodes.h", + "renderControl_server_context.h", + "renderControl_server_proc.h", + ], +} + +// out/host/linux-x86/bin/emugen_cuttlefish -i device/generic/opengl-transport/host/libs/virglrenderer/renderControl_dec -D /tmp/foo renderControl + +genrule { + name: "gles1_core_functions_hdr", + tools: ["gen_entries_cuttlefish"], + cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)", + srcs: ["OpenGLESDispatch/gles1_core.entries"], + out: ["gles1_core_functions.h"], +} + +genrule { + name: "gles1_extensions_functions_hdr", + tools: ["gen_entries_cuttlefish"], + cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)", + srcs: ["OpenGLESDispatch/gles1_extensions.entries"], + out: ["gles1_extensions_functions.h"], +} + +genrule { + name: "egl_functions_hdr", + tools: ["gen_entries_cuttlefish"], + cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)", + srcs: ["OpenGLESDispatch/egl.entries"], + out: ["egl_functions.h"], +} + +genrule { + name: "gles3_only_functions_hdr", + tools: ["gen_entries_cuttlefish"], + cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)", + srcs: ["OpenGLESDispatch/gles3_only.entries"], + out: ["gles3_only_functions.h"], +} + +genrule { + name: "gles31_only_functions_hdr", + tools: ["gen_entries_cuttlefish"], + cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)", + srcs: ["OpenGLESDispatch/gles31_only.entries"], + out: ["gles31_only_functions.h"], +} + +genrule { + name: "gles2_extensions_functions_hdr", + tools: ["gen_entries_cuttlefish"], + cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)", + srcs: ["OpenGLESDispatch/gles2_extensions.entries"], + out: ["gles2_extensions_functions.h"], +} + +genrule { + name: "egl_extensions_functions_hdr", + tools: ["gen_entries_cuttlefish"], + cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)", + srcs: ["OpenGLESDispatch/egl_extensions.entries"], + out: ["egl_extensions_functions.h"], +} + +genrule { + name: "gles2_core_functions_hdr", + tools: ["gen_entries_cuttlefish"], + cmd: "$(location gen_entries_cuttlefish) --mode=funcargs $(in) --output $(out)", + srcs: ["OpenGLESDispatch/gles2_core.entries"], + out: ["gles2_core_functions.h"], +} + +cc_library_host_shared { + name: "libvirglrenderer_cuttlefish", + include_dirs: [ + "external/libdrm", + "external/libdrm/include", + "device/generic/goldfish-opengl/system", + ], + local_include_dirs: [ + "GLESv1_dec", + "GLESv3_dec", + "include", + "renderControl_dec", + ], + srcs: [ + "AVDVirglRenderer.cpp", + "ChecksumCalculator.cpp", + "GLESv1.cpp", + "GLESv3.cpp", + "Gralloc1.cpp", + "OpenGLESDispatch/EGLDispatch.cpp", + "OpenGLESDispatch/GLESv1Dispatch.cpp", + "OpenGLESDispatch/GLESv3Dispatch.cpp", + "RenderControl.cpp", + ], + cflags: ["-Wno-unused-parameter", "-DOPENGL_DEBUG_PRINTOUT"], + host_ldlibs: [ "-ldl" ], + version_script : "libvirglrenderer.lds", + defaults: [ "cuttlefish_host_only" ], + generated_sources: [ + "glesv1_dec_cuttlefish_gensrc", + "glesv3_dec_cuttlefish_gensrc", + "rendercontrol_dec_cuttlefish_gensrc", + ], + generated_headers: [ + "glesv1_dec_cuttlefish_genhdr", + "glesv3_dec_cuttlefish_genhdr", + "rendercontrol_dec_cuttlefish_genhdr", + "gles1_core_functions_hdr", + "gles1_extensions_functions_hdr", + "egl_functions_hdr", + "gles3_only_functions_hdr", + "gles31_only_functions_hdr", + "gles2_extensions_functions_hdr", + "egl_extensions_functions_hdr", + "gles2_core_functions_hdr", + ], + header_libs: [ + "virtio_gpu_uapi_headers", + "virgl_headers" + ], +} diff --git a/host/libs/virglrenderer/ChecksumCalculator.cpp b/host/libs/virglrenderer/ChecksumCalculator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5d11c0cff73b983f045b2abdbebaaf70aefa79a --- /dev/null +++ b/host/libs/virglrenderer/ChecksumCalculator.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ChecksumCalculator.h" + +#include <string> +#include <vector> + +#include <assert.h> +#include <string.h> + +// Checklist when implementing new protocol: +// 1. update CHECKSUMHELPER_MAX_VERSION +// 2. update checksumByteSize() +// 3. update addBuffer, writeChecksum, resetChecksum, validate + +// change CHECKSUMHELPER_MAX_VERSION when you want to update the protocol version +#define CHECKSUMHELPER_MAX_VERSION 1 + +// utility macros to create checksum string at compilation time +#define CHECKSUMHELPER_VERSION_STR_PREFIX "ANDROID_EMU_CHECKSUM_HELPER_v" +#define CHECKSUMHELPER_MACRO_TO_STR(x) #x +#define CHECKSUMHELPER_MACRO_VAL_TO_STR(x) CHECKSUMHELPER_MACRO_TO_STR(x) + +static const uint32_t kMaxVersion = CHECKSUMHELPER_MAX_VERSION; +static const char* kMaxVersionStrPrefix = CHECKSUMHELPER_VERSION_STR_PREFIX; +static const char* kMaxVersionStr = CHECKSUMHELPER_VERSION_STR_PREFIX CHECKSUMHELPER_MACRO_VAL_TO_STR(CHECKSUMHELPER_MAX_VERSION); + +#undef CHECKSUMHELPER_MAX_VERSION +#undef CHECKSUMHELPER_VERSION_STR_PREFIX +#undef CHECKSUMHELPER_MACRO_TO_STR +#undef CHECKSUMHELPER_MACRO_VAL_TO_STR + +uint32_t ChecksumCalculator::getMaxVersion() {return kMaxVersion;} +const char* ChecksumCalculator::getMaxVersionStr() {return kMaxVersionStr;} +const char* ChecksumCalculator::getMaxVersionStrPrefix() {return kMaxVersionStrPrefix;} + +bool ChecksumCalculator::setVersion(uint32_t version) { + if (version > kMaxVersion) { // unsupported version + LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Unsupported version Version %d\n", + __FUNCTION__, m_version); + return false; + } + if (m_isEncodingChecksum) { // setVersion is called in the middle of encoding checksums + LOG_CHECKSUMHELPER("%s: called between addBuffer and writeChecksum\n", + __FUNCTION__); + return false; + } + m_version = version; + m_checksumSize = checksumByteSize(version); + LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Version %d\n", __FUNCTION__, + m_version); + return true; +} + +void ChecksumCalculator::addBuffer(const void* buf, size_t packetLen) { + m_isEncodingChecksum = true; + switch (m_version) { + case 1: + m_v1BufferTotalLength += packetLen; + break; + } +} + +bool ChecksumCalculator::writeChecksum(void* outputChecksum, size_t outputChecksumLen) { + if (outputChecksumLen < checksumByteSize()) return false; + char *checksumPtr = (char *)outputChecksum; + switch (m_version) { + case 1: { // protocol v1 is to reverse the packetLen and write it at the end + uint32_t val = computeV1Checksum(); + memcpy(checksumPtr, &val, sizeof(val)); + memcpy(checksumPtr+sizeof(val), &m_numWrite, sizeof(m_numWrite)); + break; + } + } + resetChecksum(); + m_numWrite++; + return true; +} + +void ChecksumCalculator::resetChecksum() { + switch (m_version) { + case 1: + m_v1BufferTotalLength = 0; + break; + } + m_isEncodingChecksum = false; +} + +bool ChecksumCalculator::validate(const void* expectedChecksum, + size_t expectedChecksumLen) { + const size_t checksumSize = checksumByteSize(); + if (expectedChecksumLen != checksumSize) { + m_numRead++; + resetChecksum(); + return false; + } + bool isValid; + switch (m_version) { + case 1: { + const uint32_t val = computeV1Checksum(); + assert(checksumSize == sizeof(val) + sizeof(m_numRead)); + isValid = 0 == memcmp(&val, expectedChecksum, sizeof(val)) && + 0 == memcmp(&m_numRead, + static_cast<const char*>(expectedChecksum) + + sizeof(val), + sizeof(m_numRead)); + break; + } + default: + isValid = true; // No checksum is a valid checksum. + break; + } + m_numRead++; + resetChecksum(); + return isValid; +} + +uint32_t ChecksumCalculator::computeV1Checksum() const { + uint32_t revLen = m_v1BufferTotalLength; + revLen = (revLen & 0xffff0000) >> 16 | (revLen & 0x0000ffff) << 16; + revLen = (revLen & 0xff00ff00) >> 8 | (revLen & 0x00ff00ff) << 8; + revLen = (revLen & 0xf0f0f0f0) >> 4 | (revLen & 0x0f0f0f0f) << 4; + revLen = (revLen & 0xcccccccc) >> 2 | (revLen & 0x33333333) << 2; + revLen = (revLen & 0xaaaaaaaa) >> 1 | (revLen & 0x55555555) << 1; + return revLen; +} diff --git a/host/libs/virglrenderer/ChecksumCalculator.h b/host/libs/virglrenderer/ChecksumCalculator.h new file mode 100644 index 0000000000000000000000000000000000000000..8e8ce952acdf4b1170af86ff85b60099fb099d37 --- /dev/null +++ b/host/libs/virglrenderer/ChecksumCalculator.h @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdint.h> +#include <stdlib.h> + +// Set TRACE_CHECKSUMHELPER to 1 to debug creation/destruction of GLprotocol +// instances. +#define TRACE_CHECKSUMHELPER 0 + +#if TRACE_CHECKSUMHELPER +#define LOG_CHECKSUMHELPER(x...) fprintf(stderr, x) +#else +#define LOG_CHECKSUMHELPER(x...) +#endif + +namespace android { +namespace base { +class Stream; +} +} // namespace android + +// ChecksumCalculator adds checksum as an array of bytes to GL pipe communication, which +// size depends on the protocol version. Each pipe should use one ChecksumCalculator. +// It can: +// (1) take a list of buffers one by one and compute their checksum string, +// in this case the checksum should be as the data in those buffers are +// concatenated; +// (2) compute the checksum of the buffer list, then either write them into +// a buffer provided by user, or compare it against a checksum provided +// by user +// (3) support different checksum version in future. +// +// For backward compatibility, checksum version 0 behaves the same as there is +// no checksum (i.e., checksumByteSize returns 0, validate always returns true, +// addBuffer and writeCheckSum does nothing). +// +// Notice that to detect package lost, ChecksumCalculator also keeps track of how +// many times it generates/validates checksums, and might use it as part of the +// checksum. +// +// To evaluate checksums from a list of data buffers buf1, buf2... Please call +// addBuffer(buf1, buf1len), addBuffer(buf2, buf2len) ... in order. +// Then if the checksum needs to be encoded into a buffer, one needs to allocate +// a checksum buffer with size checksumByteSize(), and call +// writeChecksum(checksumBuffer) to write the checksum to the buffer. +// If the checksum needs to be validated against an existing one, one needs to +// call validate(existChecksum, existChecksumLen). +// +// The checksum generator and validator must be set to the same version, and +// the validator must check ALL checksums in the order they are generated, +// otherwise the validation function will return false. +// +// It is allowed to change the checksum version between calculating two +// checksums. This is designed for backward compatibility reason. +// +// Example 1, encoding and decoding: +// +// bool testChecksum(void* buf, size_t bufLen) { +// // encoding message +// ChecksumCalculator encoder; +// encoder.setVersion(1); +// encoder.addBuffer(buf, bufLen); +// std::vector<unsigned char> message(bufLen + encoder.checksumByteSize()); +// memcpy(&message[0], buf, bufLen); +// encoder.writeChecksum(&message[0] + bufLen, encoder.checksumByteSize()); +// +// // decoding message +// ChecksumCalculator decoder; +// decoder.setVersion(1); +// decoder.addBuffer(&message[0], bufLen); +// return decoder.validate(&message[0] + bufLen, decoder.checksumByteSize()); +// } +// The return value is true. +// +// Example 2, decoding will fail if the order of messages is wrong: +// +// bool testChecksumOrder(void* buf1, size_t bufLen1, +// void* buf2, size_t bufLen2) { +// // encoding messages +// ChecksumCalculator encoder; +// encoder.setVersion(1); +// +// std::vector<unsigned char> message1(bufLen1 + encoder.checksumByteSize()); +// std::vector<unsigned char> message2(bufLen2 + encoder.checksumByteSize()); +// +// encoder.addBuffer(buf1, bufLen1); +// std::vector<unsigned char> message1(bufLen1 + encoder.checksumByteSize()); +// memcpy(&message1[0], buf1, bufLen1); +// encoder.writeChecksum(&message1[0] + bufLen1, encoder.checksumByteSize()); +// +// encoder.addBuffer(buf2, bufLen2); +// std::vector<unsigned char> message2(bufLen2 + encoder.checksumByteSize()); +// memcpy(&message2[0], buf2, bufLen2); +// encoder.writeChecksum(&message2[0] + bufLen2, encoder.checksumByteSize()); +// +// // decoding messages +// ChecksumCalculator decoder; +// decoder.setVersion(1); +// decoder.addBuffer(&message2[0], bufLen2); +// // returns false because the decoding order is not consistent with +// // encoding order +// if (!decoder.validate(&message2[0]+bufLen2, decoder.checksumByteSize())) { +// return false; +// } +// +// decoder.addBuffer(&message1[0], bufLen1); +// if (!decoder.validate(&message1[0]+bufLen1, decoder.checksumByteSize())) { +// return false; +// } +// +// return false; +// } + +class ChecksumCalculator { + public: + static constexpr size_t kMaxChecksumLength = 8; + + // Get and set current checksum version + uint32_t getVersion() const { + return m_version; + } + // Call setVersion to set a checksum version. It should be called before + // addBuffer(), writeChecksum() and validate(). And it should be called + // exact once per rendering thread if both host and guest support checksum. + // It won't be called if either host or guest does not support checksum. + bool setVersion(uint32_t version); + + // Maximum supported checksum version + static uint32_t getMaxVersion(); + // A version string that looks like "ANDROID_EMU_CHECKSUM_HELPER_v1" + // Used multiple times when the guest queries the maximum supported version + // from the host. + // The library owns the returned pointer. The returned pointer will be + // deconstructed when unloading library. + static const char* getMaxVersionStr(); + static const char* getMaxVersionStrPrefix(); + + // Size of checksum in the current version + size_t checksumByteSize() const { + return m_checksumSize; + } + + // Update the current checksum value from the data + // at |buf| of |bufLen| bytes. Once all buffers + // have been added, call writeChecksum() to store + // the final checksum value and reset its state. + void addBuffer(const void* buf, size_t bufLen); + // Write the checksum from the list of buffers to outputChecksum + // Will reset the list of buffers by calling resetChecksum. + // Return false if the buffer is not long enough + // Please query buffer size from checksumByteSize() + bool writeChecksum(void* outputChecksum, size_t outputChecksumLen); + // Restore the states for computing checksums. + // Automatically called at the end of writeChecksum and validate. + // Can also be used to abandon the current checksum being calculated. + // Notes: it doesn't update the internal read / write counter + void resetChecksum(); + + // Calculate the checksum from the list of buffers and + // compare it with the checksum encoded in expectedChecksum + // Will reset the list of buffers by calling resetChecksum. + bool validate(const void* expectedChecksum, size_t expectedChecksumLen); + + private: + static constexpr size_t kVersion1ChecksumSize = 8; // 2 x uint32_t + + static_assert(kVersion1ChecksumSize <= kMaxChecksumLength, + "Invalid ChecksumCalculator::kMaxChecksumLength value"); + + static constexpr size_t checksumByteSize(uint32_t version) { + return version == 1 ? kVersion1ChecksumSize : 0; + } + + uint32_t m_version = 0; + uint32_t m_checksumSize = checksumByteSize(0); + // A temporary state used to compute the total length of a list of buffers, + // if addBuffer is called. + uint32_t m_numRead = 0; + uint32_t m_numWrite = 0; + // m_isEncodingChecksum is true when between addBuffer and writeChecksum + bool m_isEncodingChecksum = false; + + // Compute a 32bit checksum + // Used in protocol v1 + uint32_t computeV1Checksum() const; + // The buffer used in protocol version 1 to compute checksum. + uint32_t m_v1BufferTotalLength = 0; +}; diff --git a/host/libs/virglrenderer/ChecksumCalculatorThreadInfo.h b/host/libs/virglrenderer/ChecksumCalculatorThreadInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..51f8e1c31c84c28ac7cc37d9d6da1e5aea56fa1d --- /dev/null +++ b/host/libs/virglrenderer/ChecksumCalculatorThreadInfo.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ChecksumCalculator.h" + +#include <stdio.h> + +// NOTE: This fork of ChecksumCalculatorThreadInfo is *not* thread safe + +class ChecksumCalculatorThreadInfo { + public: + static bool writeChecksum(ChecksumCalculator* calc, void* buf, size_t bufLen, + void* outputChecksum, size_t outputChecksumLen) { + calc->addBuffer(buf, bufLen); + return calc->writeChecksum(outputChecksum, outputChecksumLen); + } + + static bool validate(ChecksumCalculator* calc, void* buf, size_t bufLen, void* checksum, + size_t checksumLen) { + calc->addBuffer(buf, bufLen); + return calc->validate(checksum, checksumLen); + } + + static void validOrDie(ChecksumCalculator* calc, void* buf, size_t bufLen, void* checksum, + size_t checksumLen, const char* message) { + if (!validate(calc, buf, bufLen, checksum, checksumLen)) { + printf("%s\n", message); + } + } +}; diff --git a/host/libs/virglrenderer/Context.h b/host/libs/virglrenderer/Context.h new file mode 100644 index 0000000000000000000000000000000000000000..53c5488cd9d075bc7cb2e95a6faef0a77973a119 --- /dev/null +++ b/host/libs/virglrenderer/Context.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#undef NDEBUG + +#include <cassert> +#include <condition_variable> +#include <cstdint> +#include <map> +#include <mutex> +#include <string> +#include <thread> + +#include "GLESv1.h" +#include "GLESv3.h" +#include "RenderControl.h" +#include "Resource.h" + +struct EglContext; +struct Context; + +typedef void (*PFNSUBMITCMD)(Context*, char*, size_t, int); + +struct Context { + static std::map<uint32_t, Context*> map; + + Context(uint32_t handle_, const char* name_, uint32_t nlen_, PFNSUBMITCMD pfnProcessCmd_, + EGLDisplay dpy_) + : render_control(this, dpy_), worker(), name(std::string(name_, nlen_)), handle(handle_), + pfnProcessCmd(pfnProcessCmd_) { + map.emplace(handle, this); + reset(); + } + + ~Context() { + { + std::lock_guard<std::mutex> lk(m); + killWorker = true; + } + cv.notify_one(); + if (worker.joinable()) + worker.join(); + map.erase(handle); + } + + Context* bind(EglContext* ctx_) { + for (auto const& it : Context::map) { + Context* ctx = it.second; + if (ctx == this) + continue; + if (ctx->ctx == ctx_) + return ctx; + } + ctx = ctx_; + return nullptr; + } + + void unbind() { + ctx = nullptr; + } + + void setPidTid(int pid_, int tid_) { + if (pid != pid_ && tid != tid_) { + assert(!worker.joinable() && "Changing pid/tid is not allowed"); + worker = std::thread(&Context::worker_func, this); + } + pid = pid_; + tid = tid_; + } + + void submitCommand(void* buf, size_t bufSize) { + char* cmdBufCopy = new char[bufSize]; + memcpy(cmdBufCopy, buf, bufSize); + { + std::lock_guard<std::mutex> lk(m); + cmdBufSize = bufSize; + cmdBuf = cmdBufCopy; + } + cv.notify_one(); + } + + void setFence(int fence_) { + { + std::lock_guard<std::mutex> lk(m); + fence = fence_; + if (!worker.joinable()) + processCmd(); + } + cv.notify_one(); + } + + std::map<uint32_t, Resource*> resource_map; + ChecksumCalculator checksum_calc; + RenderControl render_control; + Resource* cmd_resp = nullptr; + EglContext* ctx = nullptr; + std::thread worker; + std::string name; + uint32_t handle; + GLESv1 gles1; + GLESv3 gles3; + int pid = 0; + int tid = 0; + + private: + std::condition_variable cv; + PFNSUBMITCMD pfnProcessCmd; + bool killWorker = false; + size_t cmdBufSize; + char* cmdBuf; + std::mutex m; + int fence; + + void reset() { + cmdBuf = nullptr; + cmdBufSize = 0U; + fence = 0; + } + + void worker_func() { + while (!killWorker) { + std::unique_lock<std::mutex> lk(m); + cv.wait(lk, [this] { return killWorker || (cmdBuf && fence); }); + if (!killWorker) + processCmd(); + lk.unlock(); + } + } + + void processCmd() { + pfnProcessCmd(this, cmdBuf, cmdBufSize, fence); + delete cmdBuf; + reset(); + } +}; diff --git a/host/libs/virglrenderer/EglConfig.h b/host/libs/virglrenderer/EglConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..3b5cd2b49583f097525f4a45aa284081d8da5864 --- /dev/null +++ b/host/libs/virglrenderer/EglConfig.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <vector> + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +typedef EGLBoolean (*PFNEGLGETCONFIGATTRIB)(EGLDisplay, EGLConfig, EGLint, EGLint*); + +struct EglConfig { + static std::vector<EglConfig*> vec; + + // clang-format off + static constexpr EGLint kAttribs[] = { + EGL_DEPTH_SIZE, + EGL_STENCIL_SIZE, + EGL_RENDERABLE_TYPE, + EGL_SURFACE_TYPE, + EGL_CONFIG_ID, + EGL_BUFFER_SIZE, + EGL_ALPHA_SIZE, + EGL_BLUE_SIZE, + EGL_GREEN_SIZE, + EGL_RED_SIZE, + EGL_CONFIG_CAVEAT, + EGL_LEVEL, + EGL_MAX_PBUFFER_HEIGHT, + EGL_MAX_PBUFFER_PIXELS, + EGL_MAX_PBUFFER_WIDTH, + EGL_NATIVE_RENDERABLE, + EGL_NATIVE_VISUAL_ID, + EGL_NATIVE_VISUAL_TYPE, + 0x3030, // EGL_PRESERVED_RESOURCES + EGL_SAMPLES, + EGL_SAMPLE_BUFFERS, + EGL_TRANSPARENT_TYPE, + EGL_TRANSPARENT_BLUE_VALUE, + EGL_TRANSPARENT_GREEN_VALUE, + EGL_TRANSPARENT_RED_VALUE, + EGL_BIND_TO_TEXTURE_RGB, + EGL_BIND_TO_TEXTURE_RGBA, + EGL_MIN_SWAP_INTERVAL, + EGL_MAX_SWAP_INTERVAL, + EGL_LUMINANCE_SIZE, + EGL_ALPHA_MASK_SIZE, + EGL_COLOR_BUFFER_TYPE, + //EGL_MATCH_NATIVE_PIXMAP, + EGL_RECORDABLE_ANDROID, + EGL_CONFORMANT + }; + // clang-format on + + static constexpr size_t kNumAttribs = sizeof(kAttribs) / sizeof(kAttribs[0]); + + EglConfig(EGLDisplay dpy, EGLConfig config_, PFNEGLGETCONFIGATTRIB pfnEglGetConfigAttrib) + : config(config_) { + for (size_t a = 0; a < kNumAttribs; a++) { + if (!pfnEglGetConfigAttrib(dpy, config, kAttribs[a], &attribs[a])) + attribs[a] = 0; + } + vec.push_back(this); + } + + ~EglConfig() { + for (size_t i = 0; i < EglConfig::vec.size(); i++) { + if (vec[i] == this) { + vec.erase(vec.begin() + i); + break; + } + } + } + + EGLint attribs[kNumAttribs]; + EGLConfig config; +}; diff --git a/host/libs/virglrenderer/EglContext.h b/host/libs/virglrenderer/EglContext.h new file mode 100644 index 0000000000000000000000000000000000000000..7283c08cd209803d630f4f1e4b2227aacb3e6e29 --- /dev/null +++ b/host/libs/virglrenderer/EglContext.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <map> + +#include <EGL/egl.h> + +struct EglContext { + enum GLESApi { + GLESApi_CM = 1, + GLESApi_2 = 2, + GLESApi_3_0 = 3, + GLESApi_3_1 = 4, + }; + + static std::map<uint32_t, EglContext*> map; + static uint32_t nextId; + + EglContext(EGLContext context_, uint32_t ctx_, GLESApi api_) + : create_ctx(ctx_), context(context_), api(api_), id(nextId++) { + map.emplace(id, this); + } + + ~EglContext() { + map.erase(id); + } + + EglContext* bind(uint32_t ctx_) { + for (auto const& it : EglContext::map) { + EglContext* ctx = it.second; + if (ctx == this) + continue; + if (ctx->bound_ctx == ctx_) + return ctx; + } + bound_ctx = ctx_; + return nullptr; + } + + void unbind() { + bound_ctx = 0U; + } + + bool disposable() { + return context == EGL_NO_CONTEXT && bound_ctx == 0U; + } + + uint32_t create_ctx; + EGLContext context; + enum GLESApi api; + uint32_t id; + + private: + uint32_t bound_ctx = 0U; +}; diff --git a/host/libs/virglrenderer/EglImage.h b/host/libs/virglrenderer/EglImage.h new file mode 100644 index 0000000000000000000000000000000000000000..09b968c205a7c90936960b090f19d36a248b4e0c --- /dev/null +++ b/host/libs/virglrenderer/EglImage.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <map> + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +typedef EGLBoolean (*PFNEGLDESTROYIMAGEKHR)(EGLDisplay, EGLImageKHR); + +struct EglImage { + static std::map<uint32_t, EglImage*> map; + static uint32_t nextId; + + EglImage(EGLDisplay dpy_, EGLImageKHR image_, PFNEGLDESTROYIMAGEKHR pfnEglDestroyImageKHR_) + : pfnEglDestroyImageKHR(pfnEglDestroyImageKHR_), image(image_), dpy(dpy_), id(nextId++) { + map.emplace(id, this); + } + + ~EglImage() { + pfnEglDestroyImageKHR(dpy, image); + map.erase(id); + } + + PFNEGLDESTROYIMAGEKHR pfnEglDestroyImageKHR; + EGLImageKHR image; + EGLDisplay dpy; + uint32_t id; +}; diff --git a/host/libs/virglrenderer/EglSurface.h b/host/libs/virglrenderer/EglSurface.h new file mode 100644 index 0000000000000000000000000000000000000000..4bb880dbb0acda986cc9fc7578daf13e83801d86 --- /dev/null +++ b/host/libs/virglrenderer/EglSurface.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <map> + +#include <EGL/egl.h> + +struct ANativeWindow; + +struct EglSurface { + static std::map<uint32_t, EglSurface*> map; + static uint32_t nextId; + + EglSurface(EGLConfig config_, uint32_t ctx_, uint32_t width_, uint32_t height_) + : create_ctx(ctx_), config(config_), height(height_), width(width_), id(nextId++) { + map.emplace(id, this); + } + + ~EglSurface() { + map.erase(id); + } + + EglSurface* bind(uint32_t ctx_, bool read_) { + for (auto const& it : EglSurface::map) { + EglSurface* sur = it.second; + if (sur == this) + continue; + if (sur->bound_ctx == ctx_) { + if (read_ && sur->read) + return sur; + if (!read_ && sur->draw) + return sur; + } + } + if (read_) { + read = true; + } else { + draw = true; + } + bound_ctx = ctx_; + return nullptr; + } + + void unbind(bool read_) { + if (read || draw) { + if (read_) + read = false; + else + draw = false; + if (read || draw) + return; + bound_ctx = 0U; + } + return; + } + + bool disposable() { + return surface == EGL_NO_SURFACE && bound_ctx == 0U; + } + + EGLSurface surface = EGL_NO_SURFACE; + ANativeWindow* window = nullptr; + uint32_t create_ctx; + EGLConfig config; + uint32_t height; + uint32_t width; + uint32_t id; + + private: + uint32_t bound_ctx = 0U; + bool draw = false; + bool read = false; +}; diff --git a/host/libs/virglrenderer/EglSync.h b/host/libs/virglrenderer/EglSync.h new file mode 100644 index 0000000000000000000000000000000000000000..8dda71331b70dedfcdc07d02736357f4d9d72426 --- /dev/null +++ b/host/libs/virglrenderer/EglSync.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <map> + +#include <EGL/egl.h> + +struct EglSync { + static std::map<uint64_t, EglSync*> map; + static uint64_t nextId; + + EglSync(EGLSyncKHR sync_) : sync(sync_), id(nextId++) { + map.emplace(id, this); + } + + ~EglSync() { + map.erase(id); + } + + EGLSyncKHR sync; + uint64_t id; +}; diff --git a/host/libs/virglrenderer/GLESv1.cpp b/host/libs/virglrenderer/GLESv1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..17a7ae4b3ed969aebe8fc7d8ab2861b64f2ca46a --- /dev/null +++ b/host/libs/virglrenderer/GLESv1.cpp @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <OpenGLESDispatch/GLESv1Dispatch.h> + +#include "GLESv1.h" + +// Stubs (common) + +static void glDeleteFencesNV(GLsizei, const GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glDisableDriverControlQCOM(GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glDiscardFramebufferEXT(GLenum, GLsizei, const GLenum*) { + printf("%s: not implemented\n", __func__); +} + +static void glEnableDriverControlQCOM(GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glEndTilingQCOM(GLbitfield) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetBufferPointervQCOM(GLenum, GLvoid**) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetBuffersQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetFramebuffersQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetProgramBinarySourceQCOM(GLuint, GLenum, GLchar*, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetProgramsQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetRenderbuffersQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetShadersQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetTexLevelParameterivQCOM(GLuint, GLenum, GLint, GLenum, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetTexSubImageQCOM(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, + GLenum, GLenum, GLvoid*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetTexturesQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static GLboolean glExtIsProgramBinaryQCOM(GLuint) { + printf("%s: not implemented\n", __func__); + return GL_FALSE; +} + +static void glExtTexObjectStateOverrideiQCOM(GLenum, GLenum, GLint) { + printf("%s: not implemented\n", __func__); +} + +static void glFinishFenceNV(GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glFramebufferTexture2DMultisampleIMG(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei) { + printf("%s: not implemented\n", __func__); +} + +static void glGenFencesNV(GLsizei, GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetDriverControlsQCOM(GLint*, GLsizei, GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetDriverControlStringQCOM(GLuint, GLsizei, GLsizei*, GLchar*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetFenceivNV(GLuint, GLenum, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static GLboolean glIsFenceNV(GLuint) { + printf("%s: not implemented\n", __func__); + return GL_FALSE; +} + +static void* glMapBufferOES(GLenum, GLenum) { + printf("%s: not implemented\n", __func__); + return nullptr; +} + +static void glMultiDrawArraysEXT(GLenum, const GLint*, const GLsizei*, GLsizei) { + printf("%s: not implemented\n", __func__); +} + +static void glMultiDrawElementsEXT(GLenum, const GLsizei*, GLenum, const GLvoid* const*, GLsizei) { + printf("%s: not implemented\n", __func__); +} + +static void glRenderbufferStorageMultisampleIMG(GLenum, GLsizei, GLenum, GLsizei, GLsizei) { + printf("%s: not implemented\n", __func__); +} + +static void glSetFenceNV(GLuint, GLenum) { + printf("%s: not implemented\n", __func__); +} + +static void glStartTilingQCOM(GLuint, GLuint, GLuint, GLuint, GLbitfield) { + printf("%s: not implemented\n", __func__); +} + +static GLboolean glTestFenceNV(GLuint) { + printf("%s: not implemented\n", __func__); + return GL_FALSE; +} + +// Stubs (ES 1.1) + +static void glBindVertexArrayOES(GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glCurrentPaletteMatrixOES(GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glDeleteVertexArraysOES(GLsizei, const GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGenVertexArraysOES(GLsizei, GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetBufferPointervOES(GLenum, GLenum, GLvoid**) { + printf("%s: not implemented\n", __func__); +} + +static void glGetTexGenfvOES(GLenum, GLenum, GLfloat*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetTexGenivOES(GLenum, GLenum, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetTexGenxvOES(GLenum, GLenum, GLfixed*) { + printf("%s: not implemented\n", __func__); +} + +static GLboolean glIsVertexArrayOES(GLuint) { + printf("%s: not implemented\n", __func__); + return GL_FALSE; +} + +static void glLoadPaletteFromModelViewMatrixOES() { + printf("%s: not implemented\n", __func__); +} + +static void glMatrixIndexPointerData(GLint, GLenum, GLsizei, void*, GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glMatrixIndexPointerOffset(GLint, GLenum, GLsizei, GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glMultiDrawArraysSUN(GLenum, GLint*, GLsizei*, GLsizei) { + printf("%s: not implemented\n", __func__); +} + +static void glMultiDrawElementsSUN(GLenum, const GLsizei*, GLenum, const GLvoid**, GLsizei) { + printf("%s: not implemented\n", __func__); +} + +static GLbitfield glQueryMatrixxOES(GLfixed*, GLint*) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static void glTexGenfOES(GLenum, GLenum, GLfloat) { + printf("%s: not implemented\n", __func__); +} + +static void glTexGenfvOES(GLenum, GLenum, const GLfloat*) { + printf("%s: not implemented\n", __func__); +} + +static void glTexGeniOES(GLenum, GLenum, GLint) { + printf("%s: not implemented\n", __func__); +} + +static void glTexGenivOES(GLenum, GLenum, const GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glTexGenxOES(GLenum, GLenum, GLfixed) { + printf("%s: not implemented\n", __func__); +} + +static void glTexGenxvOES(GLenum, GLenum, const GLfixed*) { + printf("%s: not implemented\n", __func__); +} + +static GLboolean glUnmapBufferOES(GLenum) { + printf("%s: not implemented\n", __func__); + return GL_FALSE; +} + +static void glWeightPointerData(GLint, GLenum, GLsizei, void*, GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glWeightPointerOffset(GLint, GLenum, GLsizei, GLuint) { + printf("%s: not implemented\n", __func__); +} + +// Non-stubs (common) + +static void glDrawElementsData(GLenum mode, GLsizei count, GLenum type, void* indices, GLuint) { + s_gles1.glDrawElements(mode, count, type, indices); +} + +static void glDrawElementsOffset(GLenum mode, GLsizei count, GLenum type, GLuint offset) { + s_gles1.glDrawElements(mode, count, type, reinterpret_cast<const GLvoid*>(offset)); +} + +static GLint glFinishRoundTrip() { + s_gles1.glFinish(); + return 0; +} + +static void glGetCompressedTextureFormats(int count, GLint* formats) { + int nFormats; + s_gles1.glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &nFormats); + if (nFormats <= count) + s_gles1.glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats); +} + +// Non-stubs (ES 1.1) + +static void glColorPointerData(GLint size, GLenum type, GLsizei, void* data, GLuint) { + s_gles1.glColorPointer(size, type, 0, data); +} + +static void glColorPointerOffset(GLint size, GLenum type, GLsizei, GLuint offset) { + s_gles1.glColorPointer(size, type, 0, reinterpret_cast<GLvoid*>(offset)); +} + +static void glNormalPointerData(GLenum type, GLsizei, void* data, GLuint) { + s_gles1.glNormalPointer(type, 0, data); +} + +static void glNormalPointerOffset(GLenum type, GLsizei, GLuint offset) { + s_gles1.glNormalPointer(type, 0, reinterpret_cast<GLvoid*>(offset)); +} + +static void glPointSizePointerData(GLenum type, GLsizei, void* data, GLuint) { + s_gles1.glPointSizePointerOES(type, 0, data); +} + +static void glPointSizePointerOffset(GLenum type, GLsizei, GLuint offset) { + s_gles1.glPointSizePointerOES(type, 0, reinterpret_cast<GLvoid*>(offset)); +} + +static void glTexCoordPointerData(GLint, GLint size, GLenum type, GLsizei, void* data, GLuint) { + // FIXME: unit? + s_gles1.glTexCoordPointer(size, type, 0, data); +} + +static void glTexCoordPointerOffset(GLint size, GLenum type, GLsizei, GLuint offset) { + s_gles1.glTexCoordPointer(size, type, 0, reinterpret_cast<GLvoid*>(offset)); +} + +static void glVertexPointerData(GLint size, GLenum type, GLsizei, void* data, GLuint) { + s_gles1.glVertexPointer(size, type, 0, data); +} + +static void glVertexPointerOffset(GLint size, GLenum type, GLsizei, GLuint offset) { + s_gles1.glVertexPointer(size, type, 0, reinterpret_cast<GLvoid*>(offset)); +} + +#define KNIT(return_type, function_name, signature, callargs) function_name = s_gles1.function_name; + +GLESv1::GLESv1() { + LIST_GLES1_FUNCTIONS(KNIT, KNIT) + + // Remap some ES 1.0 extensions that become core in ES 1.1 + glAlphaFuncxOES = glAlphaFuncx; + glClearColorxOES = glClearColorx; + glClearDepthfOES = glClearDepthf; + glClearDepthxOES = glClearDepthx; + glClipPlanefIMG = glClipPlanef; + glClipPlanefOES = glClipPlanef; + glClipPlanexIMG = glClipPlanex; + glClipPlanexOES = glClipPlanex; + glColor4xOES = glColor4x; + glDepthRangefOES = glDepthRangef; + glDepthRangexOES = glDepthRangex; + glFogxOES = glFogx; + glFogxvOES = glFogxv; + glFrustumfOES = glFrustumf; + glFrustumxOES = glFrustumx; + glGetClipPlanefOES = glGetClipPlanef; + glGetClipPlanexOES = glGetClipPlanex; + glGetFixedvOES = glGetFixedv; + glGetLightxvOES = glGetLightxv; + glGetMaterialxvOES = glGetMaterialxv; + glGetTexEnvxvOES = glGetTexEnvxv; + glGetTexParameterxvOES = glGetTexParameterxv; + glLightModelxOES = glLightModelx; + glLightModelxvOES = glLightModelxv; + glLightxOES = glLightx; + glLightxvOES = glLightxv; + glLineWidthxOES = glLineWidthx; + glLoadMatrixxOES = glLoadMatrixx; + glMaterialxOES = glMaterialx; + glMaterialxvOES = glMaterialxv; + glMultiTexCoord4xOES = glMultiTexCoord4x; + glMultMatrixxOES = glMultMatrixx; + glNormal3xOES = glNormal3x; + glOrthofOES = glOrthof; + glOrthoxOES = glOrthox; + glPointParameterxOES = glPointParameterx; + glPointParameterxvOES = glPointParameterxv; + glPointSizexOES = glPointSizex; + glPolygonOffsetxOES = glPolygonOffsetx; + glRotatexOES = glRotatex; + glSampleCoveragexOES = glSampleCoveragex; + glScalexOES = glScalex; + glTexEnvxOES = glTexEnvx; + glTexEnvxvOES = glTexEnvxv; + glTexParameterxOES = glTexParameterx; + glTexParameterxvOES = glTexParameterxv; + glTranslatexOES = glTranslatex; + + // Entrypoints requiring custom wrappers (common) + glDrawElementsData = ::glDrawElementsData; + glDrawElementsOffset = ::glDrawElementsOffset; + glFinishRoundTrip = ::glFinishRoundTrip; + glGetCompressedTextureFormats = ::glGetCompressedTextureFormats; + + // Entrypoints requiring custom wrappers (ES 1.1) + glColorPointerData = ::glColorPointerData; + glColorPointerOffset = ::glColorPointerOffset; + glNormalPointerData = ::glNormalPointerData; + glNormalPointerOffset = ::glNormalPointerOffset; + glPointSizePointerData = ::glPointSizePointerData; + glPointSizePointerOffset = ::glPointSizePointerOffset; + glTexCoordPointerData = ::glTexCoordPointerData; + glTexCoordPointerOffset = ::glTexCoordPointerOffset; + glVertexPointerData = ::glVertexPointerData; + glVertexPointerOffset = ::glVertexPointerOffset; + + // Stub some extensions we will never implement (common) + glDeleteFencesNV = ::glDeleteFencesNV; + glDisableDriverControlQCOM = ::glDisableDriverControlQCOM; + glDiscardFramebufferEXT = ::glDiscardFramebufferEXT; + glEnableDriverControlQCOM = ::glEnableDriverControlQCOM; + glEndTilingQCOM = ::glEndTilingQCOM; + glExtGetBufferPointervQCOM = ::glExtGetBufferPointervQCOM; + glExtGetBuffersQCOM = ::glExtGetBuffersQCOM; + glExtGetFramebuffersQCOM = ::glExtGetFramebuffersQCOM; + glExtGetProgramBinarySourceQCOM = ::glExtGetProgramBinarySourceQCOM; + glExtGetProgramsQCOM = ::glExtGetProgramsQCOM; + glExtGetRenderbuffersQCOM = ::glExtGetRenderbuffersQCOM; + glExtGetShadersQCOM = ::glExtGetShadersQCOM; + glExtGetTexLevelParameterivQCOM = ::glExtGetTexLevelParameterivQCOM; + glExtGetTexSubImageQCOM = ::glExtGetTexSubImageQCOM; + glExtGetTexturesQCOM = ::glExtGetTexturesQCOM; + glExtIsProgramBinaryQCOM = ::glExtIsProgramBinaryQCOM; + glExtTexObjectStateOverrideiQCOM = ::glExtTexObjectStateOverrideiQCOM; + glFinishFenceNV = ::glFinishFenceNV; + glFramebufferTexture2DMultisampleIMG = ::glFramebufferTexture2DMultisampleIMG; + glGenFencesNV = ::glGenFencesNV; + glGetDriverControlsQCOM = ::glGetDriverControlsQCOM; + glGetDriverControlStringQCOM = ::glGetDriverControlStringQCOM; + glGetFenceivNV = ::glGetFenceivNV; + glIsFenceNV = ::glIsFenceNV; + glMapBufferOES = ::glMapBufferOES; + glMultiDrawArraysEXT = ::glMultiDrawArraysEXT; + glMultiDrawElementsEXT = ::glMultiDrawElementsEXT; + glRenderbufferStorageMultisampleIMG = ::glRenderbufferStorageMultisampleIMG; + glSetFenceNV = ::glSetFenceNV; + glStartTilingQCOM = ::glStartTilingQCOM; + glTestFenceNV = ::glTestFenceNV; + + // Stub some extensions we will never implement (ES 1.1) + glBindVertexArrayOES = ::glBindVertexArrayOES; + glCurrentPaletteMatrixOES = ::glCurrentPaletteMatrixOES; + glDeleteVertexArraysOES = ::glDeleteVertexArraysOES; + glGenVertexArraysOES = ::glGenVertexArraysOES; + glGetBufferPointervOES = ::glGetBufferPointervOES; + glGetTexGenfvOES = ::glGetTexGenfvOES; + glGetTexGenivOES = ::glGetTexGenivOES; + glGetTexGenxvOES = ::glGetTexGenxvOES; + glIsVertexArrayOES = ::glIsVertexArrayOES; + glLoadPaletteFromModelViewMatrixOES = ::glLoadPaletteFromModelViewMatrixOES; + glMatrixIndexPointerData = ::glMatrixIndexPointerData; + glMatrixIndexPointerOffset = ::glMatrixIndexPointerOffset; + glMultiDrawArraysSUN = ::glMultiDrawArraysSUN; + glMultiDrawElementsSUN = ::glMultiDrawElementsSUN; + glQueryMatrixxOES = ::glQueryMatrixxOES; + glTexGenfOES = ::glTexGenfOES; + glTexGenfvOES = ::glTexGenfvOES; + glTexGeniOES = ::glTexGeniOES; + glTexGenivOES = ::glTexGenivOES; + glTexGenxOES = ::glTexGenxOES; + glTexGenxvOES = ::glTexGenxvOES; + glUnmapBufferOES = ::glUnmapBufferOES; + glWeightPointerData = ::glWeightPointerData; + glWeightPointerOffset = ::glWeightPointerOffset; +} diff --git a/host/libs/virglrenderer/GLESv1.h b/host/libs/virglrenderer/GLESv1.h new file mode 100644 index 0000000000000000000000000000000000000000..00c1ec42d52db73021a13c012dd14cc07f3af135 --- /dev/null +++ b/host/libs/virglrenderer/GLESv1.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "gles1_dec.h" + +struct GLESv1 : public gles1_decoder_context_t { + GLESv1(); +}; diff --git a/host/libs/virglrenderer/GLESv1_dec/gles1.addon b/host/libs/virglrenderer/GLESv1_dec/gles1.addon new file mode 100644 index 0000000000000000000000000000000000000000..2331f878c7a532e0ce8b609b04eeee0fdf066803 --- /dev/null +++ b/host/libs/virglrenderer/GLESv1_dec/gles1.addon @@ -0,0 +1,15 @@ +GL_ENTRY(void, glVertexPointerOffset, GLint size, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glColorPointerOffset, GLint size, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glNormalPointerOffset, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glPointSizePointerOffset, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glTexCoordPointerOffset, GLint size, GLenum type, GLsizei stride, GLuint offset) + +GL_ENTRY(void, glVertexPointerData, GLint size, GLenum type, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glColorPointerData, GLint size, GLenum type, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glNormalPointerData, GLenum type, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glTexCoordPointerData, GLint size, GLenum type, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glPointSizePointerData, GLenum type, GLsizei stride, void * data, GLuint datalen) + +GL_ENTRY(void, glDrawElementsOffset, GLenum mode, GLsizei count, GLenum type, GLuint offset); +GL_ENTRY(void, glDrawElementsData, GLenum mode, GLsizei count, GLenum type, void *data, GLuint datalen); + diff --git a/host/libs/virglrenderer/GLESv1_dec/gles1.attrib b/host/libs/virglrenderer/GLESv1_dec/gles1.attrib new file mode 100644 index 0000000000000000000000000000000000000000..a1f1ee7695480d670f1bf7c1e08247138630d5d2 --- /dev/null +++ b/host/libs/virglrenderer/GLESv1_dec/gles1.attrib @@ -0,0 +1,444 @@ +GLOBAL + base_opcode 1024 + +glClipPlanef + dir equation in + len equation (4 * sizeof(float)) + +glGetFloatv + dir params out + +glGetLightfv + dir params out + +glGetMaterialfv + dir params out + +glGetTexEnvfv + dir params out + +glGetTexParameterfv + dir params out + +glLoadMatrixf + len m (16 * sizeof(GLfloat)) + +glMultMatrixf + len m (16 * sizeof(GLfloat)) + +glBufferData + len data size + var_flag data nullAllowed + +glBufferSubData + dir data in + len data size + var_flag data nullAllowed + +glClipPlanex + dir eqn in + len eqn (4 * sizeof(GLfixed)) + +glColorPointer + len pointer (sizeof(unsigned int)) + flag unsupported + +glCompressedTexImage2D + len data imageSize + var_flag data nullAllowed + +glCompressedTexSubImage2D + len data imageSize + var_flag data nullAllowed + +glDeleteBuffers + len buffers (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDeleteTextures + len textures (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDrawElements + flag unsupported + +glGetBooleanv + dir params out + +glGetBufferParameteriv + len params (sizeof(GLint)) + dir params out + +glGenBuffers + len buffers (n * sizeof(GLuint)) + dir buffers out + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGenTextures + len textures (n * sizeof(GLuint)) + dir textures out + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGetFixedv + dir params out + +glGetIntegerv + dir params out + +glGetLightxv + dir params out + +glGetMaterialxv + dir params out + +glGetPointerv + flag unsupported + +glGetString + flag unsupported + +glGetTexEnviv + dir params out + +glGetTexEnvxv + dir params out + +glGetTexParameteriv + dir params out + len params (sizeof(GLint)) + +glGetTexParameterxv + dir params out + len params (sizeof(GLfixed)) + +glLoadMatrixx + len m (16 * sizeof(GLfixed)) + +glMultMatrixx + len m (16 * sizeof(GLfixed)) + +glNormalPointer + len pointer (sizeof(unsigned int)) + flag unsupported + +glReadPixels + dir pixels out + len pixels glesv1_enc::pixelDataSize(self, width, height, format, type, 1) + +glTexCoordPointer + len pointer (sizeof(unsigned int)) + flag unsupported + +glTexImage2D + dir pixels in + len pixels glesv1_enc::pixelDataSize(self, width, height, format, type, 0) + var_flag pixels nullAllowed isLarge + +glTexSubImage2D + len pixels glesv1_enc::pixelDataSize(self, width, height, format, type, 0) + var_flag pixels nullAllowed isLarge + +glVertexPointer + flag unsupported + +glPointSizePointerOES + len pointer (sizeof(unsigned int)) + flag unsupported + +glGetClipPlanef + dir eqn out + len eqn (4 * sizeof(GLfloat)) + +glVertexPointerData + len data datalen + flag not_api + +glColorPointerData + len data datalen + flag not_api + +glNormalPointerData + len data datalen + flag not_api + +glPointSizePointerData + len data datalen + flag not_api + +glTexCoordPointerData + len data datalen + flag not_api + +glWeightPointerData + len data datalen + flag not_api + +glMatrixIndexPointerData + len data datalen + flag not_api + +glVertexPointerOffset + flag not_api + +glNormalPointerOffset + flag not_api + +glTexCoordPointerOffset + flag not_api + +glPointSizePointerOffset + flag not_api + +glColorPointerOffset + flag not_api + +glWeightPointerOffset + flag not_api + +glMatrixIndexPointerOffset + flag not_api + +glDrawElementsData + len data datalen + flag not_api + +glDrawElementsOffset + flag not_api + +glGetCompressedTextureFormats + dir formats out + len formats (count * sizeof(GLint)) + flag not_api + +glFinishRoundTrip + flag not_api + +glDrawTexsvOES + len coords (5 * sizeof(GLshort)) + +glDrawTexivOES + len coords (5 * sizeof(GLint)) + +glDrawTexxvOES + len coords (5 * sizeof(GLfixed)) + +glDrawTexfvOES + len coords (5 * sizeof(GLfloat)) + +glClipPlanexOES + dir equation in + len equation (4 * sizeof(GLfixed)) + +glClipPlanexIMG + dir equation in + len equation (4 * sizeof(GLfixed)) + +glFogxvOES + dir params in + +glGetClipPlanexOES + dir eqn out + len eqn (4 * sizeof(GLfixed)) + +glGetClipPlanex + dir eqn out + len eqn (4 * sizeof(GLfixed)) + +glGetFixedvOES + dir params out + +glGetLightxvOES + dir params out + +glGetMaterialxvOES + dir params out + +glGetTexEnvxvOES + dir params out + +glGetTexParameterxvOES + dir params out + +glLightModelxvOES + dir params in + +glLightxvOES + dir params in + +glLoadMatrixxOES + dir m in + len m (16 * sizeof(GLfixed)) + +glMaterialxvOES + dir params in + +glMultMatrixxOES + dir m in + len m (16 * sizeof(GLfixed)) + +glPointParameterxvOES + dir params in + +glTexEnvxvOES + dir params in + +glTexParameterxvOES + dir params in + +glDeleteRenderbuffersOES + dir renderbuffers in + len renderbuffers (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGenRenderbuffersOES + dir renderbuffers out + len renderbuffers (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGetRenderbufferParameterivOES + dir params out + +glDeleteFramebuffersOES + dir framebuffers in + len framebuffers (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGenFramebuffersOES + dir framebuffers out + len framebuffers (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGetFramebufferAttachmentParameterivOES + dir params out + +glMapBufferOES + flag unsupported + +glGetBufferPointervOES + flag unsupported + +glMatrixIndexPointerOES + len pointer (sizeof(unsigned int)) + flag unsupported + +glWeightPointerOES + len pointer (sizeof(unsigned int)) + flag unsupported + +glQueryMatrixxOES + dir mantissa out + len mantissa (16 * sizeof(GLfixed)) + dir exponent out + len exponent (16 * sizeof(GLfixed)) + +glClipPlanefOES + dir equation in + len equation (4 * sizeof(GLfloat)) + +glClipPlanefIMG + dir equation in + len equation (4 * sizeof(GLfloat)) + +glGetClipPlanefOES + dir eqn out + len eqn (4 * sizeof(GLfloat)) + +glDeleteVertexArraysOES + dir arrays in + len arrays (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGenVertexArraysOES + dir arrays out + len arrays (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDiscardFramebufferEXT + dir attachments in + len attachments (numAttachments * sizeof(const GLenum)) + +glMultiDrawArraysEXT + flag unsupported + +glMultiDrawElementsEXT + flag unsupported + +glMultiDrawArraysSUN + flag unsupported + +glMultiDrawElementsSUN + flag unsupported + +glDeleteFencesNV + dir fences in + len fences (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGenFencesNV + dir fences in + len fences (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGetFenceivNV + dir params out + +glGetDriverControlsQCOM + dir num out + len num (1 * sizeof(GLint)) + dir driverControls out + len driverControls (size * sizeof(GLuint)) + +glGetDriverControlStringQCOM + dir length out + len length (1 * sizeof(GLsizei)) + dir driverControlString out + len driverControlString (1 * sizeof(GLchar)) + +glExtGetTexturesQCOM + dir textures out + len textures (maxTextures * sizeof(GLuint)) + dir numTextures out + len numTextures (1 * sizeof(GLint)) + +glExtGetBuffersQCOM + dir buffers out + len buffers (maxBuffers * sizeof(GLuint)) + dir numBuffers out + len numBuffers (1 * sizeof(GLint)) + +glExtGetRenderbuffersQCOM + dir renderbuffers out + len renderbuffers (maxRenderbuffers * sizeof(GLuint)) + dir numRenderbuffers out + len numRenderbuffers (1 * sizeof(GLint)) + +glExtGetFramebuffersQCOM + dir framebuffers out + len framebuffers (maxFramebuffers * sizeof(GLuint)) + dir numFramebuffers out + len numFramebuffers (1 * sizeof(GLint)) + +glExtGetTexLevelParameterivQCOM + dir params out + +glExtGetTexSubImageQCOM + dir texels out + len texels (depth * glesv1_enc::pixelDataSize(self, width, height, format, type, 0)) + +glExtGetBufferPointervQCOM + flag unsupported + +glExtGetShadersQCOM + dir shaders out + len shaders (maxShaders * sizeof(GLuint)) + dir numShaders out + len numShaders (1 * sizeof(GLint)) + +glExtGetProgramsQCOM + dir programs out + len programs (maxPrograms * sizeof(GLuint)) + dir numPrograms out + len numPrograms (1 * sizeof(GLint)) + +glExtGetProgramBinarySourceQCOM + flag unsupported diff --git a/host/libs/virglrenderer/GLESv1_dec/gles1.in b/host/libs/virglrenderer/GLESv1_dec/gles1.in new file mode 100644 index 0000000000000000000000000000000000000000..74d5454d38b77913d5238fef56957eabc89ebebe --- /dev/null +++ b/host/libs/virglrenderer/GLESv1_dec/gles1.in @@ -0,0 +1,298 @@ +GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref) +GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +GL_ENTRY(void, glClearDepthf, GLclampf depth) +GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat *equation) +GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar) +GL_ENTRY(void, glFogf, GLenum pname, GLfloat param) +GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glFrustumf, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glGetClipPlanef, GLenum pname, GLfloat* eqn) +GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetTexEnvfv, GLenum env, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params) +GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param) +GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param) +GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glLineWidth, GLfloat width) +GL_ENTRY(void, glLoadMatrixf, const GLfloat *m) +GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param) +GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glMultMatrixf, const GLfloat *m) +GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz) +GL_ENTRY(void, glOrthof, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param) +GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glPointSize, GLfloat size) +GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units) +GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glActiveTexture, GLenum texture) +GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref) +GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer) +GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture) +GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor) +GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) +GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) +GL_ENTRY(void, glClear, GLbitfield mask) +GL_ENTRY(void, glClearColorx, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) +GL_ENTRY(void, glClearDepthx, GLclampx depth) +GL_ENTRY(void, glClearStencil, GLint s) +GL_ENTRY(void, glClientActiveTexture, GLenum texture) +GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) +GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) +GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) +GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) +GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glCullFace, GLenum mode) +GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers) +GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures) +GL_ENTRY(void, glDepthFunc, GLenum func) +GL_ENTRY(void, glDepthMask, GLboolean flag) +GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar) +GL_ENTRY(void, glDisable, GLenum cap) +GL_ENTRY(void, glDisableClientState, GLenum array) +GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count) +GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) +GL_ENTRY(void, glEnable, GLenum cap) +GL_ENTRY(void, glEnableClientState, GLenum array) +GL_ENTRY(void, glFinish, void) +GL_ENTRY(void, glFlush, void) +GL_ENTRY(void, glFogx, GLenum pname, GLfixed param) +GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glFrontFace, GLenum mode) +GL_ENTRY(void, glFrustumx, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *params) +GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glClipPlanex, GLenum pname, const GLfixed * eqn) +GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers) +GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures) +GL_ENTRY(GLenum, glGetError, void) +GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *params) +GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetPointerv, GLenum pname, GLvoid **params) +GL_ENTRY(const GLubyte *, glGetString, GLenum name) +GL_ENTRY(void, glGetTexEnviv, GLenum env, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexEnvxv, GLenum env, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params) +GL_ENTRY(void, glHint, GLenum target, GLenum mode) +GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer) +GL_ENTRY(GLboolean, glIsEnabled, GLenum cap) +GL_ENTRY(GLboolean, glIsTexture, GLuint texture) +GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLineWidthx, GLfixed width) +GL_ENTRY(void, glLoadIdentity, void) +GL_ENTRY(void, glLoadMatrixx, const GLfixed *m) +GL_ENTRY(void, glLogicOp, GLenum opcode) +GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param) +GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glMatrixMode, GLenum mode) +GL_ENTRY(void, glMultMatrixx, const GLfixed *m) +GL_ENTRY(void, glMultiTexCoord4x, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) +GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz) +GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glOrthox, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param) +GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param) +GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glPointSizex, GLfixed size) +GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units) +GL_ENTRY(void, glPopMatrix, void) +GL_ENTRY(void, glPushMatrix, void) +GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) +GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert) +GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert) +GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glShadeModel, GLenum mode) +GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask) +GL_ENTRY(void, glStencilMask, GLuint mask) +GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass) +GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid *pointer) + +GL_ENTRY(void, glVertexPointerOffset, GLint size, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glColorPointerOffset, GLint size, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glNormalPointerOffset, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glPointSizePointerOffset, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glTexCoordPointerOffset, GLint size, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glWeightPointerOffset, GLint size, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glMatrixIndexPointerOffset, GLint size, GLenum type, GLsizei stride, GLuint offset) + +GL_ENTRY(void, glVertexPointerData, GLint size, GLenum type, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glColorPointerData, GLint size, GLenum type, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glNormalPointerData, GLenum type, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glTexCoordPointerData, GLint unit, GLint size, GLenum type, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glPointSizePointerData, GLenum type, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glWeightPointerData, GLint size, GLenum type, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glMatrixIndexPointerData, GLint size, GLenum type, GLsizei stride, void * data, GLuint datalen) + +GL_ENTRY(void, glDrawElementsOffset, GLenum mode, GLsizei count, GLenum type, GLuint offset) +GL_ENTRY(void, glDrawElementsData, GLenum mode, GLsizei count, GLenum type, void *data, GLuint datalen) +GL_ENTRY(void, glGetCompressedTextureFormats, int count, GLint *formats); + +GL_ENTRY(int, glFinishRoundTrip, void) + +#opengl extensions + +GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha) +GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +GL_ENTRY(void, glBlendEquationOES, GLenum mode) +GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height) +GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height) +GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height) +GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords) +GL_ENTRY(void, glDrawTexivOES, const GLint *coords) +GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords) +GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) +GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords) +GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image) +GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image) +GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref) +GL_ENTRY(void, glClearColorxOES, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) +GL_ENTRY(void, glClearDepthxOES, GLclampx depth) +GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed * equation) +GL_ENTRY(void, glClipPlanexIMG, GLenum plane, const GLfixed * equation) +GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) +GL_ENTRY(void, glDepthRangexOES, GLclampx zNear, GLclampx zFar) +GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param) +GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glFrustumxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glGetClipPlanexOES, GLenum pname, GLfixed* eqn) +GL_ENTRY(void, glGetClipPlanex, GLenum pname, GLfixed* eqn) +GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetTexEnvxvOES, GLenum env, GLenum pname, GLfixed *params) +GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params) +GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param) +GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glLineWidthxOES, GLfixed width) +GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m) +GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param) +GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m) +GL_ENTRY(void, glMultiTexCoord4xOES, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) +GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz) +GL_ENTRY(void, glOrthoxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) +GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param) +GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glPointSizexOES, GLfixed size) +GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units) +GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert) +GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z) +GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer) +GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer) +GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers) +GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers) +GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params) +GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer) +GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer) +GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint* framebuffers) +GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint* framebuffers) +GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target) +GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint* params) +GL_ENTRY(void, glGenerateMipmapOES, GLenum target) +GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access) +GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target) +GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, GLvoid* *params) +GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex) +GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void) +GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) +GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) +GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed * mantissa, GLint * exponent) +GL_ENTRY(void, glDepthRangefOES, GLclampf zNear, GLclampf zFar) +GL_ENTRY(void, glFrustumfOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glOrthofOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) +GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation) +GL_ENTRY(void, glClipPlanefIMG, GLenum plane, const GLfloat *equation) +GL_ENTRY(void, glGetClipPlanefOES, GLenum pname, GLfloat * eqn) +GL_ENTRY(void, glClearDepthfOES, GLclampf depth) +GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param) +GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param) +GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params) +GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params) +GL_ENTRY(void, glBindVertexArrayOES, GLuint array) +GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays) +GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays) +GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array) +GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments) +GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) +GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const GLvoid*const *indices, GLsizei primcount) +GL_ENTRY(void, glMultiDrawArraysSUN, GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) +GL_ENTRY(void, glMultiDrawElementsSUN, GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount) +GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) +GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences) +GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences) +GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence) +GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence) +GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params) +GL_ENTRY(void, glFinishFenceNV, GLuint fence) +GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition) +GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls) +GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString) +GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl) +GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl) +GL_ENTRY(void, glExtGetTexturesQCOM, GLuint *textures, GLint maxTextures, GLint *numTextures) +GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers) +GL_ENTRY(void, glExtGetRenderbuffersQCOM, GLuint * renderbuffers, GLint maxRenderbuffers, GLint * numRenderbuffers) +GL_ENTRY(void, glExtGetFramebuffersQCOM, GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers) +GL_ENTRY(void, glExtGetTexLevelParameterivQCOM, GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params) +GL_ENTRY(void, glExtTexObjectStateOverrideiQCOM, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glExtGetTexSubImageQCOM, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels) +GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, GLvoid* *params) +GL_ENTRY(void, glExtGetShadersQCOM, GLuint *shaders, GLint maxShaders, GLint *numShaders) +GL_ENTRY(void, glExtGetProgramsQCOM, GLuint *programs, GLint maxPrograms, GLint *numPrograms) +GL_ENTRY(GLboolean, glExtIsProgramBinaryQCOM, GLuint program) +GL_ENTRY(void, glExtGetProgramBinarySourceQCOM, GLuint program, GLenum shadertype, GLchar *source, GLint *length) +GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) +GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask) diff --git a/host/libs/virglrenderer/GLESv1_dec/gles1.types b/host/libs/virglrenderer/GLESv1_dec/gles1.types new file mode 100644 index 0000000000000000000000000000000000000000..05be29e5e4f9f9f54abbaf9ea593b22a7b09cfa5 --- /dev/null +++ b/host/libs/virglrenderer/GLESv1_dec/gles1.types @@ -0,0 +1,34 @@ +GLbitfield 32 0x%08x +GLboolean 8 %d +GLclampf 32 %f +GLclampx 32 0x%08x +GLeglImageOES 32 %p +GLenum 32 0x%08x +GLfixed 32 0x%08x +GLfloat 32 %f +GLint 32 %d +GLintptr 32 0x%08lx +GLshort 16 %d +GLsizei 32 %d +GLsizeiptr 32 0x%08lx +GLubyte 8 0x%02x +GLuint 32 %u +GLvoid 0 %x +GLchar 8 %d +GLenum* 32 0x%08x +GLboolean* 32 0x%08x +GLclampf* 32 0x%08x +GLclampx* 32 0x%08x +GLeglImageOES* 32 0x%08x +GLfixed* 32 0x%08x +GLfloat* 32 0x%08x +GLint* 32 0x%08x +GLshort* 32 0x%08x +GLsizei* 32 0x%08x +GLubyte* 32 0x%08x +GLuint* 32 0x%08x +GLvoid* 32 0x%08x +GLchar* 32 0x%08x +GLvoid** 32 0x%08x +void* 32 0x%08x +GLvoid*const* 32 0x%08x diff --git a/host/libs/virglrenderer/GLESv1_dec/gles1_types.h b/host/libs/virglrenderer/GLESv1_dec/gles1_types.h new file mode 100644 index 0000000000000000000000000000000000000000..097e03f71086e527caa16c6bea45bf4b9380a76f --- /dev/null +++ b/host/libs/virglrenderer/GLESv1_dec/gles1_types.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <GLES/gl.h> +#include <GLES/glext.h> diff --git a/host/libs/virglrenderer/GLESv3.cpp b/host/libs/virglrenderer/GLESv3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd2707d17c213f6b674517c2eba7c7ee690ea832 --- /dev/null +++ b/host/libs/virglrenderer/GLESv3.cpp @@ -0,0 +1,642 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <OpenGLESDispatch/GLESv3Dispatch.h> + +#include "GLESv3.h" + +#include <string> +#include <vector> + +// Stubs (common) + +static void glDeleteFencesNV(GLsizei, const GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glDisableDriverControlQCOM(GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glDiscardFramebufferEXT(GLenum, GLsizei, const GLenum*) { + printf("%s: not implemented\n", __func__); +} + +static void glEnableDriverControlQCOM(GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glEndTilingQCOM(GLbitfield) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetBufferPointervQCOM(GLenum, GLvoid**) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetBuffersQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetFramebuffersQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetProgramBinarySourceQCOM(GLuint, GLenum, GLchar*, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetProgramsQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetRenderbuffersQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetShadersQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetTexLevelParameterivQCOM(GLuint, GLenum, GLint, GLenum, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetTexSubImageQCOM(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, + GLenum, GLenum, GLvoid*) { + printf("%s: not implemented\n", __func__); +} + +static void glExtGetTexturesQCOM(GLuint*, GLint, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static GLboolean glExtIsProgramBinaryQCOM(GLuint) { + printf("%s: not implemented\n", __func__); + return GL_FALSE; +} + +static void glExtTexObjectStateOverrideiQCOM(GLenum, GLenum, GLint) { + printf("%s: not implemented\n", __func__); +} + +static void glFinishFenceNV(GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glFramebufferTexture2DMultisampleIMG(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei) { + printf("%s: not implemented\n", __func__); +} + +static void glGenFencesNV(GLsizei, GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetDriverControlsQCOM(GLint*, GLsizei, GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetDriverControlStringQCOM(GLuint, GLsizei, GLsizei*, GLchar*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetFenceivNV(GLuint, GLenum, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static GLboolean glIsFenceNV(GLuint) { + printf("%s: not implemented\n", __func__); + return GL_FALSE; +} + +static void* glMapBufferOES(GLenum, GLenum) { + printf("%s: not implemented\n", __func__); + return nullptr; +} + +static void glMultiDrawArraysEXT(GLenum, const GLint*, const GLsizei*, GLsizei) { + printf("%s: not implemented\n", __func__); +} + +static void glMultiDrawElementsEXT(GLenum, const GLsizei*, GLenum, const GLvoid* const*, GLsizei) { + printf("%s: not implemented\n", __func__); +} + +static void glRenderbufferStorageMultisampleIMG(GLenum, GLsizei, GLenum, GLsizei, GLsizei) { + printf("%s: not implemented\n", __func__); +} + +static void glSetFenceNV(GLuint, GLenum) { + printf("%s: not implemented\n", __func__); +} + +static void glStartTilingQCOM(GLuint, GLuint, GLuint, GLuint, GLbitfield) { + printf("%s: not implemented\n", __func__); +} + +static GLboolean glTestFenceNV(GLuint) { + printf("%s: not implemented\n", __func__); + return GL_FALSE; +} + +// Stubs (ES 3.1) + +static void glBeginPerfMonitorAMD(GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glCoverageMaskNV(GLboolean) { + printf("%s: not implemented\n", __func__); +} + +static void glCoverageOperationNV(GLenum) { + printf("%s: not implemented\n", __func__); +} + +static void glDeletePerfMonitorsAMD(GLsizei, GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glEndPerfMonitorAMD(GLuint) { + printf("%s: not implemented\n", __func__); +} + +static void glGenPerfMonitorsAMD(GLsizei, GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetPerfMonitorCounterDataAMD(GLuint, GLenum, GLsizei, GLuint*, GLint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetPerfMonitorCounterInfoAMD(GLuint, GLuint, GLenum, GLvoid*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetPerfMonitorCountersAMD(GLuint, GLint*, GLint*, GLsizei, GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetPerfMonitorCounterStringAMD(GLuint, GLuint, GLsizei, GLsizei*, GLchar*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetPerfMonitorGroupsAMD(GLint*, GLsizei, GLuint*) { + printf("%s: not implemented\n", __func__); +} + +static void glGetPerfMonitorGroupStringAMD(GLuint, GLsizei, GLsizei*, GLchar*) { + printf("%s: not implemented\n", __func__); +} + +static void glSelectPerfMonitorCountersAMD(GLuint, GLboolean, GLuint, GLint, GLuint*) { + printf("%s: not implemented\n", __func__); +} + +// Non-stubs (common) + +static void glDrawElementsData(GLenum mode, GLsizei count, GLenum type, void* indices, GLuint) { + s_gles3.glDrawElements(mode, count, type, indices); +} + +static void glDrawElementsOffset(GLenum mode, GLsizei count, GLenum type, GLuint offset) { + s_gles3.glDrawElements(mode, count, type, reinterpret_cast<const GLvoid*>(offset)); +} + +static GLint glFinishRoundTrip() { + s_gles3.glFinish(); + return 0; +} + +static void glGetCompressedTextureFormats(int count, GLint* formats) { + int nFormats; + s_gles3.glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &nFormats); + if (nFormats <= count) + s_gles3.glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats); +} + +// Non-stubs (ES 3.1) + +struct GlSync { + GlSync(GLESv3* ctx_, GLsync sync_) : sync(sync_), id(ctx_->sync_nextId++), ctx(ctx_) { + ctx->sync_map.emplace(id, this); + } + + ~GlSync() { + ctx->sync_map.erase(id); + } + + GLsync sync; + uint64_t id; + + private: + GLESv3* ctx; +}; + +static GLenum glClientWaitSyncAEMU(void* ctx_, uint64_t wait_on, GLbitfield flags, + GLuint64 timeout) { + GLESv3* ctx = static_cast<GLESv3*>(ctx_); + + std::map<uint64_t, GlSync*>::iterator it; + it = ctx->sync_map.find(wait_on); + if (it == ctx->sync_map.end()) + return GL_INVALID_VALUE; + + GlSync* sync = it->second; + return s_gles3.glClientWaitSync(sync->sync, flags, timeout); +} + +static void glCompressedTexImage2DOffsetAEMU(GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLint border, + GLsizei imageSize, GLuint offset) { + s_gles3.glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, + reinterpret_cast<const GLvoid*>(offset)); +} + +static void glCompressedTexImage3DOffsetAEMU(GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLsizei imageSize, GLuint offset) { + s_gles3.glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, + imageSize, reinterpret_cast<const GLvoid*>(offset)); +} + +static void glCompressedTexSubImage2DOffsetAEMU(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, GLuint offset) { + s_gles3.glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, + imageSize, reinterpret_cast<const GLvoid*>(offset)); +} + +static void glCompressedTexSubImage3DOffsetAEMU(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, GLuint offset) { + s_gles3.glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, + format, imageSize, reinterpret_cast<const GLvoid*>(offset)); +} + +static GLuint glCreateShaderProgramvAEMU(GLenum type, GLsizei, const char* packedStrings, GLuint) { + return s_gles3.glCreateShaderProgramv(type, 1, &packedStrings); +} + +static void glDeleteSyncAEMU(void* ctx_, uint64_t to_delete) { + GLESv3* ctx = static_cast<GLESv3*>(ctx_); + + std::map<uint64_t, GlSync*>::iterator it; + it = ctx->sync_map.find(to_delete); + if (it == ctx->sync_map.end()) + return; + + GlSync* sync = it->second; + s_gles3.glDeleteSync(sync->sync); + delete sync; +} + +static void glDrawArraysIndirectDataAEMU(GLenum mode, const void* indirect, GLuint) { + s_gles3.glDrawArraysIndirect(mode, indirect); +} + +static void glDrawArraysIndirectOffsetAEMU(GLenum mode, GLuint offset) { + s_gles3.glDrawArraysIndirect(mode, reinterpret_cast<const void*>(offset)); +} + +static void glDrawElementsIndirectDataAEMU(GLenum mode, GLenum type, const void* indirect, GLuint) { + s_gles3.glDrawElementsIndirect(mode, type, indirect); +} + +static void glDrawElementsIndirectOffsetAEMU(GLenum mode, GLenum type, GLuint offset) { + s_gles3.glDrawElementsIndirect(mode, type, reinterpret_cast<const void*>(offset)); +} + +static void glDrawElementsInstancedDataAEMU(GLenum mode, GLsizei count, GLenum type, + const void* indices, GLsizei primcount, GLsizei) { + s_gles3.glDrawElementsInstanced(mode, count, type, indices, primcount); +} + +static void glDrawElementsInstancedOffsetAEMU(GLenum mode, GLsizei count, GLenum type, + GLuint offset, GLsizei primcount) { + s_gles3.glDrawElementsInstanced(mode, count, type, reinterpret_cast<const void*>(offset), + primcount); +} + +static void glDrawRangeElementsDataAEMU(GLenum mode, GLuint start, GLuint end, GLsizei count, + GLenum type, const GLvoid* indices, GLsizei) { + s_gles3.glDrawRangeElements(mode, start, end, count, type, indices); +} + +static void glDrawRangeElementsOffsetAEMU(GLenum mode, GLuint start, GLuint end, GLsizei count, + GLenum type, GLuint offset) { + s_gles3.glDrawRangeElements(mode, start, end, count, type, + reinterpret_cast<const GLvoid*>(offset)); +} + +static uint64_t glFenceSyncAEMU(void* ctx_, GLenum condition, GLbitfield flags) { + GLsync sync_ = s_gles3.glFenceSync(condition, flags); + if (sync_ == 0) + return 0U; + + GLESv3* ctx = static_cast<GLESv3*>(ctx_); + GlSync* sync = new (std::nothrow) GlSync(ctx, sync_); + if (!sync) { + s_gles3.glDeleteSync(sync_); + return 0U; + } + + return sync->id; +} + +static void glFlushMappedBufferRangeAEMU(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access, void* guest_buffer) { + if (guest_buffer && length) { + void* gpuPtr = s_gles3.glMapBufferRange(target, offset, length, access); + if (gpuPtr) { + memcpy(gpuPtr, guest_buffer, length); + s_gles3.glFlushMappedBufferRange(target, 0, length); + s_gles3.glUnmapBuffer(target); + } + } +} + +static void glGetSyncivAEMU(void* ctx_, uint64_t sync_, GLenum pname, GLsizei bufSize, + GLsizei* length, GLint* values) { + GLESv3* ctx = static_cast<GLESv3*>(ctx_); + + std::map<uint64_t, GlSync*>::iterator it; + it = ctx->sync_map.find(sync_); + if (it == ctx->sync_map.end()) + return; + + GlSync* sync = it->second; + s_gles3.glGetSynciv(sync->sync, pname, bufSize, length, values); +} + +static std::vector<std::string> sUnpackVarNames(GLsizei count, const char* packedNames) { + std::vector<std::string> unpacked; + GLsizei current = 0; + + while (current < count) { + const char* delimPos = strstr(packedNames, ";"); + size_t nameLen = delimPos - packedNames; + std::string next; + next.resize(nameLen); + memcpy(&next[0], packedNames, nameLen); + unpacked.push_back(next); + packedNames = delimPos + 1; + current++; + } + + return unpacked; +} + +static void glGetUniformIndicesAEMU(GLuint program, GLsizei uniformCount, const GLchar* packedNames, + GLsizei packedLen, GLuint* uniformIndices) { + std::vector<std::string> unpacked = sUnpackVarNames(uniformCount, packedNames); + GLchar** unpackedArray = new GLchar*[unpacked.size()]; + GLsizei i = 0; + for (auto& elt : unpacked) { + unpackedArray[i] = (GLchar*)&elt[0]; + i++; + } + + s_gles3.glGetUniformIndices(program, uniformCount, const_cast<const GLchar**>(unpackedArray), + uniformIndices); + delete[] unpackedArray; +} + +static GLboolean glIsSyncAEMU(void* ctx_, uint64_t sync) { + GLESv3* ctx = static_cast<GLESv3*>(ctx_); + return ctx->sync_map.count(sync) ? GL_TRUE : GL_FALSE; +} + +static void glMapBufferRangeAEMU(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access, void* mapped) { + if ((access & GL_MAP_READ_BIT) || + ((access & GL_MAP_WRITE_BIT) && + (!(access & GL_MAP_INVALIDATE_RANGE_BIT) && !(access & GL_MAP_INVALIDATE_BUFFER_BIT)))) { + void* gpuPtr = s_gles3.glMapBufferRange(target, offset, length, access); + if (gpuPtr) { + if (mapped) + memcpy(mapped, gpuPtr, length); + s_gles3.glUnmapBuffer(target); + } + } +} + +static void glReadPixelsOffsetAEMU(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint offset) { + s_gles3.glReadPixels(x, y, width, height, format, type, reinterpret_cast<GLvoid*>(offset)); +} + +static void glShaderString(GLuint shader, const GLchar* string, GLsizei) { + s_gles3.glShaderSource(shader, 1, &string, NULL); +} + +static void glTexImage2DOffsetAEMU(GLenum target, GLint level, GLint internalformat, GLsizei width, + GLsizei height, GLint border, GLenum format, GLenum type, + GLuint offset) { + s_gles3.glTexImage2D(target, level, internalformat, width, height, border, format, type, + reinterpret_cast<const GLvoid*>(offset)); +} + +static void glTexImage3DOffsetAEMU(GLenum target, GLint level, GLint internalFormat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, GLenum format, + GLenum type, GLuint offset) { + s_gles3.glTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, + reinterpret_cast<const GLvoid*>(offset)); +} + +static void glTexSubImage2DOffsetAEMU(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLenum type, + GLuint offset) { + s_gles3.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, + reinterpret_cast<const GLvoid*>(offset)); +} + +static void glTexSubImage3DOffsetAEMU(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, GLuint offset) { + s_gles3.glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, + type, reinterpret_cast<const GLvoid*>(offset)); +} + +static void glTransformFeedbackVaryingsAEMU(GLuint program, GLsizei count, + const char* packedVaryings, GLuint packedVaryingsLen, + GLenum bufferMode) { + std::vector<std::string> unpacked = sUnpackVarNames(count, packedVaryings); + char** unpackedArray = new char*[unpacked.size()]; + GLsizei i = 0; + for (auto& elt : unpacked) { + unpackedArray[i] = &elt[0]; + i++; + } + + s_gles3.glTransformFeedbackVaryings(program, count, const_cast<const char**>(unpackedArray), + bufferMode); + delete[] unpackedArray; +} + +static void glUnmapBufferAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, + void* guest_buffer, GLboolean* out_res) { + *out_res = GL_TRUE; + + if (access & GL_MAP_WRITE_BIT) { + if (guest_buffer) { + void* gpuPtr = s_gles3.glMapBufferRange(target, offset, length, access); + if (gpuPtr) + memcpy(gpuPtr, guest_buffer, length); + } + + *out_res = s_gles3.glUnmapBuffer(target); + } +} + +static void glVertexAttribIPointerDataAEMU(GLuint index, GLint size, GLenum type, GLsizei, + void* data, GLuint) { + s_gles3.glVertexAttribIPointer(index, size, type, 0, data); +} + +static void glVertexAttribIPointerOffsetAEMU(GLuint index, GLint size, GLenum type, GLsizei, + GLuint offset) { + s_gles3.glVertexAttribIPointer(index, size, type, 0, reinterpret_cast<const GLvoid*>(offset)); +} + +static void glVertexAttribPointerData(GLuint indx, GLint size, GLenum type, GLboolean normalized, + GLsizei, void* data, GLuint) { + s_gles3.glVertexAttribPointer(indx, size, type, normalized, 0, data); +} + +static void glVertexAttribPointerOffset(GLuint indx, GLint size, GLenum type, GLboolean normalized, + GLsizei, GLuint offset) { + s_gles3.glVertexAttribPointer(indx, size, type, normalized, 0, + reinterpret_cast<const GLvoid*>(offset)); +} + +static void glWaitSyncAEMU(void* ctx_, uint64_t wait_on, GLbitfield flags, GLuint64 timeout) { + GLESv3* ctx = static_cast<GLESv3*>(ctx_); + + std::map<uint64_t, GlSync*>::iterator it; + it = ctx->sync_map.find(wait_on); + if (it == ctx->sync_map.end()) + return; + + GlSync* sync = it->second; + s_gles3.glWaitSync(sync->sync, flags, timeout); +} + +#define KNIT(return_type, function_name, signature, callargs) function_name = s_gles3.function_name; + +GLESv3::GLESv3() { + LIST_GLES3_FUNCTIONS(KNIT, KNIT) + + // Remap some ES 2.0 extensions that become core in ES 3.1 + glBindVertexArrayOES = glBindVertexArray; + glDeleteVertexArraysOES = glDeleteVertexArrays; + glGenVertexArraysOES = glGenVertexArrays; + glGetProgramBinaryOES = glGetProgramBinary; + glIsVertexArrayOES = glIsVertexArray; + glProgramBinaryOES = glProgramBinary; + glUnmapBufferOES = glUnmapBuffer; + + // Entrypoints requiring custom wrappers (common) + glDrawElementsData = ::glDrawElementsData; + glDrawElementsOffset = ::glDrawElementsOffset; + glFinishRoundTrip = ::glFinishRoundTrip; + glGetCompressedTextureFormats = ::glGetCompressedTextureFormats; + + // Entrypoints requiring custom wrappers (ES 3.1) + glClientWaitSyncAEMU = ::glClientWaitSyncAEMU; + glCompressedTexImage2DOffsetAEMU = ::glCompressedTexImage2DOffsetAEMU; + glCompressedTexImage3DOffsetAEMU = ::glCompressedTexImage3DOffsetAEMU; + glCompressedTexSubImage2DOffsetAEMU = ::glCompressedTexSubImage2DOffsetAEMU; + glCompressedTexSubImage3DOffsetAEMU = ::glCompressedTexSubImage3DOffsetAEMU; + glCreateShaderProgramvAEMU = ::glCreateShaderProgramvAEMU; + glDeleteSyncAEMU = ::glDeleteSyncAEMU; + glDrawArraysIndirectDataAEMU = ::glDrawArraysIndirectDataAEMU; + glDrawArraysIndirectOffsetAEMU = ::glDrawArraysIndirectOffsetAEMU; + glDrawElementsIndirectDataAEMU = ::glDrawElementsIndirectDataAEMU; + glDrawElementsIndirectOffsetAEMU = ::glDrawElementsIndirectOffsetAEMU; + glDrawElementsInstancedDataAEMU = ::glDrawElementsInstancedDataAEMU; + glDrawElementsInstancedOffsetAEMU = ::glDrawElementsInstancedOffsetAEMU; + glDrawRangeElementsDataAEMU = ::glDrawRangeElementsDataAEMU; + glDrawRangeElementsOffsetAEMU = ::glDrawRangeElementsOffsetAEMU; + glFenceSyncAEMU = ::glFenceSyncAEMU; + glFlushMappedBufferRangeAEMU = ::glFlushMappedBufferRangeAEMU; + glGetSyncivAEMU = ::glGetSyncivAEMU; + glGetUniformIndicesAEMU = ::glGetUniformIndicesAEMU; + glIsSyncAEMU = ::glIsSyncAEMU; + glMapBufferRangeAEMU = ::glMapBufferRangeAEMU; + glReadPixelsOffsetAEMU = ::glReadPixelsOffsetAEMU; + glShaderString = ::glShaderString; + glTexImage2DOffsetAEMU = ::glTexImage2DOffsetAEMU; + glTexImage3DOffsetAEMU = ::glTexImage3DOffsetAEMU; + glTexSubImage2DOffsetAEMU = ::glTexSubImage2DOffsetAEMU; + glTexSubImage3DOffsetAEMU = ::glTexSubImage3DOffsetAEMU; + glTransformFeedbackVaryingsAEMU = ::glTransformFeedbackVaryingsAEMU; + glUnmapBufferAEMU = ::glUnmapBufferAEMU; + glVertexAttribIPointerDataAEMU = ::glVertexAttribIPointerDataAEMU; + glVertexAttribIPointerOffsetAEMU = ::glVertexAttribIPointerOffsetAEMU; + glVertexAttribPointerData = ::glVertexAttribPointerData; + glVertexAttribPointerOffset = ::glVertexAttribPointerOffset; + glWaitSyncAEMU = ::glWaitSyncAEMU; + + // Stub some extensions we will never implement (common) + glDeleteFencesNV = ::glDeleteFencesNV; + glDisableDriverControlQCOM = ::glDisableDriverControlQCOM; + glDiscardFramebufferEXT = ::glDiscardFramebufferEXT; + glEnableDriverControlQCOM = ::glEnableDriverControlQCOM; + glEndTilingQCOM = ::glEndTilingQCOM; + glExtGetBufferPointervQCOM = ::glExtGetBufferPointervQCOM; + glExtGetBuffersQCOM = ::glExtGetBuffersQCOM; + glExtGetFramebuffersQCOM = ::glExtGetFramebuffersQCOM; + glExtGetProgramBinarySourceQCOM = ::glExtGetProgramBinarySourceQCOM; + glExtGetProgramsQCOM = ::glExtGetProgramsQCOM; + glExtGetRenderbuffersQCOM = ::glExtGetRenderbuffersQCOM; + glExtGetShadersQCOM = ::glExtGetShadersQCOM; + glExtGetTexLevelParameterivQCOM = ::glExtGetTexLevelParameterivQCOM; + glExtGetTexSubImageQCOM = ::glExtGetTexSubImageQCOM; + glExtGetTexturesQCOM = ::glExtGetTexturesQCOM; + glExtIsProgramBinaryQCOM = ::glExtIsProgramBinaryQCOM; + glExtTexObjectStateOverrideiQCOM = ::glExtTexObjectStateOverrideiQCOM; + glFinishFenceNV = ::glFinishFenceNV; + glFramebufferTexture2DMultisampleIMG = ::glFramebufferTexture2DMultisampleIMG; + glGenFencesNV = ::glGenFencesNV; + glGetDriverControlsQCOM = ::glGetDriverControlsQCOM; + glGetDriverControlStringQCOM = ::glGetDriverControlStringQCOM; + glGetFenceivNV = ::glGetFenceivNV; + glIsFenceNV = ::glIsFenceNV; + glMapBufferOES = ::glMapBufferOES; + glMultiDrawArraysEXT = ::glMultiDrawArraysEXT; + glMultiDrawElementsEXT = ::glMultiDrawElementsEXT; + glRenderbufferStorageMultisampleIMG = ::glRenderbufferStorageMultisampleIMG; + glSetFenceNV = ::glSetFenceNV; + glStartTilingQCOM = ::glStartTilingQCOM; + glTestFenceNV = ::glTestFenceNV; + + // Stub some extensions we will never implement (ES 3.1) + glBeginPerfMonitorAMD = ::glBeginPerfMonitorAMD; + glCoverageMaskNV = ::glCoverageMaskNV; + glCoverageOperationNV = ::glCoverageOperationNV; + glDeletePerfMonitorsAMD = ::glDeletePerfMonitorsAMD; + glEndPerfMonitorAMD = ::glEndPerfMonitorAMD; + glGenPerfMonitorsAMD = ::glGenPerfMonitorsAMD; + glGetPerfMonitorCounterDataAMD = ::glGetPerfMonitorCounterDataAMD; + glGetPerfMonitorCounterInfoAMD = ::glGetPerfMonitorCounterInfoAMD; + glGetPerfMonitorCountersAMD = ::glGetPerfMonitorCountersAMD; + glGetPerfMonitorCounterStringAMD = ::glGetPerfMonitorCounterStringAMD; + glGetPerfMonitorGroupsAMD = ::glGetPerfMonitorGroupsAMD; + glGetPerfMonitorGroupStringAMD = ::glGetPerfMonitorGroupStringAMD; + glSelectPerfMonitorCountersAMD = ::glSelectPerfMonitorCountersAMD; +} diff --git a/host/libs/virglrenderer/GLESv3.h b/host/libs/virglrenderer/GLESv3.h new file mode 100644 index 0000000000000000000000000000000000000000..a0778533c1760dc10dd173c1464ac56515dc7883 --- /dev/null +++ b/host/libs/virglrenderer/GLESv3.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "gles3_dec.h" + +#include <map> + +struct GlSync; + +struct GLESv3 : public gles3_decoder_context_t { + GLESv3(); + + glDrawBuffers_server_proc_t glDrawBuffersEXT; + + glDrawArraysInstanced_server_proc_t glDrawArraysInstancedEXT; + glDrawElementsInstanced_server_proc_t glDrawElementsInstancedEXT; + + glVertexAttribDivisor_server_proc_t glVertexAttribDivisorEXT; + + std::map<uint64_t, GlSync*> sync_map; + + private: + uint64_t sync_nextId = 1U; + friend struct GlSync; +}; diff --git a/host/libs/virglrenderer/GLESv3_dec/gles3.attrib b/host/libs/virglrenderer/GLESv3_dec/gles3.attrib new file mode 100644 index 0000000000000000000000000000000000000000..d5d8d18360b1b76afec83a497ba8b977f2c6b9cf --- /dev/null +++ b/host/libs/virglrenderer/GLESv3_dec/gles3.attrib @@ -0,0 +1,967 @@ +GLOBAL + base_opcode 2048 + +glBindAttribLocation + len name (strlen(name) + 1) + +glBufferData + len data size + var_flag data nullAllowed isLarge + +glBufferSubData + len data size + var_flag data nullAllowed isLarge + +glCompressedTexImage2D + len data imageSize + param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + var_flag data nullAllowed isLarge + param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glCompressedTexSubImage2D + len data imageSize + param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + var_flag data nullAllowed isLarge + param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDeleteBuffers + len buffers (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDeleteFramebuffers + len framebuffers (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDeleteRenderbuffers + len renderbuffers (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDeleteTextures + len textures (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDrawElements + flag unsupported + +glGenBuffers + len buffers (n * sizeof(GLuint)) + dir buffers out + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGenFramebuffers + len framebuffers (n * sizeof(GLuint)) + dir framebuffers out + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGenRenderbuffers + len renderbuffers (n * sizeof(GLuint)) + dir renderbuffers out + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGenTextures + len textures (n * sizeof(GLuint)) + dir textures out + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGetActiveAttrib + param_check bufsize if(bufsize<0){ ctx->setError(GL_INVALID_VALUE); return; } + len name bufsize + dir name out + var_flag name nullAllowed + dir length out + len length (sizeof(GLsizei)) + var_flag length nullAllowed + dir size out + len size (sizeof(GLint)) + var_flag size nullAllowed + dir type out + len type (sizeof(GLenum)) + var_flag type nullAllowed + +glGetActiveUniform + param_check bufsize if(bufsize<0){ ctx->setError(GL_INVALID_VALUE); return; } + len name bufsize + dir name out + var_flag name nullAllowed + dir length out + len length (sizeof(GLsizei)) + var_flag length nullAllowed + dir size out + len size (sizeof(GLint)) + var_flag size nullAllowed + dir type out + len type (sizeof(GLenum)) + var_flag type nullAllowed + +glGetAttachedShaders + len shaders (maxcount*sizeof(GLuint)) + dir shaders out + dir count out + var_flag count nullAllowed + len count (sizeof(GLsizei)) + +glGetAttribLocation + len name (strlen(name) + 1) + +glGetBooleanv + dir params out + +glGetBufferParameteriv + len params (sizeof(GLint)) + dir params out + +glGetFloatv + dir params out + +glGetFramebufferAttachmentParameteriv + dir params out + len params (sizeof(GLint)) + +glGetIntegerv + dir params out + +glGetProgramiv + dir params out + +glGetProgramInfoLog + dir infolog out + len infolog bufsize + param_check bufsize if(bufsize<0){ ctx->setError(GL_INVALID_VALUE); return; } + dir length out + len length sizeof(GLsizei) + var_flag length nullAllowed + +glGetRenderbufferParameteriv + dir params out + len params sizeof(GLint) + +glGetShaderiv + dir params out + len params sizeof(GLint) + +glGetShaderInfoLog + dir length out + len length (sizeof(GLsizei)) + var_flag length nullAllowed + dir infolog out + len infolog bufsize + param_check bufsize if(bufsize<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGetShaderPrecisionFormat + dir range out + len range (2 * sizeof(GLint)) + dir precision out + len precision (sizeof(GLint)) + +glGetShaderSource + dir length out + len length (sizeof(GLsizei)) + var_flag length nullAllowed + dir source out + len source bufsize + param_check bufsize if(bufsize<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGetString + flag unsupported + +glGetTexParameterfv + dir params out + +glGetTexParameteriv + dir params out + +glGetUniformfv + dir params out + len params glSizeof(glesv2_enc::uniformType(self, program, location)) + +glGetUniformiv + dir params out + len params glSizeof(glesv2_enc::uniformType(self, program, location)) + +glGetUniformLocation + len name (strlen(name) + 1) + +glGetVertexAttribfv + dir params out + +glGetVertexAttribiv + dir params out + +glReadPixels + dir pixels out + len pixels glesv2_enc::pixelDataSize(self, width, height, format, type, 1) + +glReadPixelsOffsetAEMU + flag not_api + +glShaderBinary + flag unsupported + +glTexImage2D + dir pixels in + len pixels glesv2_enc::pixelDataSize(self, width, height, format, type, 0) + var_flag pixels nullAllowed isLarge + +glTexSubImage2D + len pixels glesv2_enc::pixelDataSize(self, width, height, format, type, 0) + var_flag pixels nullAllowed isLarge + +glUniform1fv + len v (count * sizeof(GLfloat)) + +glUniform1iv + len v (count * sizeof(GLint)) + +glUniform2fv + len v (count * 2 * sizeof(GLfloat)) + +glUniform2iv + len v (count * 2 * sizeof(GLint)) + +glUniform3fv + len v (count * 3 * sizeof(GLfloat)) + +glUniform3iv + len v (3 * count * sizeof(GLint)) + +glUniform4fv + len v (4 * count * sizeof(GLfloat)) + +glUniform4iv + len v (4 * count * sizeof(GLint)) + +glUniformMatrix2fv + len value (count * 4 * sizeof(GLfloat)) + +glUniformMatrix3fv + len value (count * 9 * sizeof(GLfloat)) + +glUniformMatrix4fv + len value (count * 16 * sizeof(GLfloat)) + +glVertexAttrib1fv + len values (sizeof(GLfloat)) +glVertexAttrib2fv + len values (2 * sizeof(GLfloat)) + +glVertexAttrib3fv + len values (3 * sizeof(GLfloat)) + +glVertexAttrib4fv + len values (4 * sizeof(GLfloat)) + +glVertexAttribPointer + flag unsupported + +glGetProgramBinaryOES + flag unsupported + +glProgramBinaryOES + flag unsupported + +glMapBufferOES + flag unsupported + +glTexImage3DOES + len pixels glesv2_enc::pixelDataSize3D(self, width, height, depth, format, type, 0) + var_flag pixels nullAllowed isLarge + +glTexSubImage3DOES + len pixels glesv2_enc::pixelDataSize3D(self, width, height, depth, format, type, 0) + var_flag pixels nullAllowed isLarge + +glCompressedTexImage3DOES + len data imageSize + param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + var_flag data nullAllowed isLarge + +glCompressedTexSubImage3DOES + len data imageSize + param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + var_flag data nullAllowed isLarge + +glDeleteVertexArraysOES + len arrays (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGenVertexArraysOES + len arrays (n * sizeof(GLuint)) + dir arrays out + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDiscardFramebufferEXT + len attachments (numAttachments * sizeof(GLenum)) + +glMultiDrawArraysEXT + flag unsupported + +glMultiDrawElementsEXT + flag unsupported + +glShaderSource + flag unsupported + +glGetPerfMonitorGroupsAMD + flag unsupported + +glGetPerfMonitorCountersAMD + flag unsupported + +glGetPerfMonitorGroupStringAMD + flag unsupported + +glGetPerfMonitorCounterStringAMD + flag unsupported + +glGetPerfMonitorCounterInfoAMD + flag unsupported + +glGenPerfMonitorsAMD + flag unsupported + +glDeletePerfMonitorsAMD + flag unsupported + +glSelectPerfMonitorCountersAMD + flag unsupported + +glBeginPerfMonitorAMD + flag unsupported + +glEndPerfMonitorAMD + flag unsupported + +glGetPerfMonitorCounterDataAMD + flag unsupported + +glRenderbufferStorageMultisampleIMG + flag unsupported + +glFramebufferTexture2DMultisampleIMG + flag unsupported + +glDeleteFencesNV + flag unsupported + +glGenFencesNV + flag unsupported + +glIsFenceNV + flag unsupported + +glTestFenceNV + flag unsupported + +glGetFenceivNV + flag unsupported + +glFinishFenceNV + flag unsupported + +glSetFenceNV + flag unsupported + +glCoverageMaskNV + flag unsupported + +glCoverageOperationNV + flag unsupported + +glGetDriverControlsQCOM + flag unsupported + +glGetDriverControlStringQCOM + flag unsupported + +glEnableDriverControlQCOM + flag unsupported + +glDisableDriverControlQCOM + flag unsupported + +glExtGetTexturesQCOM + flag unsupported + +glExtGetBuffersQCOM + flag unsupported + +glExtGetRenderbuffersQCOM + flag unsupported + +glExtGetFramebuffersQCOM + flag unsupported + +glExtGetTexLevelParameterivQCOM + flag unsupported + +glExtTexObjectStateOverrideiQCOM + flag unsupported + +glExtGetTexSubImageQCOM + flag unsupported + +glExtGetBufferPointervQCOM + flag unsupported + +glExtGetShadersQCOM + flag unsupported + +glExtGetProgramsQCOM + flag unsupported + +glExtIsProgramBinaryQCOM + flag unsupported + +glExtGetProgramBinarySourceQCOM + flag unsupported + +glStartTilingQCOM + flag unsupported + +glEndTilingQCOM + flag unsupported + +glVertexAttribPointerData + len data datalen + flag not_api + +glVertexAttribPointerOffset + flag not_api + +glGetVertexAttribPointerv + flag unsupported + +glDrawElementsData + len data datalen + flag not_api + +glDrawElementsOffset + flag not_api + +glGetCompressedTextureFormats + dir formats out + len formats (count * sizeof(GLint)) + flag not_api + +glShaderString + len string len + flag not_api + +glFinishRoundTrip + flag not_api + +glGenVertexArrays + len arrays (n * sizeof(GLuint)) + dir arrays out + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDeleteVertexArrays + len arrays (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glMapBufferRange + flag unsupported + +glUnmapBuffer + flag unsupported + +glFlushMappedBufferRange + flag unsupported + +glMapBufferRangeAEMU + dir mapped out + len mapped length + var_flag mapped nullAllowed + flag not_api + +glUnmapBufferAEMU + dir guest_buffer in + len guest_buffer length + var_flag guest_buffer nullAllowed + dir out_res out + len out_res (sizeof(GLboolean)) + flag not_api + +glFlushMappedBufferRangeAEMU + dir guest_buffer in + len guest_buffer length + var_flag guest_buffer nullAllowed + flag not_api + +glReadPixelsOffsetAEMU + flag not_api + +glCompressedTexImage2DOffsetAEMU + flag not_api + +glCompressedTexSubImage2DOffsetAEMU + flag not_api + +glTexImage2DOffsetAEMU + flag not_api + +glTexSubImage2DOffsetAEMU + flag not_api + +glCopyBufferSubData + flag flushOnEncode + +glClearBufferiv + dir value in + len value (sizeof(GLint) * glesv2_enc::clearBufferNumElts(self, buffer)) + +glClearBufferuiv + dir value in + len value (sizeof(GLuint) * glesv2_enc::clearBufferNumElts(self, buffer)) + +glClearBufferfv + dir value in + len value (sizeof(GLfloat) * glesv2_enc::clearBufferNumElts(self, buffer)) + +glGetBufferParameteri64v + flag unsupported + +glGetBufferPointerv + flag unsupported + +glGetUniformBlockIndex + len uniformBlockName (strlen(uniformBlockName) + 1) + +glGetUniformIndices + flag unsupported + +glGetUniformIndicesAEMU + dir packedUniformNames in + len packedUniformNames packedLen + dir uniformIndices out + len uniformIndices (uniformCount * sizeof(GLuint)) + flag not_api + +glGetActiveUniformBlockiv + dir params out + len params (glesv2_enc::glActiveUniformBlockivParamSize(self, program, uniformBlockIndex, pname) * sizeof(GLint)) + +glGetActiveUniformBlockName + dir uniformBlockName out + len uniformBlockName bufSize + param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + var_flag uniformBlockName nullAllowed + dir length out + len length (sizeof(GLsizei)) + var_flag length nullAllowed + +glUniform1uiv + len value (count * sizeof(GLuint)) + +glUniform2uiv + len value (count * 2 * sizeof(GLuint)) + +glUniform3uiv + len value (count * 3 * sizeof(GLuint)) + +glUniform4uiv + len value (count * 4 * sizeof(GLuint)) + +glUniformMatrix2x3fv + len value (count * 6 * sizeof(GLfloat)) + +glUniformMatrix3x2fv + len value (count * 6 * sizeof(GLfloat)) + +glUniformMatrix2x4fv + len value (count * 8 * sizeof(GLfloat)) + +glUniformMatrix4x2fv + len value (count * 8 * sizeof(GLfloat)) + +glUniformMatrix3x4fv + len value (count * 12 * sizeof(GLfloat)) + +glUniformMatrix4x3fv + len value (count * 12 * sizeof(GLfloat)) + +glGetUniformuiv + dir params out + len params glSizeof(glesv2_enc::uniformType(self, program, location)) + +glGetActiveUniformsiv + len uniformIndices (uniformCount * sizeof(GLuint)) + dir params out + len params (uniformCount * sizeof(GLint)) + +glVertexAttribI4iv + len v (4 * sizeof(GLint)) + +glVertexAttribI4uiv + len v (4 * sizeof(GLuint)) + +glVertexAttribIPointer + flag unsupported + +glVertexAttribIPointerOffsetAEMU + flag not_api + +glVertexAttribIPointerDataAEMU + len data datalen + flag not_api + +glGetVertexAttribIiv + dir params out + +glGetVertexAttribIuiv + dir params out + +glDrawElementsInstanced + flag unsupported + +glDrawElementsInstancedDataAEMU + len indices datalen + flag not_api + +glDrawElementsInstancedOffsetAEMU + flag not_api + +glDrawRangeElements + flag unsupported + +glDrawRangeElementsDataAEMU + len indices datalen + flag not_api + +glDrawRangeElementsOffsetAEMU + flag not_api + +glFenceSync + flag unsupported + +glClientWaitSync + flag unsupported + +glWaitSync + flag unsupported + +glDeleteSync + flag unsupported + +glIsSync + flag unsupported + +glGetSynciv + flag unsupported + +glFenceSyncAEMU + flag custom_decoder + flag not_api + +glClientWaitSyncAEMU + flag custom_decoder + flag not_api + +glWaitSyncAEMU + flag custom_decoder + flag not_api + +glDeleteSyncAEMU + flag custom_decoder + flag not_api + +glIsSyncAEMU + flag custom_decoder + flag not_api + +glGetSyncivAEMU + flag custom_decoder + flag not_api + param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + dir length out + len length (sizeof(GLsizei)) + var_flag length nullAllowed + dir values out + len values (bufSize * sizeof(GLint)) + +glGetInternalformativ + dir params out + len params (sizeof(GLint) * bufSize) + +glDrawBuffers + len bufs (n * sizeof(GLenum)) + +glInvalidateFramebuffer + len attachments (numAttachments * sizeof(GLenum)) + +glInvalidateSubFramebuffer + len attachments (numAttachments * sizeof(GLenum)) + +glGenTransformFeedbacks + dir ids out + len ids (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDeleteTransformFeedbacks + len ids (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glTransformFeedbackVaryings + flag unsupported + +glTransformFeedbackVaryingsAEMU + dir packedVaryings in + len packedVaryings packedVaryingsLen + flag not_api + +glGetTransformFeedbackVarying + dir name out + len name bufSize + param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + var_flag name nullAllowed + dir length out + len length (sizeof(GLsizei)) + var_flag length nullAllowed + dir size out + len size (sizeof(GLsizei)) + var_flag type nullAllowed + dir type out + len type (sizeof(GLenum)) + var_flag type nullAllowed + +glGenSamplers + dir samplers out + len samplers (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDeleteSamplers + len samplers (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGetSamplerParameterfv + dir params out + +glGetSamplerParameteriv + dir params out + +glGenQueries + dir queries out + len queries (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glDeleteQueries + len queries (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGetQueryiv + dir params out + +glGetQueryObjectuiv + dir params out + +glProgramBinary + len binary length + +glGetProgramBinary + param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + dir binary out + len binary bufSize + dir binaryFormat out + len binaryFormat (sizeof(GLenum)) + var_flag length nullAllowed + dir length out + len length (sizeof(GLsizei)) + +glGetFragDataLocation + len name (strlen(name) + 1) + +glGetInteger64v + dir data out + +glGetIntegeri_v + dir data out + len data (sizeof(GLint)) + +glGetInteger64i_v + dir data out + len data (sizeof(GLint64)) + +glTexImage3D + dir data in + len data glesv2_enc::pixelDataSize3D(self, width, height, depth, format, type, 0) + var_flag data nullAllowed isLarge + +glTexImage3DOffsetAEMU + flag not_api + +glTexSubImage3D + len data glesv2_enc::pixelDataSize3D(self, width, height, depth, format, type, 0) + var_flag data nullAllowed isLarge + +glTexSubImage3DOffsetAEMU + flag not_api + +glCompressedTexImage3D + len data imageSize + param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + var_flag data nullAllowed isLarge + +glCompressedTexImage3DOffsetAEMU + flag not_api + +glCompressedTexSubImage3D + param_check imageSize if(imageSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + len data imageSize + var_flag data nullAllowed isLarge + +glCompressedTexSubImage3DOffsetAEMU + flag not_api + +glGetStringi + flag unsupported + +glGetBooleani_v + dir data out + len data (sizeof(GLboolean)) + +glGenProgramPipelines + dir pipelines out + len pipelines (n * sizeof(GLuint)) + +glDeleteProgramPipelines + len pipelines (n * sizeof(GLuint)) + param_check n if(n<0){ ctx->setError(GL_INVALID_VALUE); return; } + +glGetProgramPipelineiv + dir params out + +glGetProgramPipelineInfoLog + dir infoLog out + len infoLog bufSize + param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + dir length out + len length sizeof(GLsizei) + var_flag length nullAllowed + +glCreateShaderProgramv + flag unsupported + +glCreateShaderProgramvAEMU + len packedStrings packedLen + flag not_api + +glProgramUniform1fv + len value (count * sizeof(GLfloat)) + +glProgramUniform2fv + len value (count * 2 * sizeof(GLfloat)) + +glProgramUniform3fv + len value (count * 3 * sizeof(GLfloat)) + +glProgramUniform4fv + len value (count * 4 * sizeof(GLfloat)) + +glProgramUniform1iv + len value (count * sizeof(GLint)) + +glProgramUniform2iv + len value (count * 2 * sizeof(GLint)) + +glProgramUniform3iv + len value (count * 3 * sizeof(GLint)) + +glProgramUniform4iv + len value (count * 4 * sizeof(GLint)) + +glProgramUniform1uiv + len value (count * sizeof(GLuint)) + +glProgramUniform2uiv + len value (count * 2 * sizeof(GLuint)) + +glProgramUniform3uiv + len value (count * 3 * sizeof(GLuint)) + +glProgramUniform4uiv + len value (count * 4 * sizeof(GLuint)) + +glProgramUniformMatrix2fv + len value (count * 4 * sizeof(GLfloat)) + +glProgramUniformMatrix3fv + len value (count * 9 * sizeof(GLfloat)) + +glProgramUniformMatrix4fv + len value (count * 16 * sizeof(GLfloat)) + +glProgramUniformMatrix2x3fv + len value (count * 6 * sizeof(GLfloat)) + +glProgramUniformMatrix3x2fv + len value (count * 6 * sizeof(GLfloat)) + +glProgramUniformMatrix2x4fv + len value (count * 8 * sizeof(GLfloat)) + +glProgramUniformMatrix4x2fv + len value (count * 8 * sizeof(GLfloat)) + +glProgramUniformMatrix3x4fv + len value (count * 12 * sizeof(GLfloat)) + +glProgramUniformMatrix4x3fv + len value (count * 12 * sizeof(GLfloat)) + +glGetProgramInterfaceiv + dir params out + +glGetProgramResourceiv + dir params out + len params (bufSize * sizeof(GLint)) + param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + var_flag length nullAllowed + dir length out + len length (sizeof(GLsizei)) + len props (propCount * sizeof(GLenum)) + +glGetProgramResourceIndex + len name (strlen(name) + 1) + +glGetProgramResourceLocation + len name (strlen(name) + 1) + +glGetProgramResourceName + dir name out + len name bufSize + param_check bufSize if(bufSize<0){ ctx->setError(GL_INVALID_VALUE); return; } + var_flag length nullAllowed + dir length out + len length (sizeof(GLsizei)) + +glDrawArraysIndirect + flag unsupported + +glDrawArraysIndirectDataAEMU + len indirect datalen + flag not_api + +glDrawArraysIndirectOffsetAEMU + flag not_api + +glDrawElementsIndirect + flag unsupported + +glDrawElementsIndirectDataAEMU + len indirect datalen + flag not_api + +glDrawElementsIndirectOffsetAEMU + flag not_api + +glGetMultisamplefv + dir val out + +glGetFramebufferParameteriv + dir params out + +glGetTexLevelParameterfv + dir params out + +glGetTexLevelParameteriv + dir params out diff --git a/host/libs/virglrenderer/GLESv3_dec/gles3.in b/host/libs/virglrenderer/GLESv3_dec/gles3.in new file mode 100644 index 0000000000000000000000000000000000000000..33eb3b3961f5954925278bc03bd8e170505e9af9 --- /dev/null +++ b/host/libs/virglrenderer/GLESv3_dec/gles3.in @@ -0,0 +1,559 @@ +GL_ENTRY(void, glActiveTexture, GLenum texture) +GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader) +GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const GLchar* name) +GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer) +GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer) +GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer) +GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture) +GL_ENTRY(void, glBlendColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +GL_ENTRY(void, glBlendEquation, GLenum mode ) +GL_ENTRY(void, glBlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) +GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor) +GL_ENTRY(void, glBlendFuncSeparate, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target) +GL_ENTRY(void, glClear, GLbitfield mask) +GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +GL_ENTRY(void, glClearDepthf, GLclampf depth) +GL_ENTRY(void, glClearStencil, GLint s) +GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +GL_ENTRY(void, glCompileShader, GLuint shader) +GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) +GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) +GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(GLuint, glCreateProgram, void) +GL_ENTRY(GLuint, glCreateShader, GLenum type) +GL_ENTRY(void, glCullFace, GLenum mode) +GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint* buffers) +GL_ENTRY(void, glDeleteFramebuffers, GLsizei n, const GLuint* framebuffers) +GL_ENTRY(void, glDeleteProgram, GLuint program) +GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint* renderbuffers) +GL_ENTRY(void, glDeleteShader, GLuint shader) +GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint* textures) +GL_ENTRY(void, glDepthFunc, GLenum func) +GL_ENTRY(void, glDepthMask, GLboolean flag) +GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar) +GL_ENTRY(void, glDetachShader, GLuint program, GLuint shader) +GL_ENTRY(void, glDisable, GLenum cap) +GL_ENTRY(void, glDisableVertexAttribArray, GLuint index) +GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count) +GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) +GL_ENTRY(void, glEnable, GLenum cap) +GL_ENTRY(void, glEnableVertexAttribArray, GLuint index) +GL_ENTRY(void, glFinish, void) +GL_ENTRY(void, glFlush, void) +GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +GL_ENTRY(void, glFrontFace, GLenum mode) +GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint* buffers) +GL_ENTRY(void, glGenerateMipmap, GLenum target) +GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint* framebuffers) +GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint* renderbuffers) +GL_ENTRY(void, glGenTextures, GLsizei n, GLuint* textures) +GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +GL_ENTRY(void, glGetAttachedShaders, GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +GL_ENTRY(int, glGetAttribLocation, GLuint program, const GLchar* name) +GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean* params) +GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint* params) +GL_ENTRY(GLenum, glGetError, void) +GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat* params) +GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params) +GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint* params) +GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint* params) +GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) +GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint* params) +GL_ENTRY(void, glGetShaderiv, GLuint shader, GLenum pname, GLint* params) +GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) +GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +GL_ENTRY(const GLubyte*, glGetString, GLenum name) +GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat* params) +GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint* params) +GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat* params) +GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint* params) +GL_ENTRY(int, glGetUniformLocation, GLuint program, const GLchar* name) +GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params) +GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint* params) +GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, GLvoid** pointer) +GL_ENTRY(void, glHint, GLenum target, GLenum mode) +GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer) +GL_ENTRY(GLboolean, glIsEnabled, GLenum cap) +GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer) +GL_ENTRY(GLboolean, glIsProgram, GLuint program) +GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer) +GL_ENTRY(GLboolean, glIsShader, GLuint shader) +GL_ENTRY(GLboolean, glIsTexture, GLuint texture) +GL_ENTRY(void, glLineWidth, GLfloat width) +GL_ENTRY(void, glLinkProgram, GLuint program) +GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param) +GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units) +GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) +GL_ENTRY(void, glReleaseShaderCompiler, void) +GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert) +GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glShaderBinary, GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const GLchar*const* string, const GLint* length) +GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask) +GL_ENTRY(void, glStencilFuncSeparate, GLenum face, GLenum func, GLint ref, GLuint mask) +GL_ENTRY(void, glStencilMask, GLuint mask) +GL_ENTRY(void, glStencilMaskSeparate, GLenum face, GLuint mask) +GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass) +GL_ENTRY(void, glStencilOpSeparate, GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) +GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat* params) +GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint* params) +GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) +GL_ENTRY(void, glUniform1f, GLint location, GLfloat x) +GL_ENTRY(void, glUniform1fv, GLint location, GLsizei count, const GLfloat* v) +GL_ENTRY(void, glUniform1i, GLint location, GLint x) +GL_ENTRY(void, glUniform1iv, GLint location, GLsizei count, const GLint* v) +GL_ENTRY(void, glUniform2f, GLint location, GLfloat x, GLfloat y) +GL_ENTRY(void, glUniform2fv, GLint location, GLsizei count, const GLfloat* v) +GL_ENTRY(void, glUniform2i, GLint location, GLint x, GLint y) +GL_ENTRY(void, glUniform2iv, GLint location, GLsizei count, const GLint* v) +GL_ENTRY(void, glUniform3f, GLint location, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glUniform3fv, GLint location, GLsizei count, const GLfloat* v) +GL_ENTRY(void, glUniform3i, GLint location, GLint x, GLint y, GLint z) +GL_ENTRY(void, glUniform3iv, GLint location, GLsizei count, const GLint* v) +GL_ENTRY(void, glUniform4f, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +GL_ENTRY(void, glUniform4fv, GLint location, GLsizei count, const GLfloat* v) +GL_ENTRY(void, glUniform4i, GLint location, GLint x, GLint y, GLint z, GLint w) +GL_ENTRY(void, glUniform4iv, GLint location, GLsizei count, const GLint* v) +GL_ENTRY(void, glUniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +GL_ENTRY(void, glUniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +GL_ENTRY(void, glUseProgram, GLuint program) +GL_ENTRY(void, glValidateProgram, GLuint program) +GL_ENTRY(void, glVertexAttrib1f, GLuint indx, GLfloat x) +GL_ENTRY(void, glVertexAttrib1fv, GLuint indx, const GLfloat* values) +GL_ENTRY(void, glVertexAttrib2f, GLuint indx, GLfloat x, GLfloat y) +GL_ENTRY(void, glVertexAttrib2fv, GLuint indx, const GLfloat* values) +GL_ENTRY(void, glVertexAttrib3f, GLuint indx, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glVertexAttrib3fv, GLuint indx, const GLfloat* values) +GL_ENTRY(void, glVertexAttrib4f, GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +GL_ENTRY(void, glVertexAttrib4fv, GLuint indx, const GLfloat* values) +GL_ENTRY(void, glVertexAttribPointer, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) +GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image) +GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image) +GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) +GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length) +GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access) +GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target) +#GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, GLvoid** params) +GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) +GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) +GL_ENTRY(void, glCopyTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data) +GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) +GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) +GL_ENTRY(void, glBindVertexArrayOES, GLuint array) +GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays) +GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays) +GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array) +GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments) +GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) +GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const GLvoid*const* indices, GLsizei primcount) + +#not supported +GL_ENTRY(void, glGetPerfMonitorGroupsAMD, GLint *numGroups, GLsizei groupsSize, GLuint *groups) +GL_ENTRY(void, glGetPerfMonitorCountersAMD, GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters) +GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString) +GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString) +GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, GLvoid *data) +GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors) +GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors) +GL_ENTRY(void, glSelectPerfMonitorCountersAMD, GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList) +GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor) +GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor) +GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) + +GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) +GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences) +GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences) +GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence) +GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence) +GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params) +GL_ENTRY(void, glFinishFenceNV, GLuint fence) +GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition) +GL_ENTRY(void, glCoverageMaskNV, GLboolean mask) +GL_ENTRY(void, glCoverageOperationNV, GLenum operation) +GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls) +GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString) +GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl) +GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl) +GL_ENTRY(void, glExtGetTexturesQCOM, GLuint *textures, GLint maxTextures, GLint *numTextures) +GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers) +GL_ENTRY(void, glExtGetRenderbuffersQCOM, GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers) +GL_ENTRY(void, glExtGetFramebuffersQCOM, GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers) +GL_ENTRY(void, glExtGetTexLevelParameterivQCOM, GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params) +GL_ENTRY(void, glExtTexObjectStateOverrideiQCOM, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glExtGetTexSubImageQCOM, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels) +GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, GLvoid** params) +GL_ENTRY(void, glExtGetShadersQCOM, GLuint *shaders, GLint maxShaders, GLint *numShaders) +GL_ENTRY(void, glExtGetProgramsQCOM, GLuint *programs, GLint maxPrograms, GLint *numPrograms) +GL_ENTRY(GLboolean, glExtIsProgramBinaryQCOM, GLuint program) +GL_ENTRY(void, glExtGetProgramBinarySourceQCOM, GLuint program, GLenum shadertype, GLchar *source, GLint *length) +GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) +GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask) + +# add-ons for GLES 2 +GL_ENTRY(void, glVertexAttribPointerData, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, void * data, GLuint datalen) +GL_ENTRY(void, glVertexAttribPointerOffset, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint offset) +GL_ENTRY(void, glDrawElementsOffset, GLenum mode, GLsizei count, GLenum type, GLuint offset) +GL_ENTRY(void, glDrawElementsData, GLenum mode, GLsizei count, GLenum type, void *data, GLuint datalen) +GL_ENTRY(void, glGetCompressedTextureFormats, int count, GLint *formats) +GL_ENTRY(void, glShaderString, GLuint shader, const GLchar* string, GLsizei len) +GL_ENTRY(int, glFinishRoundTrip, void) + +# GLES 3.0 ApiGen .in + +# Changes to existing API: + +## New formats: Need to update all validation code to handle GLES 3.x-specific formats. +## Primitive restart (close to already implemented in guest encoder, but can be tricky to validate in the middle of all the other draw validation going on) +## Texture compression with ETC2 (already implemented) + +# New API calls - listed in approximate decreasing order of complexity + +# Vertex Array Objects +## Before anything else, move GL calls out of sendVertexAttributes() in encoder, +## or we will get this wrong, as we currently delay glEnableVertexAttribArray/ glVertexAttribPointer +## until right before glDrawElements/Arrays. +## This means moving those attribpointer calls out, +## AND preserving the index range validation behavior that happens +## just before glDrawElements/Arrays. +GL_ENTRY(void, glGenVertexArrays, GLsizei n, GLuint* arrays) +GL_ENTRY(void, glBindVertexArray, GLuint array) +GL_ENTRY(void, glDeleteVertexArrays, GLsizei n, const GLuint *arrays) +GL_ENTRY(GLboolean, glIsVertexArray, GLuint array) + +# New buffer operationarrays Mapping needs different encoding interface: copy from host on map, and copy to host (and host GPU pointer) on unmap or flush. +## Proposed: +GL_ENTRY(void*, glMapBufferRange, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +GL_ENTRY(GLboolean, glUnmapBuffer, GLenum target) +GL_ENTRY(void, glFlushMappedBufferRange, GLenum target, GLintptr offset, GLsizeiptr length) +GL_ENTRY(void, glMapBufferRangeAEMU, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* mapped) +GL_ENTRY(void, glUnmapBufferAEMU, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res) +GL_ENTRY(void, glFlushMappedBufferRangeAEMU, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer) +## It seems we can use glUnmapBuffer and glFlushMappedBufferRange as synchronization points +## to update the host with the new buffer contents: +## glMapBufferRange / glUnmapBuffer: +## Guest: | Encoder: | Host: +## void* x = glMapBuffer... | | +## | glMapBufferRangeAEMU_enc... | +## | | void* hostptr = glMapBufferRange... +## | | memcpy(mapped, hostptr, sz) +## | stream->readback(mapped, sz) | +## | glMapBufferRangeAEMU_enc exit | +## x holds host GPU contents | | +## <operations on x> | | +## glUnmapBuffer... | | +## | glUnmapBufferAEMU_enc... | +## | stream->writeFully(x, sz) | +## | | memcpy(hostptr, x, sz) +## | | glUnmapBuffer +## glMapBufferRange / glFlushMappedBufferRange: +## Guest: | Encoder: | Host: +## void* x = glMapBuffer... | | +## | glMapBufferRangeAEMU_enc... | +## | | void* hostptr = glMapBufferRange... +## | | memcpy(mapped, hostptr, sz) +## | stream->readback(mapped, sz) | +## | glMapBufferRangeAEMU_enc exit | +## x holds host GPU contents | | +## <operations on x> | | +## glFlushMappedBufferRange..| | +## | glFlushMappedBufferRangeAEMU... | +## | stream->writeFully(flushedrange... | +## | | memcpy(hostptr + offset, flushedrange, length) +## | | glFlushMappedBufferRange +## Make sure to store the binded range when mapped, I bet there is some dEQP test that checks this sort of thing :) + +## PBOs need to be delivered differently to the host. +GL_ENTRY(void, glReadPixelsOffsetAEMU, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLuint offset) +GL_ENTRY(void, glCompressedTexImage2DOffsetAEMU, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLuint offset) +GL_ENTRY(void, glCompressedTexSubImage2DOffsetAEMU, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLuint offset) +GL_ENTRY(void, glTexImage2DOffsetAEMU, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLuint offset) +GL_ENTRY(void, glTexSubImage2DOffsetAEMU, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLuint offset) + +GL_ENTRY(void, glBindBufferRange, GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) +GL_ENTRY(void, glBindBufferBase, GLenum target, GLuint index, GLuint buffer) +## No need to consider mapped buffers here as that is a GL_INVALID_OPERATION :) +GL_ENTRY(void, glCopyBufferSubData, GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size); + +## These buffer clears don't involve anything that can be mapped, so we are OK. +GL_ENTRY(void, glClearBufferiv, GLenum buffer, GLint drawBuffer, const GLint * value) +GL_ENTRY(void, glClearBufferuiv, GLenum buffer, GLint drawBuffer, const GLuint * value) +GL_ENTRY(void, glClearBufferfv, GLenum buffer, GLint drawBuffer, const GLfloat * value) +GL_ENTRY(void, glClearBufferfi, GLenum buffer, GLint drawBuffer, GLfloat depth, GLint stencil) + +## Reads (not writes) mapped state only, so shouldn't be sent to host. +GL_ENTRY(void, glGetBufferParameteri64v, GLenum target, GLenum value, GLint64 * data) + +# Get current mapped buffer pointer. Shouldn't be sent to host. +GL_ENTRY(void, glGetBufferPointerv, GLenum target, GLenum pname, GLvoid** params) + +# UBOs +## Share group processing needed for all of these, as the program is an argument. +## Validation is bound (heh) to be tricky +GL_ENTRY(void, glUniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) + +GL_ENTRY(GLuint, glGetUniformBlockIndex, GLuint program, const GLchar *uniformBlockName) + +# Assume uniformNames packed into 1 buffer on the guest. +GL_ENTRY(void, glGetUniformIndices, GLuint program, GLsizei uniformCount, const GLchar*const* uniformNames, GLuint* uniformIndices) +GL_ENTRY(void, glGetUniformIndicesAEMU, GLuint program, GLsizei uniformCount, const GLchar *packedUniformNames, GLsizei packedLen, GLuint *uniformIndices) + +GL_ENTRY(void, glGetActiveUniformBlockiv, GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params) +GL_ENTRY(void, glGetActiveUniformBlockName, GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) + +# More uniform setters +GL_ENTRY(void, glUniform1ui, GLint location, GLuint v0) +GL_ENTRY(void, glUniform2ui, GLint location, GLuint v0, GLuint v1) +GL_ENTRY(void, glUniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) +GL_ENTRY(void, glUniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +GL_ENTRY(void, glUniform1uiv, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glUniform2uiv, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glUniform3uiv, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glUniform4uiv, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glUniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix2x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix4x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix3x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix4x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) + +# Need share group processing for these gets +GL_ENTRY(void, glGetUniformuiv, GLuint program, GLint location, GLuint *params) +GL_ENTRY(void, glGetActiveUniformsiv, GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params) + +# More vertex attribute setters / queries +GL_ENTRY(void, glVertexAttribI4i, GLuint index, GLint v0, GLint v1, GLint v2, GLint v3) +GL_ENTRY(void, glVertexAttribI4ui, GLuint index, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +GL_ENTRY(void, glVertexAttribI4iv, GLuint index, const GLint *v) +GL_ENTRY(void, glVertexAttribI4uiv, GLuint index, const GLuint *v) +GL_ENTRY(void, glVertexAttribIPointer, GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) +GL_ENTRY(void, glVertexAttribIPointerOffsetAEMU, GLuint index, GLint size, GLenum type, GLsizei stride, GLuint offset) +GL_ENTRY(void, glVertexAttribIPointerDataAEMU, GLuint index, GLint size, GLenum type, GLsizei stride, void* data, GLuint datalen) +GL_ENTRY(void, glGetVertexAttribIiv, GLuint index, GLenum pname, GLint *params) +GL_ENTRY(void, glGetVertexAttribIuiv, GLuint index, GLenum pname, GLuint *params) + +# Instanced draws +GL_ENTRY(void, glVertexAttribDivisor, GLuint index, GLuint divisor) +GL_ENTRY(void, glDrawArraysInstanced, GLenum mode, GLint first, GLsizei count, GLsizei primcount) + +GL_ENTRY(void, glDrawElementsInstanced, GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei primcount) +GL_ENTRY(void, glDrawElementsInstancedDataAEMU, GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei primcount, GLsizei datalen) +GL_ENTRY(void, glDrawElementsInstancedOffsetAEMU, GLenum mode, GLsizei count, GLenum type, GLuint offset, GLsizei primcount) + + +# Draw with known index range +GL_ENTRY(void, glDrawRangeElements, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices) +GL_ENTRY(void, glDrawRangeElementsDataAEMU, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices, GLsizei datalen) +GL_ENTRY(void, glDrawRangeElementsOffsetAEMU, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLuint offset) + +# Sync - mostly implemented on host, just need encoder part +GL_ENTRY(GLsync, glFenceSync, GLenum condition, GLbitfield flags) +GL_ENTRY(GLenum, glClientWaitSync, GLsync wait_on, GLbitfield flags, GLuint64 timeout) +GL_ENTRY(void, glWaitSync, GLsync wait_on, GLbitfield flags, GLuint64 timeout) +GL_ENTRY(void, glDeleteSync, GLsync to_delete) +GL_ENTRY(GLboolean, glIsSync, GLsync sync) +GL_ENTRY(void, glGetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) + +GL_ENTRY(uint64_t, glFenceSyncAEMU, GLenum condition, GLbitfield flags) +GL_ENTRY(GLenum, glClientWaitSyncAEMU, uint64_t wait_on, GLbitfield flags, GLuint64 timeout) +GL_ENTRY(void, glWaitSyncAEMU, uint64_t wait_on, GLbitfield flags, GLuint64 timeout) +GL_ENTRY(void, glDeleteSyncAEMU, uint64_t to_delete) +GL_ENTRY(GLboolean, glIsSyncAEMU, uint64_t sync) +GL_ENTRY(void, glGetSyncivAEMU, uint64_t sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) + +# MRT / MSAA render buffer +GL_ENTRY(void, glDrawBuffers, GLsizei n, const GLenum *bufs); +GL_ENTRY(void, glReadBuffer, GLenum src); +GL_ENTRY(void, glBlitFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); + +# Not even implemented in host driver if < OpenGL 4.3. +# But we should call this anyway if the function is available. +GL_ENTRY(void, glInvalidateFramebuffer, GLenum target, GLsizei numAttachments, const GLenum *attachments) +GL_ENTRY(void, glInvalidateSubFramebuffer, GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height) + +GL_ENTRY(void, glFramebufferTextureLayer, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GL_ENTRY(void, glRenderbufferStorageMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GL_ENTRY(void, glTexStorage2D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GL_ENTRY(void, glGetInternalformativ, GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params) + +# Transform feedback - share group processing in the last two +GL_ENTRY(void, glBeginTransformFeedback, GLenum primitiveMode) +GL_ENTRY(void, glEndTransformFeedback, void) +GL_ENTRY(void, glGenTransformFeedbacks, GLsizei n, GLuint *ids) +GL_ENTRY(void, glDeleteTransformFeedbacks, GLsizei n, const GLuint *ids) +GL_ENTRY(void, glBindTransformFeedback, GLenum target, GLuint id) +GL_ENTRY(void, glPauseTransformFeedback, void) +GL_ENTRY(void, glResumeTransformFeedback, void) +GL_ENTRY(GLboolean, glIsTransformFeedback, GLuint id) +GL_ENTRY(void, glTransformFeedbackVaryings, GLuint program, GLsizei count, const GLchar*const* varyings, GLenum bufferMode) +GL_ENTRY(void, glTransformFeedbackVaryingsAEMU, GLuint program, GLsizei count, const char* packedVaryings, GLuint packedVaryingsLen, GLenum bufferMode) +GL_ENTRY(void, glGetTransformFeedbackVarying, GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, char * name) + +# Sampler objects +GL_ENTRY(void, glGenSamplers, GLsizei n, GLuint *samplers) +GL_ENTRY(void, glDeleteSamplers, GLsizei n, const GLuint * samplers) +GL_ENTRY(void, glBindSampler, GLuint unit, GLuint sampler) +GL_ENTRY(void, glSamplerParameterf, GLuint sampler, GLenum pname, GLfloat param) +GL_ENTRY(void, glSamplerParameteri, GLuint sampler, GLenum pname, GLint param) +GL_ENTRY(void, glSamplerParameterfv, GLuint sampler, GLenum pname, const GLfloat * params) +GL_ENTRY(void, glSamplerParameteriv, GLuint sampler, GLenum pname, const GLint * params) +GL_ENTRY(void, glGetSamplerParameterfv, GLuint sampler, GLenum pname, GLfloat * params) +GL_ENTRY(void, glGetSamplerParameteriv, GLuint sampler, GLenum pname, GLint * params) +GL_ENTRY(GLboolean, glIsSampler, GLuint sampler) + +# Query objects +GL_ENTRY(void, glGenQueries, GLsizei n, GLuint * queries) +GL_ENTRY(void, glDeleteQueries, GLsizei n, const GLuint * queries) +GL_ENTRY(void, glBeginQuery, GLenum target, GLuint query) +GL_ENTRY(void, glEndQuery, GLenum target) +GL_ENTRY(void, glGetQueryiv, GLenum target, GLenum pname, GLint * params) +GL_ENTRY(void, glGetQueryObjectuiv, GLuint query, GLenum pname, GLuint * params) +GL_ENTRY(GLboolean, glIsQuery, GLuint query) + +# Shader binary objects - need share group processing +GL_ENTRY(void, glProgramParameteri, GLuint program, GLenum pname, GLint value) +GL_ENTRY(void, glProgramBinary, GLuint program, GLenum binaryFormat, const void *binary, GLsizei length) +GL_ENTRY(void, glGetProgramBinary, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) + +# New glGets - need share group processing for program object +GL_ENTRY(GLint, glGetFragDataLocation, GLuint program, const char * name) +GL_ENTRY(void, glGetInteger64v, GLenum pname, GLint64 * data) +GL_ENTRY(void, glGetIntegeri_v, GLenum target, GLuint index, GLint * data) +GL_ENTRY(void, glGetInteger64i_v, GLenum target, GLuint index, GLint64 * data) + +# Array/3D textures +GL_ENTRY(void, glTexImage3D, GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * data) +GL_ENTRY(void, glTexImage3DOffsetAEMU, GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLuint offset) +GL_ENTRY(void, glTexStorage3D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GL_ENTRY(void, glTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid * data); +GL_ENTRY(void, glTexSubImage3DOffsetAEMU, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLuint offset); +GL_ENTRY(void, glCompressedTexImage3D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid * data) +GL_ENTRY(void, glCompressedTexImage3DOffsetAEMU, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLuint offset) +GL_ENTRY(void, glCompressedTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid * data); +GL_ENTRY(void, glCompressedTexSubImage3DOffsetAEMU, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLuint data); +GL_ENTRY(void, glCopyTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) + +# glGetStringi +GL_ENTRY(const GLubyte*, glGetStringi, GLenum name, GLuint index); + +# GLES 3.1: + +# New get +GL_ENTRY(void, glGetBooleani_v, GLenum target, GLuint index, GLboolean * data) + +# Memory barriers +GL_ENTRY(void, glMemoryBarrier, GLbitfield barriers); +GL_ENTRY(void, glMemoryBarrierByRegion, GLbitfield barriers); + +# Program pipelines - may require adding a new shared object type! +GL_ENTRY(void, glGenProgramPipelines, GLsizei n, GLuint *pipelines) +GL_ENTRY(void, glDeleteProgramPipelines, GLsizei n, const GLuint *pipelines) +GL_ENTRY(void, glBindProgramPipeline, GLuint pipeline) + +GL_ENTRY(void, glGetProgramPipelineiv, GLuint pipeline, GLenum pname, GLint *params) +GL_ENTRY(void, glGetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) + +GL_ENTRY(void, glValidateProgramPipeline, GLuint pipeline) +GL_ENTRY(GLboolean, glIsProgramPipeline, GLuint pipeline); +GL_ENTRY(void, glUseProgramStages, GLuint pipeline, GLbitfield stages, GLuint program) + +# Separable shader programs - may need to change how program objects are represented and shared! +GL_ENTRY(void, glActiveShaderProgram, GLuint pipeline, GLuint program); +GL_ENTRY(GLuint, glCreateShaderProgramv, GLenum type, GLsizei count, const GLchar*const* strings) +GL_ENTRY(GLuint, glCreateShaderProgramvAEMU, GLenum type, GLsizei count, const char *packedStrings, GLuint packedLen) +# Uniforms should work easily if any program object representation problems are solved. +GL_ENTRY(void, glProgramUniform1f, GLuint program, GLint location, GLfloat v0) +GL_ENTRY(void, glProgramUniform2f, GLuint program, GLint location, GLfloat v0, GLfloat v1) +GL_ENTRY(void, glProgramUniform3f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +GL_ENTRY(void, glProgramUniform4f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) +GL_ENTRY(void, glProgramUniform1i, GLuint program, GLint location, GLint v0) +GL_ENTRY(void, glProgramUniform2i, GLuint program, GLint location, GLint v0, GLint v1) +GL_ENTRY(void, glProgramUniform3i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2) +GL_ENTRY(void, glProgramUniform4i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +GL_ENTRY(void, glProgramUniform1ui, GLuint program, GLint location, GLuint v0) +GL_ENTRY(void, glProgramUniform2ui, GLuint program, GLint location, GLuint v0, GLuint v1) +GL_ENTRY(void, glProgramUniform3ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) +GL_ENTRY(void, glProgramUniform4ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +GL_ENTRY(void, glProgramUniform1fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform2fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform3fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform4fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform1iv, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform2iv, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform3iv, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform4iv, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform1uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniform2uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniform3uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniform4uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniformMatrix2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix2x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix3x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix2x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix4x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix3x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix4x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) + +# Depending on whether ANGLE shader translator supports ES 3.1, this might require us to enhance the ANGLE shader translator by a LOT. +GL_ENTRY(void, glGetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname, GLint * params) +GL_ENTRY(void, glGetProgramResourceiv, GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum * props, GLsizei bufSize, GLsizei * length, GLint * params) +GL_ENTRY(GLuint, glGetProgramResourceIndex, GLuint program, GLenum programInterface, const char * name) +GL_ENTRY(GLint, glGetProgramResourceLocation, GLuint program, GLenum programInterface, const char * name) +GL_ENTRY(void, glGetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei * length, char * name) + +# Compute shaders. Should just work if everything else does. +GL_ENTRY(void, glBindImageTexture, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) +GL_ENTRY(void, glDispatchCompute, GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) + +### This is an indirect call and the |indirect| field could be a GPU pointer. +### We will need to make sure that |indirect| is updated to the latest version if so, +### and probably manage a running set of GPU pointers on the host +### that the guest is using. +GL_ENTRY(void, glDispatchComputeIndirect, GLintptr indirect) + +# Separate vertex format / buffer binding +### Requires us tp really clean up how draws work in the encoder currently. +GL_ENTRY(void, glBindVertexBuffer, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) +GL_ENTRY(void, glVertexAttribBinding, GLuint attribindex, GLuint bindingindex); +GL_ENTRY(void, glVertexAttribFormat, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) +GL_ENTRY(void, glVertexAttribIFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) +GL_ENTRY(void, glVertexBindingDivisor, GLuint bindingindex, GLuint divisor) + +# Indirect draws +### Again, if |indirect| is a GPU pointer, we need to synchronize it before calling. +GL_ENTRY(void, glDrawArraysIndirect, GLenum mode, const void * indirect) +GL_ENTRY(void, glDrawArraysIndirectDataAEMU, GLenum mode, const void *indirect, GLuint datalen) +GL_ENTRY(void, glDrawArraysIndirectOffsetAEMU, GLenum mode, GLuint offset) +GL_ENTRY(void, glDrawElementsIndirect, GLenum mode, GLenum type, const void * indirect) +GL_ENTRY(void, glDrawElementsIndirectDataAEMU, GLenum mode, GLenum type, const void *indirect, GLuint datalen) +GL_ENTRY(void, glDrawElementsIndirectOffsetAEMU, GLenum mode, GLenum type, GLuint offset) + +# Multisampling +GL_ENTRY(void, glTexStorage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) +GL_ENTRY(void, glSampleMaski, GLuint maskNumber, GLbitfield mask) +GL_ENTRY(void, glGetMultisamplefv, GLenum pname, GLuint index, GLfloat *val) + +# New framebuffer parameters +GL_ENTRY(void, glFramebufferParameteri, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glGetFramebufferParameteriv, GLenum target, GLenum pname, GLint * params) + +# Texture LOD queries +# Already used in Translator's validations, just need encoder. +GL_ENTRY(void, glGetTexLevelParameterfv, GLenum target, GLint level, GLenum pname, GLfloat * params) +GL_ENTRY(void, glGetTexLevelParameteriv, GLenum target, GLint level, GLenum pname, GLint * params) diff --git a/host/libs/virglrenderer/GLESv3_dec/gles3.types b/host/libs/virglrenderer/GLESv3_dec/gles3.types new file mode 100644 index 0000000000000000000000000000000000000000..2b39b29dc4916f3f4753d140646f6a7d84d67161 --- /dev/null +++ b/host/libs/virglrenderer/GLESv3_dec/gles3.types @@ -0,0 +1,50 @@ +GLbitfield 32 0x%08x +GLboolean 8 %d +GLclampf 32 %f +GLclampx 32 0x%08x +GLeglImageOES 32 %p +GLenum 32 0x%08x +GLfixed 32 0x%08x +GLfloat 32 %f +GLint 32 %d +GLintptr 32 0x%08lx +GLshort 16 %d +GLsizei 32 %d +GLsizeiptr 32 0x%08lx +GLubyte 8 0x%02x +GLuint 32 %u +GLvoid 0 %x +GLchar 8 %d +GLenum* 32 0x%08x +GLboolean* 32 0x%08x +GLclampf* 32 0x%08x +GLclampx* 32 0x%08x +GLeglImageOES* 32 0x%08x +GLfixed* 32 0x%08x +GLfloat* 32 0x%08x +GLint* 32 0x%08x +GLshort* 32 0x%08x +GLsizei* 32 0x%08x +GLubyte* 32 0x%08x +GLuint* 32 0x%08x +GLvoid* 32 0x%08x +GLchar* 32 0x%08x +GLchar** 32 0x%08x +GLvoid** 32 0x%08x +void* 32 0x%08x +GLstr* 32 0x%08x +GLvoidptr* 32 0x%08x +GLchar*const* 32 0x%08x +GLvoid*const* 32 0x%08x +GLsync 64 %p +uint64_t 64 0x%016lx +GLint32 32 0x%08x +GLint32* 32 %p +GLint64 64 0x%016lx +GLint64* 32 %p +GLuint32 32 0x%08x +GLuint32* 32 %p +GLuint64 64 0x%016lx +GLuint64* 32 %p +char* 32 0x%08x +char** 32 0x%08x diff --git a/host/libs/virglrenderer/GLESv3_dec/gles3_types.h b/host/libs/virglrenderer/GLESv3_dec/gles3_types.h new file mode 100644 index 0000000000000000000000000000000000000000..3347b99238b46586c281833e6e3ba8c30987e9e4 --- /dev/null +++ b/host/libs/virglrenderer/GLESv3_dec/gles3_types.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <GLES3/gl31.h> +#include <GLES2/gl2ext.h> diff --git a/host/libs/virglrenderer/Gralloc1.cpp b/host/libs/virglrenderer/Gralloc1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2fcd8147bb78e47470d7129ab7c4092112b94fb --- /dev/null +++ b/host/libs/virglrenderer/Gralloc1.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cstdint> + +extern "C" { +#include "virgl_hw.h" +} + +#include "Resource.h" + +#include <android/sync.h> +#include <hardware/gralloc1.h> + +#include <cerrno> + +#define ALIGN(A, B) (((A) + (B)-1) / (B) * (B)) + +static int gralloc1_device_open(const hw_module_t*, const char*, hw_device_t**); + +static hw_module_methods_t g_gralloc1_methods = { + .open = gralloc1_device_open, +}; + +static hw_module_t g_gralloc1_module = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = GRALLOC_MODULE_API_VERSION_1_0, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = GRALLOC_HARDWARE_MODULE_ID, + .name = "AVDVirglRenderer", + .author = "Google", + .methods = &g_gralloc1_methods, +}; + +static int gralloc1_device_close(hw_device_t*) { + // No-op + return 0; +} + +static void gralloc1_getCapabilities(gralloc1_device_t*, uint32_t* outCount, int32_t*) { + *outCount = 0U; +} + +static int32_t gralloc1_lock(gralloc1_device_t*, buffer_handle_t buffer, uint64_t producerUsage, + uint64_t consumerUsage, const gralloc1_rect_t* rect, void** outData, + int32_t) { + uint32_t resource_id = (uint32_t) reinterpret_cast<uintptr_t>(buffer); + std::map<uint32_t, Resource*>::iterator it; + it = Resource::map.find(resource_id); + if (it == Resource::map.end()) + return GRALLOC1_ERROR_BAD_HANDLE; + + Resource* res = it->second; + + // validate the lock rectangle + if (rect->width < 0 || rect->height < 0 || rect->left < 0 || rect->top < 0 || + (uint32_t)rect->width + (uint32_t)rect->left > res->args.width || + (uint32_t)rect->height + (uint32_t)rect->top > res->args.height) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + uint32_t bpp; + switch (res->args.format) { + case VIRGL_FORMAT_R8_UNORM: + bpp = 1U; + break; + case VIRGL_FORMAT_B5G6R5_UNORM: + bpp = 2U; + break; + default: + bpp = 4U; + break; + } + uint32_t stride = ALIGN(res->args.width * bpp, 16U); + *outData = (char*)res->linear + rect->top * stride + rect->left * bpp; + return GRALLOC1_ERROR_NONE; +} + +static int32_t gralloc1_unlock(gralloc1_device_t*, buffer_handle_t buffer, + int32_t* outReleaseFence) { + uint32_t resource_id = (uint32_t) reinterpret_cast<uintptr_t>(buffer); + std::map<uint32_t, Resource*>::iterator it; + it = Resource::map.find(resource_id); + if (it == Resource::map.end()) + return GRALLOC1_ERROR_BAD_HANDLE; + if (outReleaseFence) + *outReleaseFence = -1; + + return GRALLOC1_ERROR_NONE; +} + +static gralloc1_function_pointer_t gralloc1_getFunction(gralloc1_device_t*, int32_t descriptor) { + switch (descriptor) { + case GRALLOC1_FUNCTION_LOCK: + return reinterpret_cast<gralloc1_function_pointer_t>(&gralloc1_lock); + case GRALLOC1_FUNCTION_UNLOCK: + return reinterpret_cast<gralloc1_function_pointer_t>(&gralloc1_unlock); + default: + return nullptr; + } +} + +static gralloc1_device_t g_gralloc1_device = { + .common = + { + .tag = HARDWARE_DEVICE_TAG, + .module = &g_gralloc1_module, + .close = gralloc1_device_close, + }, + .getCapabilities = gralloc1_getCapabilities, + .getFunction = gralloc1_getFunction, +}; + +static int gralloc1_device_open(const hw_module_t* module, const char* id, hw_device_t** device) { + if (module != &g_gralloc1_module) + return -EINVAL; + if (strcmp(id, g_gralloc1_module.id)) + return -EINVAL; + *device = &g_gralloc1_device.common; + return 0; +} + +int hw_get_module(const char* id, const hw_module_t** module) { + if (strcmp(id, g_gralloc1_module.id)) + return -EINVAL; + *module = const_cast<const hw_module_t*>(&g_gralloc1_module); + return 0; +} + +int sync_wait(int, int) { + return 0; +} diff --git a/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.cpp b/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40cf7fc37fe0b46763500ada6ca9721ff6017ac4 --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <OpenGLESDispatch/EGLDispatch.h> + +#include <dlfcn.h> +#include <stdio.h> + +EGLDispatch s_egl; + +#define DEFAULT_EGL_LIB "libEGL_swiftshader.so" + +#define EGL_LOAD_FIELD(return_type, function_name, signature, callargs) \ + s_egl.function_name = (function_name##_t)dlsym(handle, #function_name); + +#define EGL_LOAD_FIELD_WITH_EGL(return_type, function_name, signature, callargs) \ + if ((!s_egl.function_name) && s_egl.eglGetProcAddress) \ + s_egl.function_name = (function_name##_t)s_egl.eglGetProcAddress(#function_name); + +#define EGL_LOAD_OPTIONAL_FIELD(return_type, function_name, signature, callargs) \ + if (s_egl.eglGetProcAddress) \ + s_egl.function_name = (function_name##_t)s_egl.eglGetProcAddress(#function_name); \ + if (!s_egl.function_name || !s_egl.eglGetProcAddress) \ + EGL_LOAD_FIELD(return_type, function_name, signature, callargs) + +bool egl_dispatch_init() { + void* handle = dlopen(DEFAULT_EGL_LIB, RTLD_NOW); + if (!handle) { + printf("Failed to open %s\n", dlerror()); + return false; + } + + LIST_EGL_FUNCTIONS(EGL_LOAD_FIELD) + LIST_EGL_FUNCTIONS(EGL_LOAD_FIELD_WITH_EGL) + LIST_EGL_EXTENSIONS_FUNCTIONS(EGL_LOAD_OPTIONAL_FIELD) + + return true; +} diff --git a/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.h b/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.h new file mode 100644 index 0000000000000000000000000000000000000000..13c60787370a749ba1adbc2610e3352313e9b656 --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/EGLDispatch.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <egl_functions.h> +#include <egl_extensions_functions.h> + +#define EGL_DEFINE_TYPE(return_type, function_name, signature, callargs) \ + typedef return_type(EGLAPIENTRY* function_name##_t) signature; + +#define EGL_DECLARE_MEMBER(return_type, function_name, signature, callargs) \ + function_name##_t function_name; + +LIST_EGL_FUNCTIONS(EGL_DEFINE_TYPE) +LIST_EGL_EXTENSIONS_FUNCTIONS(EGL_DEFINE_TYPE) + +struct EGLDispatch { + LIST_EGL_FUNCTIONS(EGL_DECLARE_MEMBER) + LIST_EGL_EXTENSIONS_FUNCTIONS(EGL_DECLARE_MEMBER) +}; + +bool egl_dispatch_init(); + +extern EGLDispatch s_egl; diff --git a/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.cpp b/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd25afc5d28a544dcf50b7a08f1f8c5c9e30417b --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <OpenGLESDispatch/EGLDispatch.h> +#include <OpenGLESDispatch/GLESv1Dispatch.h> + +#include <dlfcn.h> +#include <stdio.h> + +#define DEFAULT_GLES_CM_LIB "libGLES_CM_swiftshader.so" + +GLESv1Dispatch s_gles1; + +#define LOOKUP_SYMBOL(return_type, function_name, signature, callargs) \ + s_gles1.function_name = (function_name##_t)dlsym(handle, #function_name); \ + if ((!s_gles1.function_name) && s_egl.eglGetProcAddress) \ + s_gles1.function_name = (function_name##_t)s_egl.eglGetProcAddress(#function_name); + +bool gles1_dispatch_init() { + void* handle = dlopen(DEFAULT_GLES_CM_LIB, RTLD_NOW); + if (!handle) { + printf("Failed to open %s\n", dlerror()); + return false; + } + + LIST_GLES1_FUNCTIONS(LOOKUP_SYMBOL, LOOKUP_SYMBOL) + + return true; +} diff --git a/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.h b/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.h new file mode 100644 index 0000000000000000000000000000000000000000..b65b83cdcb8fb27df2293cb5b6134d1d0010eeba --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/GLESv1Dispatch.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <GLES/gl.h> + +#include <OpenGLESDispatch/gles_functions.h> + +#define GLES1_DISPATCH_DEFINE_TYPE(return_type, func_name, signature, callargs) \ + typedef return_type(KHRONOS_APIENTRY* func_name##_t) signature; + +#define GLES1_DISPATCH_DECLARE_POINTER(return_type, func_name, signature, callargs) \ + func_name##_t func_name; + +LIST_GLES1_FUNCTIONS(GLES1_DISPATCH_DEFINE_TYPE, GLES1_DISPATCH_DEFINE_TYPE) + +struct GLESv1Dispatch { + LIST_GLES1_FUNCTIONS(GLES1_DISPATCH_DECLARE_POINTER, GLES1_DISPATCH_DECLARE_POINTER) +}; + +#undef GLES1_DISPATCH_DEFINE_TYPE +#undef GLES1_DISPATCH_DECLARE_POINTER + +bool gles1_dispatch_init(); + +extern GLESv1Dispatch s_gles1; diff --git a/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.cpp b/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4aaa5180c45d35602a5f099d70f1e59cb6a7a19e --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <OpenGLESDispatch/EGLDispatch.h> +#include <OpenGLESDispatch/GLESv3Dispatch.h> + +#include <dlfcn.h> +#include <stdio.h> + +#define DEFAULT_GLESv2_LIB "libGLESv2_swiftshader.so" + +GLESv3Dispatch s_gles3; + +#define LOOKUP_SYMBOL(return_type, function_name, signature, callargs) \ + s_gles3.function_name = (function_name##_t)dlsym(handle, #function_name); \ + if ((!s_gles3.function_name) && s_egl.eglGetProcAddress) \ + s_gles3.function_name = (function_name##_t)s_egl.eglGetProcAddress(#function_name); + +bool gles3_dispatch_init() { + void* handle = dlopen(DEFAULT_GLESv2_LIB, RTLD_NOW); + if (!handle) { + printf("Failed to open %s\n", dlerror()); + return false; + } + + LIST_GLES3_FUNCTIONS(LOOKUP_SYMBOL, LOOKUP_SYMBOL) + + return true; +} diff --git a/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.h b/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.h new file mode 100644 index 0000000000000000000000000000000000000000..afdd0007d4bcec527998926cccb9fb42184a5c00 --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/GLESv3Dispatch.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <GLES3/gl31.h> + +#include <OpenGLESDispatch/gles_functions.h> + +// Define function pointer types. +#define GLES3_DISPATCH_DEFINE_TYPE(return_type, func_name, signature, callargs) \ + typedef return_type(KHRONOS_APIENTRY* func_name##_t) signature; + +#define GLES3_DISPATCH_DECLARE_POINTER(return_type, func_name, signature, callargs) \ + func_name##_t func_name; + +LIST_GLES3_FUNCTIONS(GLES3_DISPATCH_DEFINE_TYPE, GLES3_DISPATCH_DEFINE_TYPE) + +struct GLESv3Dispatch { + LIST_GLES3_FUNCTIONS(GLES3_DISPATCH_DECLARE_POINTER, GLES3_DISPATCH_DECLARE_POINTER) +}; + +#undef GLES3_DISPATCH_DEFINE_TYPE +#undef GLES3_DISPATCH_DECLARE_POINTER + +bool gles3_dispatch_init(); + +extern GLESv3Dispatch s_gles3; diff --git a/host/libs/virglrenderer/OpenGLESDispatch/egl.entries b/host/libs/virglrenderer/OpenGLESDispatch/egl.entries new file mode 100644 index 0000000000000000000000000000000000000000..46d4c0dd8bb9ecbe24fdabcdc7d234839bfa5265 --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/egl.entries @@ -0,0 +1,44 @@ +!egl + +%#include <EGL/egl.h> + +%// Return types must be single words, see GLDispatch.cpp +%typedef const char* EGLconstcharptr; + +EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); +EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); +EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); +EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); +EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list); +EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); +EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx); +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface); +EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); +EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); +EGLDisplay eglGetCurrentDisplay(void); +EGLSurface eglGetCurrentSurface(EGLint readdraw); +EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id); +EGLint eglGetError(void); +void* eglGetProcAddress(const char *procname); +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); +EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); +EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); +EGLconstcharptr eglQueryString(EGLDisplay dpy, EGLint name); +EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); +EGLBoolean eglTerminate(EGLDisplay dpy); +EGLBoolean eglWaitGL(void); +EGLBoolean eglWaitNative(EGLint engine); + +EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); +EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval); + +EGLBoolean eglBindAPI(EGLenum api); +EGLenum eglQueryAPI(void); +EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list); +EGLBoolean eglReleaseThread(void); +EGLBoolean eglWaitClient(void); + +EGLContext eglGetCurrentContext(void); diff --git a/host/libs/virglrenderer/OpenGLESDispatch/egl_extensions.entries b/host/libs/virglrenderer/OpenGLESDispatch/egl_extensions.entries new file mode 100644 index 0000000000000000000000000000000000000000..e1e0bc7ded4c98e7adf257f1f512d0b216177d65 --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/egl_extensions.entries @@ -0,0 +1,11 @@ +!egl_extensions + +%#include <EGL/eglext.h> + +EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); +EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync); +EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); +EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); + +EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); +EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image); diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles1_core.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles1_core.entries new file mode 100644 index 0000000000000000000000000000000000000000..8c7f95376499fddfafdc084d2512eea1f5e188a1 --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/gles1_core.entries @@ -0,0 +1,153 @@ +!gles1_core + +%#include <GLES/gl.h> + +%// Return types must be single words, see GLDispatch.cpp +%typedef const GLubyte* GL1constubyteptr; + +void glAlphaFunc(GLenum func, GLclampf ref); +void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +void glClearDepthf(GLclampf depth); +void glClipPlanef(GLenum plane, const GLfloat *equation); +void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void glDepthRangef(GLclampf zNear, GLclampf zFar); +void glFogf(GLenum pname, GLfloat param); +void glFogfv(GLenum pname, const GLfloat *params); +void glFrustumf(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); +void glGetClipPlanef(GLenum pname, GLfloat *eqn); +void glGetFloatv(GLenum pname, GLfloat *params); +void glGetLightfv(GLenum light, GLenum pname, GLfloat *params); +void glGetMaterialfv(GLenum face, GLenum pname, GLfloat *params); +void glGetTexEnvfv(GLenum env, GLenum pname, GLfloat *params); +void glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params); +void glLightModelf(GLenum pname, GLfloat param); +void glLightModelfv(GLenum pname, const GLfloat *params); +void glLightf(GLenum light, GLenum pname, GLfloat param); +void glLightfv(GLenum light, GLenum pname, const GLfloat *params); +void glLineWidth(GLfloat width); +void glLoadMatrixf(const GLfloat *m); +void glMaterialf(GLenum face, GLenum pname, GLfloat param); +void glMaterialfv(GLenum face, GLenum pname, const GLfloat *params); +void glMultMatrixf(const GLfloat *m); +void glMultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz); +void glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); +void glPointParameterf(GLenum pname, GLfloat param); +void glPointParameterfv(GLenum pname, const GLfloat *params); +void glPointSize(GLfloat size); +void glPolygonOffset(GLfloat factor, GLfloat units); +void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +void glScalef(GLfloat x, GLfloat y, GLfloat z); +void glTexEnvf(GLenum target, GLenum pname, GLfloat param); +void glTexEnvfv(GLenum target, GLenum pname, const GLfloat *params); +void glTexParameterf(GLenum target, GLenum pname, GLfloat param); +void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params); +void glTranslatef(GLfloat x, GLfloat y, GLfloat z); +void glActiveTexture(GLenum texture); +void glAlphaFuncx(GLenum func, GLclampx ref); +void glBindBuffer(GLenum target, GLuint buffer); +void glBindTexture(GLenum target, GLuint texture); +void glBlendFunc(GLenum sfactor, GLenum dfactor); +void glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); +void glClear(GLbitfield mask); +void glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha); +void glClearDepthx(GLclampx depth); +void glClearStencil(GLint s); +void glClientActiveTexture(GLenum texture); +void glClipPlanex(GLenum plane, const GLfixed *equation); +void glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +void glColor4x(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +void glCullFace(GLenum mode); +void glDeleteBuffers(GLsizei n, const GLuint *buffers); +void glDeleteTextures(GLsizei n, const GLuint *textures); +void glDepthFunc(GLenum func); +void glDepthMask(GLboolean flag); +void glDepthRangex(GLclampx zNear, GLclampx zFar); +void glDisable(GLenum cap); +void glDisableClientState(GLenum array); +void glDrawArrays(GLenum mode, GLint first, GLsizei count); +void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +void glEnable(GLenum cap); +void glEnableClientState(GLenum array); +void glFinish(void); +void glFlush(void); +void glFogx(GLenum pname, GLfixed param); +void glFogxv(GLenum pname, const GLfixed *params); +void glFrontFace(GLenum mode); +void glFrustumx(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); +void glGetBooleanv(GLenum pname, GLboolean *params); +void glGetBufferParameteriv(GLenum target, GLenum pname, GLint *params); +void glGetClipPlanex(GLenum pname, GLfixed *eqn); +void glGenBuffers(GLsizei n, GLuint *buffers); +void glGenTextures(GLsizei n, GLuint *textures); +GLenum glGetError(void); +void glGetFixedv(GLenum pname, GLfixed *params); +void glGetIntegerv(GLenum pname, GLint *params); +void glGetLightxv(GLenum light, GLenum pname, GLfixed *params); +void glGetMaterialxv(GLenum face, GLenum pname, GLfixed *params); +void glGetPointerv(GLenum pname, GLvoid **params); +GL1constubyteptr glGetString(GLenum name); +void glGetTexEnviv(GLenum env, GLenum pname, GLint *params); +void glGetTexEnvxv(GLenum env, GLenum pname, GLfixed *params); +void glGetTexParameteriv(GLenum target, GLenum pname, GLint *params); +void glGetTexParameterxv(GLenum target, GLenum pname, GLfixed *params); +void glHint(GLenum target, GLenum mode); +GLboolean glIsBuffer(GLuint buffer); +GLboolean glIsEnabled(GLenum cap); +GLboolean glIsTexture(GLuint texture); +void glLightModelx(GLenum pname, GLfixed param); +void glLightModelxv(GLenum pname, const GLfixed *params); +void glLightx(GLenum light, GLenum pname, GLfixed param); +void glLightxv(GLenum light, GLenum pname, const GLfixed *params); +void glLineWidthx(GLfixed width); +void glLoadIdentity(void); +void glLoadMatrixx(const GLfixed *m); +void glLogicOp(GLenum opcode); +void glMaterialx(GLenum face, GLenum pname, GLfixed param); +void glMaterialxv(GLenum face, GLenum pname, const GLfixed *params); +void glMatrixMode(GLenum mode); +void glMultMatrixx(const GLfixed *m); +void glMultiTexCoord4x(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q); +void glNormal3x(GLfixed nx, GLfixed ny, GLfixed nz); +void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer); +void glOrthox(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); +void glPixelStorei(GLenum pname, GLint param); +void glPointParameterx(GLenum pname, GLfixed param); +void glPointParameterxv(GLenum pname, const GLfixed *params); +void glPointSizex(GLfixed size); +void glPolygonOffsetx(GLfixed factor, GLfixed units); +void glPopMatrix(void); +void glPushMatrix(void); +void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +void glRotatex(GLfixed angle, GLfixed x, GLfixed y, GLfixed z); +void glSampleCoverage(GLclampf value, GLboolean invert); +void glSampleCoveragex(GLclampx value, GLboolean invert); +void glScalex(GLfixed x, GLfixed y, GLfixed z); +void glScissor(GLint x, GLint y, GLsizei width, GLsizei height); +void glShadeModel(GLenum mode); +void glStencilFunc(GLenum func, GLint ref, GLuint mask); +void glStencilMask(GLuint mask); +void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass); +void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void glTexEnvi(GLenum target, GLenum pname, GLint param); +void glTexEnvx(GLenum target, GLenum pname, GLfixed param); +void glTexEnviv(GLenum target, GLenum pname, const GLint *params); +void glTexEnvxv(GLenum target, GLenum pname, const GLfixed *params); +void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void glTexParameteri(GLenum target, GLenum pname, GLint param); +void glTexParameterx(GLenum target, GLenum pname, GLfixed param); +void glTexParameteriv(GLenum target, GLenum pname, const GLint *params); +void glTexParameterxv(GLenum target, GLenum pname, const GLfixed *params); +void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void glTranslatex(GLfixed x, GLfixed y, GLfixed z); +void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void glViewport(GLint x, GLint y, GLsizei width, GLsizei height); + +void glPointSizePointerOES(GLenum type, GLsizei stride, const GLvoid *pointer); diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles1_extensions.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles1_extensions.entries new file mode 100644 index 0000000000000000000000000000000000000000..a2e990acf2798089525b6f4a7090092c03179bf5 --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/gles1_extensions.entries @@ -0,0 +1,35 @@ +!gles1_extensions + +%#include <GLES/glext.h> + +void glBlendEquationSeparateOES(GLenum modeRGB, GLenum modeAlpha); +void glBlendFuncSeparateOES(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +void glBlendEquationOES(GLenum mode); + +void glDrawTexsOES(GLshort x, GLshort y, GLshort z, GLshort width, GLshort height); +void glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height); +void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height); +void glDrawTexsvOES(const GLshort *coords); +void glDrawTexivOES(const GLint *coords); +void glDrawTexxvOES(const GLfixed *coords); +void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height); +void glDrawTexfvOES(const GLfloat *coords); + +void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image); +void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image); + +GLboolean glIsRenderbufferOES(GLuint renderbuffer); +void glBindRenderbufferOES(GLenum target, GLuint renderbuffer); +void glDeleteRenderbuffersOES(GLsizei n, const GLuint* renderbuffers); +void glGenRenderbuffersOES(GLsizei n, GLuint* renderbuffers); +void glRenderbufferStorageOES(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +void glGetRenderbufferParameterivOES(GLenum target, GLenum pname, GLint* params); +GLboolean glIsFramebufferOES(GLuint framebuffer); +void glBindFramebufferOES(GLenum target, GLuint framebuffer); +void glDeleteFramebuffersOES(GLsizei n, const GLuint* framebuffers); +void glGenFramebuffersOES(GLsizei n, GLuint* framebuffers); +GLenum glCheckFramebufferStatusOES(GLenum target); +void glFramebufferRenderbufferOES(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +void glFramebufferTexture2DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +void glGetFramebufferAttachmentParameterivOES(GLenum target, GLenum attachment, GLenum pname, GLint* params); +void glGenerateMipmapOES(GLenum target); diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles2_core.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles2_core.entries new file mode 100644 index 0000000000000000000000000000000000000000..6cab5f8fa1d26598ba4a2150ac0903e7b990b63a --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/gles2_core.entries @@ -0,0 +1,146 @@ +!gles2_core + +%#include <GLES3/gl31.h> + +void glActiveTexture(GLenum texture); +void glAttachShader(GLuint program, GLuint shader); +void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name); +void glBindBuffer(GLenum target, GLuint buffer); +void glBindFramebuffer(GLenum target, GLuint framebuffer); +void glBindRenderbuffer(GLenum target, GLuint renderbuffer); +void glBindTexture(GLenum target, GLuint texture); +void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void glBlendEquation(GLenum mode); +void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); +void glBlendFunc(GLenum sfactor, GLenum dfactor); +void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage); +void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLenum glCheckFramebufferStatus(GLenum target); +void glClear(GLbitfield mask); +void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void glClearDepthf(GLfloat d); +void glClearStencil(GLint s); +void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +void glCompileShader(GLuint shader); +void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLuint glCreateProgram(void); +GLuint glCreateShader(GLenum type); +void glCullFace(GLenum mode); +void glDeleteBuffers(GLsizei n, const GLuint *buffers); +void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers); +void glDeleteProgram(GLuint program); +void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers); +void glDeleteShader(GLuint shader); +void glDeleteTextures(GLsizei n, const GLuint *textures); +void glDepthFunc(GLenum func); +void glDepthMask(GLboolean flag); +void glDepthRangef(GLfloat n, GLfloat f); +void glDetachShader(GLuint program, GLuint shader); +void glDisable(GLenum cap); +void glDisableVertexAttribArray(GLuint index); +void glDrawArrays(GLenum mode, GLint first, GLsizei count); +void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices); +void glEnable(GLenum cap); +void glEnableVertexAttribArray(GLuint index); +void glFinish(void); +void glFlush(void); +void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +void glFrontFace(GLenum mode); +void glGenBuffers(GLsizei n, GLuint *buffers); +void glGenerateMipmap(GLenum target); +void glGenFramebuffers(GLsizei n, GLuint *framebuffers); +void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers); +void glGenTextures(GLsizei n, GLuint *textures); +void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +void glGetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLint glGetAttribLocation(GLuint program, const GLchar *name); +void glGetBooleanv(GLenum pname, GLboolean *data); +void glGetBufferParameteriv(GLenum target, GLenum pname, GLint *params); +GLenum glGetError(void); +void glGetFloatv(GLenum pname, GLfloat *data); +void glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params); +void glGetIntegerv(GLenum pname, GLint *data); +void glGetProgramiv(GLuint program, GLenum pname, GLint *params); +void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params); +void glGetShaderiv(GLuint shader, GLenum pname, GLint *params); +void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +void glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +void glGetShaderSource(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +const GLubyte *glGetString(GLenum name); +void glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params); +void glGetTexParameteriv(GLenum target, GLenum pname, GLint *params); +void glGetUniformfv(GLuint program, GLint location, GLfloat *params); +void glGetUniformiv(GLuint program, GLint location, GLint *params); +GLint glGetUniformLocation(GLuint program, const GLchar *name); +void glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params); +void glGetVertexAttribiv(GLuint index, GLenum pname, GLint *params); +void glGetVertexAttribPointerv(GLuint index, GLenum pname, void **pointer); +void glHint(GLenum target, GLenum mode); +GLboolean glIsBuffer(GLuint buffer); +GLboolean glIsEnabled(GLenum cap); +GLboolean glIsFramebuffer(GLuint framebuffer); +GLboolean glIsProgram(GLuint program); +GLboolean glIsRenderbuffer(GLuint renderbuffer); +GLboolean glIsShader(GLuint shader); +GLboolean glIsTexture(GLuint texture); +void glLineWidth(GLfloat width); +void glLinkProgram(GLuint program); +void glPixelStorei(GLenum pname, GLint param); +void glPolygonOffset(GLfloat factor, GLfloat units); +void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +void glReleaseShaderCompiler(void); +void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +void glSampleCoverage(GLfloat value, GLboolean invert); +void glScissor(GLint x, GLint y, GLsizei width, GLsizei height); +void glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); +void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +void glStencilFunc(GLenum func, GLint ref, GLuint mask); +void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); +void glStencilMask(GLuint mask); +void glStencilMaskSeparate(GLenum face, GLuint mask); +void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass); +void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +void glTexParameterf(GLenum target, GLenum pname, GLfloat param); +void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params); +void glTexParameteri(GLenum target, GLenum pname, GLint param); +void glTexParameteriv(GLenum target, GLenum pname, const GLint *params); +void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +void glUniform1f(GLint location, GLfloat v0); +void glUniform1fv(GLint location, GLsizei count, const GLfloat *value); +void glUniform1i(GLint location, GLint v0); +void glUniform1iv(GLint location, GLsizei count, const GLint *value); +void glUniform2f(GLint location, GLfloat v0, GLfloat v1); +void glUniform2fv(GLint location, GLsizei count, const GLfloat *value); +void glUniform2i(GLint location, GLint v0, GLint v1); +void glUniform2iv(GLint location, GLsizei count, const GLint *value); +void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +void glUniform3fv(GLint location, GLsizei count, const GLfloat *value); +void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2); +void glUniform3iv(GLint location, GLsizei count, const GLint *value); +void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +void glUniform4fv(GLint location, GLsizei count, const GLfloat *value); +void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +void glUniform4iv(GLint location, GLsizei count, const GLint *value); +void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glUseProgram(GLuint program); +void glValidateProgram(GLuint program); +void glVertexAttrib1f(GLuint index, GLfloat x); +void glVertexAttrib1fv(GLuint index, const GLfloat *v); +void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y); +void glVertexAttrib2fv(GLuint index, const GLfloat *v); +void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z); +void glVertexAttrib3fv(GLuint index, const GLfloat *v); +void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void glVertexAttrib4fv(GLuint index, const GLfloat *v); +void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +void glViewport(GLint x, GLint y, GLsizei width, GLsizei height); diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles2_extensions.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles2_extensions.entries new file mode 100644 index 0000000000000000000000000000000000000000..1453e874400eb5167f32fbca2e052643d66bb4da --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/gles2_extensions.entries @@ -0,0 +1,20 @@ +!gles2_extensions + +%#include <GLES2/gl2ext.h> + +void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image); +void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image); + +void glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +void glTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +void glCopyTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +void glCompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +void glCompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +void glFramebufferTexture3DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); + +void glDrawBuffersEXT(GLsizei n, const GLenum *bufs); + +void glDrawArraysInstancedEXT(GLenum mode, GLint start, GLsizei count, GLsizei primcount); +void glDrawElementsInstancedEXT(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); + +void glVertexAttribDivisorEXT(GLuint index, GLuint divisor); diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles31_only.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles31_only.entries new file mode 100644 index 0000000000000000000000000000000000000000..53cc1e1991783012e60d63f7af4bc58ef9ccee20 --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/gles31_only.entries @@ -0,0 +1,72 @@ +!gles31_only + +%#include <GLES3/gl31.h> + +void glDispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +void glDispatchComputeIndirect(GLintptr indirect); +void glDrawArraysIndirect(GLenum mode, const void *indirect); +void glDrawElementsIndirect(GLenum mode, GLenum type, const void *indirect); +void glFramebufferParameteri(GLenum target, GLenum pname, GLint param); +void glGetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params); +void glGetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint *params); +GLuint glGetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar *name); +void glGetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +void glGetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +GLint glGetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar *name); +void glUseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program); +void glActiveShaderProgram(GLuint pipeline, GLuint program); +GLuint glCreateShaderProgramv(GLenum type, GLsizei count, const GLchar *const*strings); +void glBindProgramPipeline(GLuint pipeline); +void glDeleteProgramPipelines(GLsizei n, const GLuint *pipelines); +void glGenProgramPipelines(GLsizei n, GLuint *pipelines); +GLboolean glIsProgramPipeline(GLuint pipeline); +void glGetProgramPipelineiv(GLuint pipeline, GLenum pname, GLint *params); +void glProgramUniform1i(GLuint program, GLint location, GLint v0); +void glProgramUniform2i(GLuint program, GLint location, GLint v0, GLint v1); +void glProgramUniform3i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +void glProgramUniform4i(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +void glProgramUniform1ui(GLuint program, GLint location, GLuint v0); +void glProgramUniform2ui(GLuint program, GLint location, GLuint v0, GLuint v1); +void glProgramUniform3ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +void glProgramUniform4ui(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +void glProgramUniform1f(GLuint program, GLint location, GLfloat v0); +void glProgramUniform2f(GLuint program, GLint location, GLfloat v0, GLfloat v1); +void glProgramUniform3f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +void glProgramUniform4f(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +void glProgramUniform1iv(GLuint program, GLint location, GLsizei count, const GLint *value); +void glProgramUniform2iv(GLuint program, GLint location, GLsizei count, const GLint *value); +void glProgramUniform3iv(GLuint program, GLint location, GLsizei count, const GLint *value); +void glProgramUniform4iv(GLuint program, GLint location, GLsizei count, const GLint *value); +void glProgramUniform1uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); +void glProgramUniform2uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); +void glProgramUniform3uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); +void glProgramUniform4uiv(GLuint program, GLint location, GLsizei count, const GLuint *value); +void glProgramUniform1fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); +void glProgramUniform2fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); +void glProgramUniform3fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); +void glProgramUniform4fv(GLuint program, GLint location, GLsizei count, const GLfloat *value); +void glProgramUniformMatrix2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glProgramUniformMatrix3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glProgramUniformMatrix4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glProgramUniformMatrix2x3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glProgramUniformMatrix3x2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glProgramUniformMatrix2x4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glProgramUniformMatrix4x2fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glProgramUniformMatrix3x4fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glProgramUniformMatrix4x3fv(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glValidateProgramPipeline(GLuint pipeline); +void glGetProgramPipelineInfoLog(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +void glBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +void glGetBooleani_v(GLenum target, GLuint index, GLboolean *data); +void glMemoryBarrier(GLbitfield barriers); +void glMemoryBarrierByRegion(GLbitfield barriers); +void glTexStorage2DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +void glGetMultisamplefv(GLenum pname, GLuint index, GLfloat *val); +void glSampleMaski(GLuint maskNumber, GLbitfield mask); +void glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params); +void glGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params); +void glBindVertexBuffer(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +void glVertexAttribFormat(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +void glVertexAttribIFormat(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +void glVertexAttribBinding(GLuint attribindex, GLuint bindingindex); +void glVertexBindingDivisor(GLuint bindingindex, GLuint divisor); diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles3_only.entries b/host/libs/virglrenderer/OpenGLESDispatch/gles3_only.entries new file mode 100644 index 0000000000000000000000000000000000000000..9742d382e56e40c02363f7c85dee21a67c7c24ce --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/gles3_only.entries @@ -0,0 +1,111 @@ +!gles3_only + +%#include <GLES3/gl31.h> + +%// Return types must be single words, see GLDispatch.cpp +%typedef const GLubyte* GL3constubyteptr; + +void glReadBuffer(GLenum src); +void glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +void glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +void glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +void glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +void glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +void glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +void glGenQueries(GLsizei n, GLuint *ids); +void glDeleteQueries(GLsizei n, const GLuint *ids); +GLboolean glIsQuery(GLuint id); +void glBeginQuery(GLenum target, GLuint id); +void glEndQuery(GLenum target); +void glGetQueryiv(GLenum target, GLenum pname, GLint *params); +void glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params); +GLboolean glUnmapBuffer(GLenum target); +void glGetBufferPointerv(GLenum target, GLenum pname, void **params); +void glDrawBuffers(GLsizei n, const GLenum *bufs); +void glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +void glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +void glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +void glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); +void glBindVertexArray(GLuint array); +void glDeleteVertexArrays(GLsizei n, const GLuint *arrays); +void glGenVertexArrays(GLsizei n, GLuint *arrays); +GLboolean glIsVertexArray(GLuint array); +void glGetIntegeri_v(GLenum target, GLuint index, GLint *data); +void glBeginTransformFeedback(GLenum primitiveMode); +void glEndTransformFeedback(void); +void glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +void glBindBufferBase(GLenum target, GLuint index, GLuint buffer); +void glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +void glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +void glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +void glGetVertexAttribIiv(GLuint index, GLenum pname, GLint *params); +void glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params); +void glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w); +void glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +void glVertexAttribI4iv(GLuint index, const GLint *v); +void glVertexAttribI4uiv(GLuint index, const GLuint *v); +void glGetUniformuiv(GLuint program, GLint location, GLuint *params); +GLint glGetFragDataLocation(GLuint program, const GLchar *name); +void glUniform1ui(GLint location, GLuint v0); +void glUniform2ui(GLint location, GLuint v0, GLuint v1); +void glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2); +void glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +void glUniform1uiv(GLint location, GLsizei count, const GLuint *value); +void glUniform2uiv(GLint location, GLsizei count, const GLuint *value); +void glUniform3uiv(GLint location, GLsizei count, const GLuint *value); +void glUniform4uiv(GLint location, GLsizei count, const GLuint *value); +void glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value); +void glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value); +void glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value); +void glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GL3constubyteptr glGetStringi(GLenum name, GLuint index); +void glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +void glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +void glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +GLuint glGetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName); +void glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +void glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +void glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +GLsync glFenceSync(GLenum condition, GLbitfield flags); +GLboolean glIsSync(GLsync sync); +void glDeleteSync(GLsync sync); +GLenum glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); +void glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); +void glGetInteger64v(GLenum pname, GLint64 *data); +void glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +void glGetInteger64i_v(GLenum target, GLuint index, GLint64 *data); +void glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params); +void glGenSamplers(GLsizei count, GLuint *samplers); +void glDeleteSamplers(GLsizei count, const GLuint *samplers); +GLboolean glIsSampler(GLuint sampler); +void glBindSampler(GLuint unit, GLuint sampler); +void glSamplerParameteri(GLuint sampler, GLenum pname, GLint param); +void glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param); +void glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param); +void glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param); +void glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params); +void glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params); +void glVertexAttribDivisor(GLuint index, GLuint divisor); +void glBindTransformFeedback(GLenum target, GLuint id); +void glDeleteTransformFeedbacks(GLsizei n, const GLuint *ids); +void glGenTransformFeedbacks(GLsizei n, GLuint *ids); +GLboolean glIsTransformFeedback(GLuint id); +void glPauseTransformFeedback(void); +void glResumeTransformFeedback(void); +void glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +void glProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); +void glProgramParameteri(GLuint program, GLenum pname, GLint value); +void glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments); +void glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +void glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +void glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +void glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); diff --git a/host/libs/virglrenderer/OpenGLESDispatch/gles_functions.h b/host/libs/virglrenderer/OpenGLESDispatch/gles_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..1219391ce6c113d22a81536e92c7ed7183d34b55 --- /dev/null +++ b/host/libs/virglrenderer/OpenGLESDispatch/gles_functions.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "gles1_core_functions.h" +#include "gles1_extensions_functions.h" +#include "gles2_core_functions.h" +#include "gles2_extensions_functions.h" +#include "gles3_only_functions.h" +#include "gles31_only_functions.h" + +#define LIST_GLES1_FUNCTIONS(X, Y) \ + LIST_GLES1_CORE_FUNCTIONS(X) \ + LIST_GLES1_EXTENSIONS_FUNCTIONS(Y) \ + +#define LIST_GLES3_FUNCTIONS(X, Y) \ + LIST_GLES2_CORE_FUNCTIONS(X) \ + LIST_GLES2_EXTENSIONS_FUNCTIONS(Y) \ + LIST_GLES3_ONLY_FUNCTIONS(X) \ + LIST_GLES31_ONLY_FUNCTIONS(X) diff --git a/host/libs/virglrenderer/OpenglRender/IOStream.h b/host/libs/virglrenderer/OpenglRender/IOStream.h new file mode 100644 index 0000000000000000000000000000000000000000..82e5bdea5a81116cb4a377d5308dbb2e80ae7097 --- /dev/null +++ b/host/libs/virglrenderer/OpenglRender/IOStream.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <cstdio> +#include <cstdlib> + +class IOStream { + public: + IOStream(unsigned char* buf, size_t bufSize) : m_buf(buf), m_bufSize(bufSize) { + } + + unsigned char* alloc(size_t len) { + if (m_allocSize + len > m_bufSize) { + printf("Command response is too large.\n"); + return nullptr; + } + unsigned char* buf = m_buf + m_allocSize; + m_allocSize += len; + return buf; + } + + int flush() { + m_flushSize = m_allocSize; + return 0; + } + + void* getDmaForReading(uint64_t guest_paddr) { + // GLDMA is not supported, so we don't have to implement this. Just keep + // a stub here to keep the generated decoder stubs happy + return nullptr; + } + + void unlockDma(uint64_t guest_paddr) { + // GLDMA is not supported, so we don't have to implement this. Just keep + // a stub here to keep the generated decoder stubs happy + } + + size_t getFlushSize() { + return m_flushSize; + } + + private: + size_t m_allocSize = 0U; + size_t m_flushSize = 0U; + unsigned char* m_buf; + size_t m_bufSize; +}; diff --git a/host/libs/virglrenderer/ProtocolUtils.h b/host/libs/virglrenderer/ProtocolUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..fd0bebef3e5ac08df4482bba62dc9c8d43b8d9d5 --- /dev/null +++ b/host/libs/virglrenderer/ProtocolUtils.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +namespace emugl { + +// A helper template to extract values form the wire protocol stream +// and convert them to appropriate host values. +// +// The wire protocol uses 32-bit exclusively when transferring +// GLintptr or GLsizei values, as well as opaque handles like GLeglImage, +// from the guest (even when the guest is 64-bit). +// +// The corresponding host definitions depend on the host bitness. For +// example, GLintptr is 64-bit on linux-x86_64. The following is a set +// of templates that can simplify the conversion of protocol values +// into host ones. +// +// The most important one is: +// +// unpack<HOST_TYPE,SIZE_TYPE>(const void* ptr) +// +// Which reads bytes from |ptr|, using |SIZE_TYPE| as the underlying +// sized-integer specifier (e.g. 'uint32_t'), and converting the result +// into a |HOST_TYPE| value. For example: +// +// unpack<EGLImage,uint32_t>(ptr + 12); +// +// will read a 4-byte value from |ptr + 12| and convert it into +// an EGLImage, which is a host void*. The template detects host +// pointer types to perform proper type casting. +// +// TODO(digit): Add custom unpackers to handle generic opaque void* values. +// and map them to unique 32-bit values. + +template <typename T, typename S> +struct UnpackerT { + static T unpack(const void* ptr) { + static_assert(sizeof(T) == sizeof(S), + "Bad input arguments, have to be of the same size"); + return *(const T*)ptr; + } +}; + +template <typename T, typename S> +struct UnpackerT<T*, S> { + static T* unpack(const void* ptr) { + return (T*)(uintptr_t)(*(const S*)ptr); + } +}; + +template <> +struct UnpackerT<ssize_t, uint32_t> { + static ssize_t unpack(const void* ptr) { + return (ssize_t)*(const int32_t*)ptr; + } +}; + +template <typename T, typename S> +inline T Unpack(const void* ptr) { + return UnpackerT<T, S>::unpack(ptr); +} + +// Helper classes GenericInputBuffer and GenericOutputBuffer used to ensure +// input and output buffers passed to EGL/GL functions are properly aligned +// (preventing crashes with some backends). +// +// Usage example: +// +// GenericInputBuffer<> inputBuffer(ptrIn, sizeIn); +// GenericOutputBuffer<> outputBuffer(ptrOut, sizeOut); +// glDoGetStuff(inputBuffer.get(), outputBuffer.get()); +// outputBuffer.flush(); +// +// get() will return the original value of |ptr| if it was aligned on the +// configured boundary (8 bytes by default). Otherwise, it will return the +// address of an aligned copy of the original |size| bytes starting from |ptr|. +// +// Allowed alignment values are 1, 2, 4, 8. +// +// outputBuffer.flush() copies the content of the copy back to |ptr| explictly, +// if needed. It is a no-op if |ptr| was aligned. +// +// Both classes try to minimize heap usage as much as possible - the first +// template argument defines the size of an internal array Generic*Buffer-s use +// if the |ptr|'s |size| is small enough. If it doesn't fit into the internal +// array, an aligned copy is allocated on the heap and freed in the dtor. + +template <size_t StackSize = 1024, size_t Align = 8> +class GenericInputBuffer { + static_assert(Align == 1 || Align == 2 || Align == 4 || Align == 8, + "Bad alignment parameter"); + +public: + GenericInputBuffer(const void* input, size_t size) : mOrigBuff(input) { + if (((uintptr_t)input & (Align - 1U)) == 0) { + mPtr = const_cast<void*>(input); + } else { + if (size <= StackSize) { + mPtr = &mArray[0]; + } else { + mPtr = malloc(size); + } + memcpy(mPtr, input, size); + } + } + + ~GenericInputBuffer() { + if (mPtr != mOrigBuff && mPtr != &mArray[0]) { + free(mPtr); + } + } + + const void* get() const { return mPtr; } + +private: + // A pointer to the aligned buffer, might point either to mOrgBuf, to mArray + // start or to a heap-allocated chunk of data. + void* mPtr; + // Original buffer. + const void* mOrigBuff; + // Inplace aligned array for small enough buffers. + char __attribute__((__aligned__(Align))) mArray[StackSize]; +}; + +template <size_t StackSize = 1024, size_t Align = 8> +class GenericOutputBuffer { + static_assert(Align == 1 || Align == 2 || Align == 4 || Align == 8, + "Bad alignment parameter"); + +public: + GenericOutputBuffer(unsigned char* ptr, size_t size) : + mOrigBuff(ptr), mSize(size) { + if (((uintptr_t)ptr & (Align - 1U)) == 0) { + mPtr = ptr; + } else { + if (size <= StackSize) { + mPtr = &mArray[0]; + } else { + mPtr = calloc(1, size); + } + } + } + + ~GenericOutputBuffer() { + if (mPtr != mOrigBuff && mPtr != &mArray[0]) { + free(mPtr); + } + } + + void* get() const { return mPtr; } + + void flush() { + if (mPtr != mOrigBuff) { + memcpy(mOrigBuff, mPtr, mSize); + } + } + +private: + // A pointer to the aligned buffer, might point either to mOrgBuf, to mArray + // start or to a heap-allocated chunk of data. + void* mPtr; + // Original buffer. + unsigned char* mOrigBuff; + // Original buffer size. + size_t mSize; + // Inplace array for small enough buffers. + unsigned char __attribute__((__aligned__(Align))) mArray[StackSize]; +}; + +// Pin the defaults for the commonly used type names +using InputBuffer = GenericInputBuffer<>; +using OutputBuffer = GenericOutputBuffer<>; + +} // namespace emugl diff --git a/host/libs/virglrenderer/README.md b/host/libs/virglrenderer/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e9b13789cce489e25ada2be8cfc4d1ab367689cc --- /dev/null +++ b/host/libs/virglrenderer/README.md @@ -0,0 +1,112 @@ +# AVDVirglRenderer + +This project implements an alternative for 'virglrenderer', a part of the +Virgil 3D GPU project that normally implements the translation from the +virtio-gpu-3d command stream & tgsi/gallium shaders, to desktop OpenGL. + +This version of the library keeps translation to a minimum and only works with +a true EGL/GLES driver implementation on the host. It won't intercept and +translate shaders, and no part of the GL state machine is processed in the +emulated guest. + +The wire protocol used between the virtio-gpu DRM driver and QEMU's +virtio-gpu-3d device is the same as that used by goldfish (the classic Android +emulator). Submits (writes) are made with an `DRM_VIRTGPU_EXECBUFFER` call; the +response comes back through a separate memory mapped buffer. Responses are very +expensive and are minimized where possible, as they involve a pipeline flush and +roundtrip to the host. + +## Structure + +### [`AVDVirglRenderer`](AVDVirglRenderer.cpp)[](#AVDVirglRenderer) + +Provides the entrypoints expected by QEMU for its libvirglrenderer integration. + +This is where contexts, resources and fences are monitored. + +### [`RenderControl`](RenderControl.cpp) [`Header`](RenderControl.h) [`Decoder`](renderControl_dec)[](#RenderControl) + +The RenderControl is analogous to EGL on the guest side. It has a similar API to +EGL, except that not every EGL function can be implemented as one API call, and +instead multiple RenderControl calls are made. The RenderControl architecture +was precipitated by goldfish's requirement that EGL window surfaces and images +would be directly mapped to GL texture names, but in AVDVirglRenderer we +preserve them as EGL objects on the host side. + +This component contains a decoder for the wire protocol, and stubs for any +functions that we do not need to implement. The wire protocol is completely +unmodified. + +### [`GLESv1`](GLESv1.cpp) [`Header`](GLESv1.h) [`Decoder`](GLESv1_dec)[](#GLESv1) + +This component contains a decoder for the wire protocol, and stubs for any +functions that we do not need to implement. Only the GL ES 1.1 extensions +implemented by SwiftShader are implemented, and only if they are needed by +Android. Any extensions provided by the wire protocol that are not supported by +either are intentionally stubbed. + +### [`GLESv3`](GLESv3.cpp) [`Header`](GLESv3.h) [`Decoder`](GLESv3_dec)[](#GLESv3) + +This component contains a decoder for the wire protocol, and stubs for any +functions that we do not need to implement. Only the core GL ES 3.0 API is +implemented; no ES 2.0 extensions are supported, unless they are remappable to +GL ES 3.0 features. GL ES 3.1 is not currently supported. Any extensions +provided by the wire protocol that are not supported by either Android or +SwiftShader are intentionally stubbed. + +Note that we are *not* stubbing ES 3.1 functions; these will crash if called. + +### [`ChecksumCalculator`](OpenglRenderer/ChecksumCalculator.cpp)[`Header`](ChecksumCalculator.h)[](#ChecksumCalculator) + +This code was taken from the Android emulator. The header has been slightly +trimmed but its functionality has not been changed. + +### [`ChecksumCalculatorThreadInfo`](ChecksumCalculatorThreadInfo.h)[](#ChecksumCalculatorThreadInfo) + +This header has been added for compatibility with the decoder code generated by +the `emugen_cuttlefish` tool. Unlike the original implementation, it is not +thread safe. We do not require thread safety because no decoder state is shared +between threads in AVDVirglRenderer without its own locking. + +### [`Context`](Context.h)[](#Context) + +The Context structure represents a virglrenderer context assigned by QEMU. Each +time the driver's device node is opened by the guest, a new context is created. +In the design of AVDVirglRenderer, there are two kinds of context. The first +kind of context is for `gralloc`, and there is one of these contexts per guest +process. The second kind of context is per-thread, used by the EGL/GLES +implementation. This second kind of context can receive 3D commands, which are +processed in their own thread by AVDVirglRenderer so as to minimize the number +of synthetic calls we have to make (such as eglMakeCurrent()). + +### [`Resource`](Resource.h)[](#Resource) + +The Resource structure represents a virglrenderer resource assigned by QEMU. +Each time the driver allocates memory through the device driver's interface, a +new resource is created. Resources can be owned by the kernel (for example, the +primary framebuffer surfaces), Gralloc (EGL window surfaces or images), or used +for other purposes such as the Context response buffer and fencing. + +### [`EglConfig`](EglConfig.h)[](EglConfig) + +The EglConfig structure maintains a list of available EGLConfigs. + +### [`EglContext`](EglContext.h)[](EglContext) + +The EglContext structure maintains a list of active EGLContexts, and decides +when they can be disposed of. + +### [`EglImage`](EglImage.h)[](EglImage) + +The EglImage structure maintains a list of active EGLImageKHRs, and decides +when they can be disposed of. + +### [`EglSurface`](EglSurface.h)[](EglSurface) + +The EglSurface structure maintains a list of active EGLSurfaces, and decides +when they can be disposed of. + +### [`EglSync`](EglSync.h)[](EglSync) + +The EglSync structure maintains a list of active EGLSyncKHRs, and decides +when they can be disposed of. diff --git a/host/libs/virglrenderer/RenderControl.cpp b/host/libs/virglrenderer/RenderControl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd84eb5485cc74d91386d7db3cbc5c7078a5c94e --- /dev/null +++ b/host/libs/virglrenderer/RenderControl.cpp @@ -0,0 +1,868 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#undef NDEBUG + +#include "Context.h" +#include "EglConfig.h" +#include "EglContext.h" +#include "EglImage.h" +#include "EglSurface.h" +#include "EglSync.h" + +#include <cassert> +#include <cerrno> +#include <cstring> +#include <string> + +#include <unistd.h> + +#include <GLES/gl.h> +#include <GLES/glext.h> + +#include <OpenGLESDispatch/EGLDispatch.h> +#include <OpenGLESDispatch/GLESv1Dispatch.h> +#include <OpenGLESDispatch/GLESv3Dispatch.h> + +#include "virgl_hw.h" + +#include "RenderControl.h" + +#include <hardware/gralloc.h> +#include <hardware/gralloc1.h> +#include <nativebase/nativebase.h> +#include <system/window.h> + +static void incRefANWB(android_native_base_t* base) { + ANativeWindowBuffer* anwb = reinterpret_cast<ANativeWindowBuffer*>(base); + anwb->layerCount++; +} + +static void decRefANWB(android_native_base_t* base) { + ANativeWindowBuffer* anwb = reinterpret_cast<ANativeWindowBuffer*>(base); + if (anwb->layerCount > 0) { + anwb->layerCount--; + if (anwb->layerCount == 0) + delete anwb; + } +} +struct FakeANativeWindowBuffer : public ANativeWindowBuffer { + FakeANativeWindowBuffer() { + ANativeWindowBuffer(); + + common.incRef = incRefANWB; + common.decRef = decRefANWB; + layerCount = 0U; + } +}; + +static void incRefANW(android_native_base_t* base) { + ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(base); + anw->oem[0]++; +} + +static void decRefANW(android_native_base_t* base) { + ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(base); + if (anw->oem[0] > 0) { + anw->oem[0]--; + if (anw->oem[0] == 0) + delete anw; + } +} + +static int setSwapInterval(ANativeWindow*, int) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static int dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer) { + if (!window->oem[1]) + return -EINVAL; + *buffer = reinterpret_cast<ANativeWindowBuffer*>(window->oem[1]); + window->oem[1] = 0; + return 0; +} + +static int lockBuffer_DEPRECATED(ANativeWindow*, ANativeWindowBuffer*) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static int queueBuffer_DEPRECATED(ANativeWindow*, ANativeWindowBuffer*) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static int query(const ANativeWindow* window, int what, int* value) { + switch (what) { + case NATIVE_WINDOW_WIDTH: + return static_cast<int>(window->oem[2]); + case NATIVE_WINDOW_HEIGHT: + return static_cast<int>(window->oem[3]); + default: + return -EINVAL; + } +} + +static int perform(ANativeWindow*, int, ...) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static int cancelBuffer_DEPRECATED(ANativeWindow*, ANativeWindowBuffer*) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) { + *fenceFd = -1; + return dequeueBuffer_DEPRECATED(window, buffer); +} + +static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { + if (fenceFd >= 0) + close(fenceFd); + return queueBuffer_DEPRECATED(window, buffer); +} + +static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { + if (fenceFd >= 0) + close(fenceFd); + return cancelBuffer_DEPRECATED(window, buffer); +} + +struct FakeANativeWindow : public ANativeWindow { + FakeANativeWindow(uint32_t width, uint32_t height) { + ANativeWindow(); + + common.incRef = incRefANW; + common.decRef = decRefANW; + oem[0] = 0; + oem[2] = static_cast<intptr_t>(width); + oem[3] = static_cast<intptr_t>(height); + + this->setSwapInterval = ::setSwapInterval; + this->dequeueBuffer_DEPRECATED = ::dequeueBuffer_DEPRECATED; + this->lockBuffer_DEPRECATED = ::lockBuffer_DEPRECATED; + this->queueBuffer_DEPRECATED = ::queueBuffer_DEPRECATED; + this->query = ::query; + this->perform = ::perform; + this->cancelBuffer_DEPRECATED = ::cancelBuffer_DEPRECATED; + this->dequeueBuffer = ::dequeueBuffer; + this->queueBuffer = ::queueBuffer; + this->cancelBuffer = ::cancelBuffer; + } +}; + +// Helpers + +static ANativeWindowBuffer* resourceToANWB(Resource* res) { + ANativeWindowBuffer* buffer = new (std::nothrow) FakeANativeWindowBuffer(); + if (!buffer) + return nullptr; + + buffer->width = res->args.width; + buffer->height = res->args.height; + buffer->stride = res->args.width; + buffer->handle = reinterpret_cast<const native_handle_t*>(res->args.handle); + buffer->usage_deprecated = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER; + buffer->usage = + GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN | GRALLOC1_CONSUMER_USAGE_CPU_WRITE_OFTEN | + GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE | GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN | + GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN | GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET; + + switch (res->args.format) { + case VIRGL_FORMAT_B8G8R8A8_UNORM: + buffer->format = HAL_PIXEL_FORMAT_BGRA_8888; + break; + case VIRGL_FORMAT_B5G6R5_UNORM: + buffer->format = HAL_PIXEL_FORMAT_RGB_565; + break; + case VIRGL_FORMAT_R8G8B8A8_UNORM: + buffer->format = HAL_PIXEL_FORMAT_RGBA_8888; + break; + case VIRGL_FORMAT_R8G8B8X8_UNORM: + buffer->format = HAL_PIXEL_FORMAT_RGBX_8888; + break; + default: + delete buffer; + return nullptr; + } + + return buffer; +} + +// RenderControl + +static GLint rcGetRendererVersion() { + return 1; // seems to be hard-coded +} + +static EGLint rcGetEGLVersion(void* ctx_, EGLint* major, EGLint* minor) { + RenderControl* rc = static_cast<RenderControl*>(ctx_); + return s_egl.eglInitialize(rc->dpy, major, minor); +} + +static EGLint rcQueryEGLString(void* ctx_, EGLenum name, void* buffer, EGLint bufferSize) { + RenderControl* rc = static_cast<RenderControl*>(ctx_); + const char* str = s_egl.eglQueryString(rc->dpy, name); + if (!str) + str = ""; + + if (strlen(str) > (size_t)bufferSize) { + memset(buffer, 0, bufferSize); + return -strlen(str); + } + + char* strOut = static_cast<char*>(buffer); + strncpy(strOut, str, bufferSize - 1); + strOut[bufferSize - 1] = 0; + + return strlen(strOut) + 1U; +} + +static std::string replaceESVersionString(const std::string& prev, const char* const newver) { + // Do not touch ES 1.x contexts (they will all be 1.1 anyway) + if (prev.find("ES-CM") != std::string::npos) + return prev; + + size_t esStart = prev.find("ES "); + size_t esEnd = prev.find(" ", esStart + 3); + + // Do not change out-of-spec version strings. + if (esStart == std::string::npos || esEnd == std::string::npos) + return prev; + + std::string res = prev.substr(0, esStart + 3); + res += newver; + res += prev.substr(esEnd); + return res; +} + +static EGLint rcGetGLString(void* ctx_, EGLenum name, void* buffer, EGLint bufferSize) { + std::string glStr; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + if (rc->ctx->ctx) { + const char* str = nullptr; + switch (rc->ctx->ctx->api) { + case EglContext::GLESApi::GLESApi_CM: + str = reinterpret_cast<const char*>(s_gles1.glGetString(name)); + break; + default: + str = reinterpret_cast<const char*>(s_gles3.glGetString(name)); + break; + } + if (str) + glStr += str; + } + + // FIXME: Should probably filter the extensions list like the emulator + // does. We need to handle ES2 on ES3 compatibility for older + // Android versions, as well as filter out unsupported features. + + if (name == GL_EXTENSIONS) { + glStr += ChecksumCalculator::getMaxVersionStr(); + glStr += " "; + + // FIXME: Hard-coded to 3.0 for now. We should attempt to detect 3.1. + glStr += "ANDROID_EMU_gles_max_version_3_0"; + glStr += " "; + } + + // FIXME: Add support for async swap and the fence_sync extensions + + // We don't support GLDMA; use VIRTGPU_RESOURCE_CREATE and a combination of + // VIRTGPU_TRANSFER_TO_HOST and VIRTGPU_TRANSFER_FROM_HOST. + + // FIXME: Add support for 'no host error' + + if (name == GL_VERSION) + glStr = replaceESVersionString(glStr, "3.0"); + + int nextBufferSize = glStr.size() + 1; + + if (!buffer || nextBufferSize > bufferSize) + return -nextBufferSize; + + snprintf((char*)buffer, nextBufferSize, "%s", glStr.c_str()); + return nextBufferSize; +} + +static EGLint rcGetNumConfigs(uint32_t* numAttribs) { + *numAttribs = EglConfig::kNumAttribs; + return EglConfig::vec.size(); +} + +static EGLint rcGetConfigs(uint32_t bufSize, GLuint* buffer) { + size_t configAttribBytes = sizeof(EglConfig::kAttribs); + size_t nConfigs = EglConfig::vec.size(); + size_t sizeNeeded = configAttribBytes + nConfigs * configAttribBytes; + + if (bufSize < sizeNeeded) + return -sizeNeeded; + + memcpy(buffer, &EglConfig::kAttribs, configAttribBytes); + size_t offset = EglConfig::kNumAttribs; + for (auto const& config : EglConfig::vec) { + memcpy(&buffer[offset], config->attribs, configAttribBytes); + offset += EglConfig::kNumAttribs; + } + + return nConfigs; +} + +static EGLint rcChooseConfig(void* ctx_, EGLint* attribs, uint32_t, uint32_t* config_ints, + uint32_t configs_size) { + EGLint num_config; + EGLConfig configs[configs_size]; + RenderControl* rc = static_cast<RenderControl*>(ctx_); + EGLBoolean ret = s_egl.eglChooseConfig(rc->dpy, attribs, configs, configs_size, &num_config); + if (!ret) + num_config = 0; + + if (configs_size) { + for (EGLint i = 0; i < num_config; i++) { + config_ints[i] = ~0U; + EGLint config_id; + if (s_egl.eglGetConfigAttrib(rc->dpy, configs[i], EGL_CONFIG_ID, &config_id)) { + for (size_t i = 0; i < EglConfig::vec.size(); i++) { + if (EglConfig::vec[i]->attribs[4] == config_id) + config_ints[i] = i; + } + } + if (config_ints[i] == ~0U) { + num_config = 0; + break; + } + } + if (!num_config) + memset(config_ints, 0, configs_size * sizeof(uint32_t)); + } + + return num_config; +} + +static EGLint rcGetFBParam(EGLint) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static uint32_t rcCreateContext(void* ctx_, uint32_t config_, uint32_t share_, uint32_t glVersion) { + // clang-format off + EGLint attrib_list[] = { + EGL_CONTEXT_CLIENT_VERSION, 0, + EGL_CONTEXT_MINOR_VERSION_KHR, 0, + EGL_NONE + }; + // clang-format on + switch (glVersion) { + case EglContext::GLESApi::GLESApi_CM: + attrib_list[1] = 1; + attrib_list[3] = 1; + break; + case EglContext::GLESApi::GLESApi_2: + attrib_list[1] = 2; + break; + case EglContext::GLESApi::GLESApi_3_0: + attrib_list[1] = 3; + break; + case EglContext::GLESApi::GLESApi_3_1: + attrib_list[1] = 3; + attrib_list[3] = 1; + break; + } + if (!attrib_list[1]) + return 0U; + + if (config_ > EglConfig::vec.size()) + return 0U; + EglConfig const* config = EglConfig::vec[config_]; + + EGLContext share_context = EGL_NO_CONTEXT; + if (share_ > 0) { + std::map<uint32_t, EglContext*>::iterator context_it; + context_it = EglContext::map.find(share_); + if (context_it == EglContext::map.end()) + return 0U; + + EglContext const* share = context_it->second; + share_context = share->context; + } + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + EGLContext context_ = + s_egl.eglCreateContext(rc->dpy, config->config, share_context, attrib_list); + if (context_ == EGL_NO_CONTEXT) + return 0U; + + EglContext* context = new (std::nothrow) + EglContext(context_, rc->ctx->handle, (enum EglContext::GLESApi)glVersion); + if (!context) { + s_egl.eglDestroyContext(rc->dpy, context_); + return 0U; + } + + return context->id; +} + +static void rcDestroyContext(void* ctx_, uint32_t ctx) { + std::map<uint32_t, EglContext*>::iterator it; + it = EglContext::map.find(ctx); + if (it == EglContext::map.end()) + return; + + EglContext* context = it->second; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + s_egl.eglDestroyContext(rc->dpy, context->context); + context->context = EGL_NO_CONTEXT; + if (context->disposable()) + delete context; +} + +static uint32_t rcCreateWindowSurface(void* ctx_, uint32_t config_, uint32_t width, + uint32_t height) { + if (config_ > EglConfig::vec.size()) + return 0U; + + EglConfig const* config = EglConfig::vec[config_]; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + EglSurface* surface = + new (std::nothrow) EglSurface(config->config, rc->ctx->handle, width, height); + if (!surface) + return 0U; + + return surface->id; +} + +static void rcDestroyWindowSurface(void* ctx_, uint32_t surface_) { + std::map<uint32_t, EglSurface*>::iterator it; + it = EglSurface::map.find(surface_); + if (it == EglSurface::map.end()) + return; + + EglSurface* surface = it->second; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + s_egl.eglDestroySurface(rc->dpy, surface->surface); + surface->surface = EGL_NO_SURFACE; + if (surface->disposable()) { + delete surface->window; + delete surface; + } +} + +static uint32_t rcCreateColorBuffer(uint32_t, uint32_t, GLenum) { + // NOTE: This CreateColorBuffer implementation is a no-op which returns a + // special surface ID to indicate that a pbuffer surface should be + // created. This is necessary because the emulator does not create a + // true pbuffer, it always creates a fake one. We don't want this. + return ~1U; +} + +static void rcOpenColorBuffer(uint32_t) { + printf("%s: not implemented\n", __func__); +} + +static void rcCloseColorBuffer(uint32_t) { + printf("%s: not implemented\n", __func__); +} + +static void rcSetWindowColorBuffer(void* ctx_, uint32_t windowSurface, uint32_t colorBuffer) { + std::map<uint32_t, EglSurface*>::iterator surface_it; + surface_it = EglSurface::map.find(windowSurface); + if (surface_it == EglSurface::map.end()) + return; + + EglSurface* surface = surface_it->second; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + + if (colorBuffer == ~1U) { + EGLint const attrib_list[] = { EGL_WIDTH, (EGLint)surface->width, EGL_HEIGHT, + (EGLint)surface->height, EGL_NONE }; + assert(surface->surface == EGL_NO_SURFACE && "Pbuffer set twice"); + surface->surface = s_egl.eglCreatePbufferSurface(rc->dpy, surface->config, attrib_list); + } else { + std::map<uint32_t, Resource*>::iterator resource_it; + resource_it = Resource::map.find(colorBuffer); + if (resource_it == Resource::map.end()) + return; + + Resource* res = resource_it->second; + ANativeWindowBuffer* buffer = resourceToANWB(res); + if (!buffer) + return; + + if (surface->surface == EGL_NO_SURFACE) { + surface->window = + new (std::nothrow) FakeANativeWindow(res->args.width, res->args.height); + if (!surface->window) + return; + + NativeWindowType native_window = reinterpret_cast<NativeWindowType>(surface->window); + surface->window->oem[1] = (intptr_t)buffer; + surface->surface = + s_egl.eglCreateWindowSurface(rc->dpy, surface->config, native_window, nullptr); + } else { + surface->window->oem[1] = (intptr_t)buffer; + s_egl.eglSwapBuffers(rc->dpy, surface->surface); + } + } +} + +static int rcFlushWindowColorBuffer(uint32_t windowSurface) { + std::map<uint32_t, EglSurface*>::iterator it; + it = EglSurface::map.find(windowSurface); + return it == EglSurface::map.end() ? -1 : 0; +} + +static EGLint rcMakeCurrent(void* ctx_, uint32_t context_, uint32_t drawSurf, uint32_t readSurf) { + std::map<uint32_t, EglContext*>::iterator context_it; + context_it = EglContext::map.find(context_); + if (context_it == EglContext::map.end()) + return EGL_FALSE; + + EglContext* context = context_it->second; + + std::map<uint32_t, EglSurface*>::iterator surface_it; + surface_it = EglSurface::map.find(drawSurf); + if (surface_it == EglSurface::map.end()) + return EGL_FALSE; + + EglSurface* draw_surface = surface_it->second; + + surface_it = EglSurface::map.find(readSurf); + if (surface_it == EglSurface::map.end()) + return EGL_FALSE; + + EglSurface* read_surface = surface_it->second; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + + EglSurface* old_draw_surface = draw_surface->bind(rc->ctx->handle, false); + if (old_draw_surface) + old_draw_surface->unbind(false); + + EglSurface* old_read_surface = read_surface->bind(rc->ctx->handle, true); + if (old_read_surface) + old_read_surface->unbind(true); + + EglContext* old_context = context->bind(rc->ctx->handle); + if (old_context) + old_context->unbind(); + + EGLBoolean ret = s_egl.eglMakeCurrent(rc->dpy, draw_surface->surface, read_surface->surface, + context->context); + if (!ret) { + // If eglMakeCurrent fails, it's specified *not* to have unbound the + // previous contexts or surfaces, but many implementations do. This bug + // isn't worked around here, and we just assume the implementations obey + // the spec. + context->unbind(); + if (old_context) + old_context->bind(rc->ctx->handle); + read_surface->unbind(true); + if (old_read_surface) + old_read_surface->bind(rc->ctx->handle, true); + draw_surface->unbind(false); + if (old_draw_surface) + old_draw_surface->bind(rc->ctx->handle, false); + } else { + if (old_context && old_context->disposable()) + delete old_context; + if (old_read_surface && old_read_surface->disposable()) + delete old_read_surface; + if (old_draw_surface && old_draw_surface->disposable()) + delete old_draw_surface; + rc->ctx->unbind(); + rc->ctx->bind(context); + } + + return (EGLint)ret; +} + +static void rcFBPost(uint32_t) { + printf("%s: not implemented\n", __func__); +} + +static void rcFBSetSwapInterval(void* ctx_, EGLint interval) { + RenderControl* rc = static_cast<RenderControl*>(ctx_); + s_egl.eglSwapInterval(rc->dpy, interval); +} + +static void rcBindTexture(void* ctx_, uint32_t colorBuffer) { + std::map<uint32_t, Resource*>::iterator it; + it = Resource::map.find(colorBuffer); + if (it == Resource::map.end()) + return; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + Resource* res = it->second; + if (!res->image) { + ANativeWindowBuffer* buffer = resourceToANWB(res); + if (!buffer) + return; + + EGLClientBuffer client_buffer = static_cast<EGLClientBuffer>(buffer); + EGLImageKHR image = s_egl.eglCreateImageKHR( + rc->dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, client_buffer, nullptr); + if (image == EGL_NO_IMAGE_KHR) + return; + + EglImage* img = new (std::nothrow) EglImage(rc->dpy, image, s_egl.eglDestroyImageKHR); + if (!img) { + s_egl.eglDestroyImageKHR(rc->dpy, image); + return; + } + + // FIXME: House keeping, because we won't get asked to delete the image + // object otherwise, so we need to keep a reference to it.. + res->image = img; + } + + if (rc->ctx->ctx->api == EglContext::GLESApi::GLESApi_CM) { + // FIXME: Unconditional use of GL_TEXTURE_2D here is wrong + s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, res->image->image); + } else { + // FIXME: Unconditional use of GL_TEXTURE_2D here is wrong + s_gles3.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, res->image->image); + } +} + +static void rcBindRenderbuffer(void* ctx_, uint32_t colorBuffer) { + std::map<uint32_t, Resource*>::iterator it; + it = Resource::map.find(colorBuffer); + if (it == Resource::map.end()) + return; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + Resource* res = it->second; + if (!res->image) { + ANativeWindowBuffer* buffer = resourceToANWB(res); + if (!buffer) + return; + + EGLClientBuffer client_buffer = static_cast<EGLClientBuffer>(buffer); + EGLImageKHR image = s_egl.eglCreateImageKHR( + rc->dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, client_buffer, nullptr); + if (image == EGL_NO_IMAGE_KHR) + return; + + EglImage* img = new (std::nothrow) EglImage(rc->dpy, image, s_egl.eglDestroyImageKHR); + if (!img) { + s_egl.eglDestroyImageKHR(rc->dpy, image); + return; + } + + // FIXME: House keeping, because we won't get asked to delete the image + // object otherwise, so we need to keep a reference to it.. + res->image = img; + } + + if (rc->ctx->ctx->api == EglContext::GLESApi::GLESApi_CM) { + s_gles1.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, res->image->image); + } else { + s_gles3.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, res->image->image); + } +} + +static EGLint rcColorBufferCacheFlush(uint32_t, EGLint, int) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static void rcReadColorBuffer(uint32_t, GLint, GLint, GLint, GLint, GLenum, GLenum, void*) { + printf("%s: not implemented\n", __func__); +} + +static int rcUpdateColorBuffer(uint32_t, GLint, GLint, GLint, GLint, GLenum, GLenum, void*) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static int rcOpenColorBuffer2(uint32_t) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static uint32_t rcCreateClientImage(void* ctx_, uint32_t context_, EGLenum target, GLuint buffer_) { + std::map<uint32_t, EglContext*>::iterator it; + it = EglContext::map.find(context_); + if (it == EglContext::map.end()) + return 0U; + + EglContext* context = it->second; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(buffer_); + EGLImageKHR image = s_egl.eglCreateImageKHR(rc->dpy, context, target, buffer, nullptr); + EglImage* img = new (std::nothrow) EglImage(rc->dpy, image, s_egl.eglDestroyImageKHR); + if (!img) { + s_egl.eglDestroyImageKHR(rc->dpy, image); + return 0U; + } + + return img->id; +} + +static int rcDestroyClientImage(uint32_t image_) { + std::map<uint32_t, EglImage*>::iterator it; + it = EglImage::map.find(image_); + if (it == EglImage::map.end()) + return EGL_FALSE; + + EglImage* image = it->second; + + delete image; + return EGL_TRUE; +} + +static void rcSelectChecksumHelper(void* ctx_, uint32_t protocol, uint32_t) { + RenderControl* rc = static_cast<RenderControl*>(ctx_); + rc->ctx->checksum_calc.setVersion(protocol); +} + +static void rcCreateSyncKHR(void* ctx_, EGLenum type, EGLint* attribs, uint32_t, int, + uint64_t* glsync_out, uint64_t* syncthread_out) { + *syncthread_out = 0ULL; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + EGLSyncKHR sync = s_egl.eglCreateSyncKHR(rc->dpy, type, attribs); + if (sync == EGL_NO_SYNC_KHR) { + *glsync_out = 0ULL; + return; + } + + EglSync* syn = new (std::nothrow) EglSync(sync); + if (!syn) { + s_egl.eglDestroySyncKHR(rc->dpy, sync); + *glsync_out = 0ULL; + return; + } + + *glsync_out = syn->id; +} + +static EGLint rcClientWaitSyncKHR(void* ctx_, uint64_t sync_, EGLint flags, uint64_t timeout) { + std::map<uint64_t, EglSync*>::iterator it; + it = EglSync::map.find(sync_); + if (it == EglSync::map.end()) + return EGL_CONDITION_SATISFIED_KHR; + + EglSync* sync = it->second; + RenderControl* rc = static_cast<RenderControl*>(ctx_); + return s_egl.eglClientWaitSyncKHR(rc->dpy, sync->sync, flags, timeout); +} + +static void rcFlushWindowColorBufferAsync(uint32_t windowSurface) { + // No-op +} + +static int rcDestroySyncKHR(void* ctx_, uint64_t sync_) { + std::map<uint64_t, EglSync*>::iterator it; + it = EglSync::map.find(sync_); + if (it == EglSync::map.end()) + return EGL_FALSE; + + EglSync* sync = it->second; + RenderControl* rc = static_cast<RenderControl*>(ctx_); + return s_egl.eglDestroySyncKHR(rc->dpy, sync->sync); +} + +static void rcSetPuid(void* ctx_, uint64_t proto) { + union { + uint64_t proto; + struct { + int pid; + int tid; + } id; + } puid; + + puid.proto = proto; + + RenderControl* rc = static_cast<RenderControl*>(ctx_); + rc->ctx->setPidTid(puid.id.pid, puid.id.tid); +} + +static int rcUpdateColorBufferDMA(uint32_t, GLint, GLint, GLint, GLint, GLenum, GLenum, void*, + uint32_t) { + printf("%s: not implemented\n", __func__); + return 0; +} + +static uint32_t rcCreateColorBufferDMA(uint32_t, uint32_t, GLenum, int) { + printf("%s: not implemented\n", __func__); + return 0U; +} + +static void rcWaitSyncKHR(void* ctx_, uint64_t sync_, EGLint flags) { + std::map<uint64_t, EglSync*>::iterator it; + it = EglSync::map.find(sync_); + if (it == EglSync::map.end()) + return; + + EglSync* sync = it->second; + RenderControl* rc = static_cast<RenderControl*>(ctx_); + // FIXME: No eglWaitSyncKHR support in SwiftShader + // This call will BLOCK when it should be asynchronous! + s_egl.eglClientWaitSyncKHR(rc->dpy, sync->sync, flags, EGL_FOREVER_KHR); +} + +RenderControl::RenderControl(Context* ctx_, EGLDisplay dpy_) { + rcGetRendererVersion = ::rcGetRendererVersion; + rcGetEGLVersion_dec = ::rcGetEGLVersion; + rcQueryEGLString_dec = ::rcQueryEGLString; + rcGetGLString_dec = ::rcGetGLString; + rcGetNumConfigs = ::rcGetNumConfigs; + rcGetConfigs = ::rcGetConfigs; + rcChooseConfig_dec = ::rcChooseConfig; + rcGetFBParam = ::rcGetFBParam; + rcCreateContext_dec = ::rcCreateContext; + rcDestroyContext_dec = ::rcDestroyContext; + rcCreateWindowSurface_dec = ::rcCreateWindowSurface; + rcDestroyWindowSurface_dec = ::rcDestroyWindowSurface; + rcCreateColorBuffer = ::rcCreateColorBuffer; + rcOpenColorBuffer = ::rcOpenColorBuffer; + rcCloseColorBuffer = ::rcCloseColorBuffer; + rcSetWindowColorBuffer_dec = ::rcSetWindowColorBuffer; + rcFlushWindowColorBuffer = ::rcFlushWindowColorBuffer; + rcMakeCurrent_dec = ::rcMakeCurrent; + rcFBPost = ::rcFBPost; + rcFBSetSwapInterval_dec = ::rcFBSetSwapInterval; + rcBindTexture_dec = ::rcBindTexture; + rcBindRenderbuffer_dec = ::rcBindRenderbuffer; + rcColorBufferCacheFlush = ::rcColorBufferCacheFlush; + rcReadColorBuffer = ::rcReadColorBuffer; + rcUpdateColorBuffer = ::rcUpdateColorBuffer; + rcOpenColorBuffer2 = ::rcOpenColorBuffer2; + rcCreateClientImage_dec = ::rcCreateClientImage; + rcDestroyClientImage = ::rcDestroyClientImage; + rcSelectChecksumHelper_dec = ::rcSelectChecksumHelper; + rcCreateSyncKHR_dec = ::rcCreateSyncKHR; + rcClientWaitSyncKHR_dec = ::rcClientWaitSyncKHR; + rcFlushWindowColorBufferAsync = ::rcFlushWindowColorBufferAsync; + rcDestroySyncKHR_dec = ::rcDestroySyncKHR; + rcSetPuid_dec = ::rcSetPuid; + rcUpdateColorBufferDMA = ::rcUpdateColorBufferDMA; + rcCreateColorBufferDMA = ::rcCreateColorBufferDMA; + rcWaitSyncKHR_dec = ::rcWaitSyncKHR; + + dpy = dpy_; + ctx = ctx_; +} diff --git a/host/libs/virglrenderer/RenderControl.h b/host/libs/virglrenderer/RenderControl.h new file mode 100644 index 0000000000000000000000000000000000000000..88734e5684ecc8c0469d7f7510aa32741fb58864 --- /dev/null +++ b/host/libs/virglrenderer/RenderControl.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "renderControl_dec.h" + +typedef void* EGLDisplay; + +struct Context; + +struct RenderControl : public renderControl_decoder_context_t { + RenderControl(Context* ctx_, EGLDisplay dpy_); + EGLDisplay dpy; + Context* ctx; +}; diff --git a/host/libs/virglrenderer/Resource.h b/host/libs/virglrenderer/Resource.h new file mode 100644 index 0000000000000000000000000000000000000000..9fd462e712d53e8ff2658a843e3e1dc0206fb7de --- /dev/null +++ b/host/libs/virglrenderer/Resource.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +extern "C" { +#include <virglrenderer.h> +} + +#include <cstdint> +#include <cstdlib> +#include <map> + +#include <GLES/gl.h> + +#include <sys/uio.h> + +#include "EglImage.h" + +struct Context; + +struct Resource { + static std::map<uint32_t, Resource*> map; + + Resource(virgl_renderer_resource_create_args* args_, uint32_t num_iovs_, iovec* iov_) + : args(*args_), num_iovs(num_iovs_), tex_id(0U), iov(iov_) { + reallocLinear(); + map.emplace(args.handle, this); + } + + ~Resource() { + map.erase(args.handle); + delete image; + } + + void reallocLinear() { + if (linearShadow && num_iovs <= 1) + free(linear); + linearShadow = num_iovs > 1 ? true : false; + if (linearShadow) { + uint32_t i; + for (i = 0, linearSize = 0U; i < num_iovs; i++) + linearSize += iov[i].iov_len; + linear = realloc(linear, linearSize); + } else if (num_iovs == 1) { + linearSize = iov[0].iov_len; + linear = iov[0].iov_base; + } else { + linearSize = 0U; + linear = nullptr; + } + } + + std::map<uint32_t, Context*> context_map; + virgl_renderer_resource_create_args args; + EglImage* image = nullptr; + size_t linearSize = 0U; + void* linear = nullptr; + uint32_t num_iovs; + GLuint tex_id; + iovec* iov; + + private: + bool linearShadow = false; +}; diff --git a/host/libs/virglrenderer/emugl/common/dma_device.cpp b/host/libs/virglrenderer/emugl/common/dma_device.cpp new file mode 100644 index 0000000000000000000000000000000000000000..880d559cd130fd5176d3fbd8266a1b79d8b077c3 --- /dev/null +++ b/host/libs/virglrenderer/emugl/common/dma_device.cpp @@ -0,0 +1,38 @@ + +#include "android/emulation/GoldfishDma.h" +#include "emugl/common/dma_device.h" + +static void defaultDmaAddBuffer(void* pipe, uint64_t guest_paddr, uint64_t size) { } +static void defaultDmaRemoveBuffer(uint64_t guest_paddr) { } +static void* defaultDmaGetHostAddr(uint64_t guest_paddr) { + return nullptr; +} +static void defaultDmaInvalidateHostMappings() { } + +static void defaultDmaUnlock(uint64_t addr) { } + +emugl_dma_add_buffer_t g_emugl_dma_add_buffer = defaultDmaAddBuffer; +emugl_dma_remove_buffer_t g_emugl_dma_remove_buffer = defaultDmaRemoveBuffer; +emugl_dma_get_host_addr_t g_emugl_dma_get_host_addr = defaultDmaGetHostAddr; +emugl_dma_invalidate_host_mappings_t g_emugl_dma_invalidate_host_mappings = defaultDmaInvalidateHostMappings; +emugl_dma_unlock_t g_emugl_dma_unlock = defaultDmaUnlock; + +void set_emugl_dma_add_buffer(emugl_dma_add_buffer_t f) { + g_emugl_dma_add_buffer = f; +} + +void set_emugl_dma_remove_buffer(emugl_dma_remove_buffer_t f) { + g_emugl_dma_remove_buffer = f; +} + +void set_emugl_dma_get_host_addr(emugl_dma_get_host_addr_t f) { + g_emugl_dma_get_host_addr = f; +} + +void set_emugl_dma_invalidate_host_mappings(emugl_dma_invalidate_host_mappings_t f) { + g_emugl_dma_invalidate_host_mappings = f; +} + +void set_emugl_dma_unlock(emugl_dma_unlock_t f) { + g_emugl_dma_unlock = f; +} diff --git a/host/libs/virglrenderer/emugl/common/dma_device.h b/host/libs/virglrenderer/emugl/common/dma_device.h new file mode 100644 index 0000000000000000000000000000000000000000..a76c4345b2e612c785e34c6e087fa82272722611 --- /dev/null +++ b/host/libs/virglrenderer/emugl/common/dma_device.h @@ -0,0 +1,30 @@ +/* +* Copyright (C) 2016 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once + +#include "OpenglRender/render_api_types.h" + +extern emugl_dma_add_buffer_t g_emugl_dma_add_buffer; +extern emugl_dma_remove_buffer_t g_emugl_dma_remove_buffer; +extern emugl_dma_get_host_addr_t g_emugl_dma_get_host_addr; +extern emugl_dma_unlock_t g_emugl_dma_unlock; + +void set_emugl_dma_add_buffer(emugl_dma_add_buffer_t); +void set_emugl_dma_remove_buffer(emugl_dma_remove_buffer_t); +void set_emugl_dma_get_host_addr(emugl_dma_get_host_addr_t); +void set_emugl_dma_invalidate_host_mappings(emugl_dma_invalidate_host_mappings_t); +void set_emugl_dma_unlock(emugl_dma_unlock_t); diff --git a/host/libs/virglrenderer/emugl/common/logging.h b/host/libs/virglrenderer/emugl/common/logging.h new file mode 100644 index 0000000000000000000000000000000000000000..081df6132daab62a3c741ca0dc718cbf3d152320 --- /dev/null +++ b/host/libs/virglrenderer/emugl/common/logging.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +typedef void (*emugl_logger_t)(const char* fmt, ...); + +extern emugl_logger_t emugl_logger; +extern emugl_logger_t emugl_cxt_logger; +void set_emugl_logger(emugl_logger_t f); +void set_emugl_cxt_logger(emugl_logger_t f); + +#define GL_LOGGING 1 + +#if GL_LOGGING + +#define GL_LOG(...) do { \ + emugl_logger(__VA_ARGS__); \ +} while (0) + +#define GL_CXT_LOG(...) do { \ + emugl_cxt_logger(__VA_ARGS__); \ +} while (0) + +#else +#define GL_LOG(...) 0 +#endif diff --git a/host/libs/virglrenderer/include/VirtioGpuCmd.h b/host/libs/virglrenderer/include/VirtioGpuCmd.h new file mode 100644 index 0000000000000000000000000000000000000000..6ffacd3fc6a708083261b4a8b3e0441d04da20db --- /dev/null +++ b/host/libs/virglrenderer/include/VirtioGpuCmd.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +struct VirtioGpuCmd { + uint32_t op; + uint32_t cmdSize; + unsigned char buf[0]; +} __attribute__((packed)); diff --git a/host/libs/virglrenderer/include/android/api-level.h b/host/libs/virglrenderer/include/android/api-level.h new file mode 100644 index 0000000000000000000000000000000000000000..2d2f0968c4e9d4527778c2ba13c640b916206f22 --- /dev/null +++ b/host/libs/virglrenderer/include/android/api-level.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ANDROID_API_LEVEL_H +#define ANDROID_API_LEVEL_H + +/* + * Magic version number for a current development build, which has + * not yet turned into an official release. + */ +#define __ANDROID_API__ 10000 + +#endif /* ANDROID_API_LEVEL_H */ diff --git a/host/libs/virglrenderer/include/android/sync.h b/host/libs/virglrenderer/include/android/sync.h new file mode 100644 index 0000000000000000000000000000000000000000..1ae728a5a892b65496fe576b280256b71dfa2989 --- /dev/null +++ b/host/libs/virglrenderer/include/android/sync.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +extern "C" { +int sync_wait(int fd, int timeout); +}; diff --git a/host/libs/virglrenderer/include/cutils/native_handle.h b/host/libs/virglrenderer/include/cutils/native_handle.h new file mode 100644 index 0000000000000000000000000000000000000000..b92a66385245e6fa6994912665374bce6299d4b3 --- /dev/null +++ b/host/libs/virglrenderer/include/cutils/native_handle.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +struct native_handle_t; + +typedef const struct native_handle_t* buffer_handle_t; diff --git a/host/libs/virglrenderer/include/hardware/gralloc.h b/host/libs/virglrenderer/include/hardware/gralloc.h new file mode 100644 index 0000000000000000000000000000000000000000..8446ba4ea803941cb6a64e7651b44825a5b3d71e --- /dev/null +++ b/host/libs/virglrenderer/include/hardware/gralloc.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cutils/native_handle.h> + +#include <hardware/hardware.h> + +struct android_ycbcr; + +enum { + GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003U, + GRALLOC_USAGE_SW_WRITE_OFTEN = 0x00000030U, + GRALLOC_USAGE_HW_TEXTURE = 0x00000100U, + GRALLOC_USAGE_HW_RENDER = 0x00000200U, +}; + +struct gralloc_module_t { + hw_module_t common; + int (*registerBuffer)(gralloc_module_t const*, buffer_handle_t); + int (*unregisterBuffer)(gralloc_module_t const*, buffer_handle_t); + int (*lock)(gralloc_module_t const*, buffer_handle_t, int, int, int, int, int, void**); + int (*unlock)(gralloc_module_t const*, buffer_handle_t); + int (*perform)(gralloc_module_t const*, int, ...); + int (*lock_ycbcr)(gralloc_module_t const*, buffer_handle_t, int, int, int, int, int, + android_ycbcr*); + int (*lockAsync)(gralloc_module_t const*, buffer_handle_t, int, int, int, int, int, void**, int); + int (*unlockAsync)(gralloc_module_t const*, buffer_handle_t, int*); + int (*lockAsync_ycbcr)(gralloc_module_t const*, buffer_handle_t, int, int, int, int, int, + android_ycbcr*, int); + void* reserved_proc[3]; +}; diff --git a/host/libs/virglrenderer/include/hardware/gralloc1.h b/host/libs/virglrenderer/include/hardware/gralloc1.h new file mode 100644 index 0000000000000000000000000000000000000000..b02decfa031a124d1825d62cf5ff1871d02e8195 --- /dev/null +++ b/host/libs/virglrenderer/include/hardware/gralloc1.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <hardware/hardware.h> + +#include <cutils/native_handle.h> + +#define GRALLOC_MODULE_API_VERSION_1_0 HARDWARE_MAKE_API_VERSION(1, 0) + +#define GRALLOC_HARDWARE_MODULE_ID "gralloc" + +enum { + GRALLOC1_ERROR_NONE = 0, + GRALLOC1_ERROR_BAD_HANDLE = 2, + GRALLOC1_ERROR_BAD_VALUE = 3, + GRALLOC1_ERROR_UNDEFINED = 6, +}; + +enum { + GRALLOC1_FUNCTION_LOCK = 18, + GRALLOC1_FUNCTION_UNLOCK = 20, +}; + +enum { + GRALLOC1_CONSUMER_USAGE_CPU_READ = 1ULL << 1, + GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN = 1ULL << 2 | GRALLOC1_CONSUMER_USAGE_CPU_READ, + GRALLOC1_CONSUMER_USAGE_CPU_WRITE = 1ULL << 5, + GRALLOC1_CONSUMER_USAGE_CPU_WRITE_OFTEN = 1ULL << 6 | GRALLOC1_CONSUMER_USAGE_CPU_WRITE, + GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE = 1ULL << 8, +}; + +enum { + GRALLOC1_PRODUCER_USAGE_CPU_READ = 1ULL << 1, + GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN = 1ULL << 2 | GRALLOC1_PRODUCER_USAGE_CPU_READ, + GRALLOC1_PRODUCER_USAGE_CPU_WRITE = 1ULL << 5, + GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN = 1ULL << 6 | GRALLOC1_PRODUCER_USAGE_CPU_WRITE, + GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET = 1ULL << 9, +}; + +typedef void (*gralloc1_function_pointer_t)(); + +struct gralloc1_rect_t { + int32_t left; + int32_t top; + int32_t width; + int32_t height; +}; + +struct gralloc1_device_t { + hw_device_t common; + void (*getCapabilities)(gralloc1_device_t*, uint32_t*, int32_t*); + gralloc1_function_pointer_t (*getFunction)(gralloc1_device_t*, int32_t); +}; + +typedef int32_t (*GRALLOC1_PFN_LOCK)(gralloc1_device_t*, buffer_handle_t, uint64_t, uint64_t, + const gralloc1_rect_t*, void**, int32_t); +typedef int32_t (*GRALLOC1_PFN_UNLOCK)(gralloc1_device_t*, buffer_handle_t, int32_t*); + +static inline int gralloc1_open(const hw_module_t* module, gralloc1_device_t** device) { + return module->methods->open(module, GRALLOC_HARDWARE_MODULE_ID, + reinterpret_cast<hw_device_t**>(device)); +} diff --git a/host/libs/virglrenderer/include/hardware/hardware.h b/host/libs/virglrenderer/include/hardware/hardware.h new file mode 100644 index 0000000000000000000000000000000000000000..21d6dc4ab58e35bb4681cb6b92f8549617cdd7de --- /dev/null +++ b/host/libs/virglrenderer/include/hardware/hardware.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#define MAKE_TAG_CONSTANT(A, B, C, D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D)) + +#define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T') +#define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T') + +#define HARDWARE_MAKE_API_VERSION(maj, min) ((((maj)&0xff) << 8) | ((min)&0xff)) + +#define HARDWARE_HAL_API_VERSION HARDWARE_MAKE_API_VERSION(1, 0) + +struct hw_module_methods_t; + +struct hw_module_t { + uint32_t tag; + uint16_t module_api_version; + uint16_t hal_api_version; + const char* id; + const char* name; + const char* author; + hw_module_methods_t* methods; + void* dso; +#ifdef __LP64__ + uint64_t reserved[32 - 7]; +#else + uint32_t reserved[32 - 7]; +#endif +}; + +struct hw_device_t { + uint32_t tag; + uint32_t version; + struct hw_module_t* module; +#ifdef __LP64__ + uint64_t reserved[12]; +#else + uint32_t reserved[12]; +#endif + int (*close)(hw_device_t* device); +}; + +struct hw_module_methods_t { + int (*open)(const hw_module_t*, const char*, hw_device_t**); +}; + +extern "C" { +int hw_get_module(const char* id, const hw_module_t** module); +}; diff --git a/host/libs/virglrenderer/include/nativebase/nativebase.h b/host/libs/virglrenderer/include/nativebase/nativebase.h new file mode 100644 index 0000000000000000000000000000000000000000..c2e84d79a7750eab6a0fcb20a781c367627c27de --- /dev/null +++ b/host/libs/virglrenderer/include/nativebase/nativebase.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cutils/native_handle.h> + +#include <cstdint> +#include <cstring> + +// clang-format off +#define ANDROID_NATIVE_MAKE_CONSTANT(a, b, c, d) \ + ((static_cast<unsigned int>(a) << 24) | \ + (static_cast<unsigned int>(b) << 16) | \ + (static_cast<unsigned int>(c) << 8) | \ + (static_cast<unsigned int>(d) << 0)) +// clang-format on + +struct android_native_base_t { + int magic; + int version; + void* reserved[4]; + void (*incRef)(android_native_base_t*); + void (*decRef)(android_native_base_t*); +}; + +#define ANDROID_NATIVE_BUFFER_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_', 'b', 'f', 'r') + +struct ANativeWindowBuffer { + ANativeWindowBuffer() { + common.magic = ANDROID_NATIVE_BUFFER_MAGIC; + common.version = sizeof(ANativeWindowBuffer); + memset(common.reserved, 0, sizeof(common.reserved)); + } + + android_native_base_t common; + + int width; + int height; + int stride; + int format; + int usage_deprecated; + uintptr_t layerCount; + + void* reserved[1]; + + const native_handle_t* handle; + uint64_t usage; + + void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))]; +}; diff --git a/host/libs/virglrenderer/include/sync/sync.h b/host/libs/virglrenderer/include/sync/sync.h new file mode 100644 index 0000000000000000000000000000000000000000..1ae728a5a892b65496fe576b280256b71dfa2989 --- /dev/null +++ b/host/libs/virglrenderer/include/sync/sync.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +extern "C" { +int sync_wait(int fd, int timeout); +}; diff --git a/host/libs/virglrenderer/include/system/graphics.h b/host/libs/virglrenderer/include/system/graphics.h new file mode 100644 index 0000000000000000000000000000000000000000..884db9cc2639804cc53824b12947f25d0beee99c --- /dev/null +++ b/host/libs/virglrenderer/include/system/graphics.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +enum { + HAL_PIXEL_FORMAT_RGBA_8888 = 1, + HAL_PIXEL_FORMAT_RGBX_8888 = 2, + HAL_PIXEL_FORMAT_RGB_888 = 3, + HAL_PIXEL_FORMAT_RGB_565 = 4, + HAL_PIXEL_FORMAT_BGRA_8888 = 5, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 34, + HAL_PIXEL_FORMAT_YV12 = 842094169, +}; diff --git a/host/libs/virglrenderer/include/system/window.h b/host/libs/virglrenderer/include/system/window.h new file mode 100644 index 0000000000000000000000000000000000000000..f986274c1ae1103fd6e69323d48c8ef19a6f56fa --- /dev/null +++ b/host/libs/virglrenderer/include/system/window.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <nativebase/nativebase.h> +#include <system/graphics.h> + +#define ANDROID_NATIVE_WINDOW_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_', 'w', 'n', 'd') + +enum { + NATIVE_WINDOW_WIDTH = 0, + NATIVE_WINDOW_HEIGHT = 1, +}; + +struct ANativeWindow { + ANativeWindow() : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0) { + common.magic = ANDROID_NATIVE_BUFFER_MAGIC; + common.version = sizeof(ANativeWindowBuffer); + memset(common.reserved, 0, sizeof(common.reserved)); + } + + android_native_base_t common; + + const uint32_t flags; + const int minSwapInterval; + const int maxSwapInterval; + const float xdpi; + const float ydpi; + intptr_t oem[4]; + + int (*setSwapInterval)(ANativeWindow*, int); + int (*dequeueBuffer_DEPRECATED)(ANativeWindow*, ANativeWindowBuffer**); + int (*lockBuffer_DEPRECATED)(ANativeWindow*, ANativeWindowBuffer*); + int (*queueBuffer_DEPRECATED)(ANativeWindow*, ANativeWindowBuffer*); + int (*query)(const ANativeWindow*, int, int*); + int (*perform)(ANativeWindow*, int, ...); + int (*cancelBuffer_DEPRECATED)(ANativeWindow*, ANativeWindowBuffer*); + int (*dequeueBuffer)(ANativeWindow*, ANativeWindowBuffer**, int*); + int (*queueBuffer)(ANativeWindow*, ANativeWindowBuffer*, int); + int (*cancelBuffer)(ANativeWindow*, ANativeWindowBuffer*, int); +}; + +static inline int native_window_set_usage(ANativeWindow*, uint64_t) { + // No-op + return 0; +} + +static inline int native_window_dequeue_buffer_and_wait(ANativeWindow* anw, + ANativeWindowBuffer** anwb) { + return anw->dequeueBuffer_DEPRECATED(anw, anwb); +} diff --git a/host/libs/virglrenderer/libOpenglRender/FrameworkFormats.h b/host/libs/virglrenderer/libOpenglRender/FrameworkFormats.h new file mode 100644 index 0000000000000000000000000000000000000000..c6f1f3719dbdcb057d6c863dc8a5db4bd0313a56 --- /dev/null +++ b/host/libs/virglrenderer/libOpenglRender/FrameworkFormats.h @@ -0,0 +1,19 @@ +#pragma once + +// Android system might want to allocate some color buffers with formats +// that are not compatible with most OpenGL implementations, +// such as YV12. +// In this situation, we need to convert to some OpenGL format such as +// RGB888 that actually works. +// While we can do some of this conversion in the guest gralloc driver itself +// (which would make ColorBuffer see only the OpenGL formatted pixels), +// it may be advantageous to do the conversion on the host as well. +// FrameworkFormat tracks whether the incoming color buffer from the guest +// can be directly used as a GL texture (FRAMEWORK_FORMAT_GL_COMPATIBLE). +// Otherwise, we need to know which format it is (e.g., FRAMEWORK_FORMAT_YV12) +// and convert on the host. +enum FrameworkFormat { + FRAMEWORK_FORMAT_GL_COMPATIBLE = 0, + FRAMEWORK_FORMAT_YV12 = 1, + FRAMEWORK_FORMAT_YUV_420_888 = 2, +}; diff --git a/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.cpp b/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57a3b50274ce5e327ad8ba872341df6837df3efd --- /dev/null +++ b/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.cpp @@ -0,0 +1,47 @@ +/* +* Copyright (C) 2016 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "GLESVersionDetector.h" + +#include "DispatchTables.h" + +#include "emugl/common/feature_control.h" + +#include <algorithm> + +GLESDispatchMaxVersion calcMaxVersionFromDispatch() { + // Detect the proper OpenGL ES version to advertise to the system. + // + // If the underlying glesv2 library also is on top of system OpenGL, + // we assume existence of a function called "gl_dispatch_get_max_version" + // which matches the return type of gles2_dispatch_get_max_version, + // and allows us to scale back if the underlying host machine + // doesn't actually suppport a particular GLES version. + if (!emugl_feature_is_enabled(android::featurecontrol::GLESDynamicVersion)) + return GLES_DISPATCH_MAX_VERSION_2; + + GLESDispatchMaxVersion underlying_gles2_lib_max = + gles2_dispatch_get_max_version(); + if (s_gles2.gl_dispatch_get_max_version) { + GLESDispatchMaxVersion underlying_gl_lib_max = + (GLESDispatchMaxVersion)s_gles2.gl_dispatch_get_max_version(); + return std::min(underlying_gl_lib_max, underlying_gles2_lib_max); + } else { + return underlying_gles2_lib_max; + } + + return GLES_DISPATCH_MAX_VERSION_2; +} diff --git a/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.h b/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.h new file mode 100644 index 0000000000000000000000000000000000000000..82532ff1614cf9ddc1b7a37a0bd8497a1d31b950 --- /dev/null +++ b/host/libs/virglrenderer/libOpenglRender/GLESVersionDetector.h @@ -0,0 +1,22 @@ +/* +* Copyright (C) 2016 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once + +#include "OpenGLESDispatch/GLESv2Dispatch.h" + +// Used to determine maximum supported GLES version. +GLESDispatchMaxVersion calcMaxVersionFromDispatch(); diff --git a/host/libs/virglrenderer/libOpenglRender/YUVConverter.cpp b/host/libs/virglrenderer/libOpenglRender/YUVConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74a229f8e2f4045c3c7c956c4202f5c57294f771 --- /dev/null +++ b/host/libs/virglrenderer/libOpenglRender/YUVConverter.cpp @@ -0,0 +1,475 @@ +/* +* Copyright (C) 2016 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "YUVConverter.h" + +#include "DispatchTables.h" + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#define FATAL(fmt,...) do { \ + fprintf(stderr, "%s: FATAL: " fmt "\n", __func__, ##__VA_ARGS__); \ + assert(false); \ +} while(0) + +static void getPlanarYUVSizes(int width, int height, + FrameworkFormat format, + uint32_t* nBytes_out, + uint32_t* yStride_out, + uint32_t* cStride_out, + uint32_t* cHeight_out) { + assert(nBytes_out); + assert(yStride_out); + assert(cStride_out); + assert(cHeight_out); + + uint32_t align; + switch (format) { + case FRAMEWORK_FORMAT_YV12: + align = 16; + break; + case FRAMEWORK_FORMAT_YUV_420_888: + align = 1; + break; + case FRAMEWORK_FORMAT_GL_COMPATIBLE: + FATAL("Input not a YUV format!"); + } + + // 16-alignment means we need to get the + // smallest multiple of 16 pixels that is + // greater than or equal to |width| for |yStride| and + // greater than or equal to |width / 2| for |cStride| + uint32_t yStride = (width + (align - 1)) & ~(align - 1); + uint32_t cStride = (yStride / 2 + (align - 1)) & ~(align - 1); + uint32_t cHeight = height / 2; + + *nBytes_out = yStride * height + 2 * (cStride * cHeight); + *yStride_out = yStride; + *cStride_out = cStride; + *cHeight_out = cHeight; +} + +// getYUVSizes(): given |width| and |height|, return +// the total number of bytes of the YUV-formatted buffer +// in |nBytes_out|, and store aligned width and C height +// in |yStride_out|/|cStride_out| and |cHeight_out|. +static void getYUVSizes(int width, int height, + FrameworkFormat format, + uint32_t* nBytes_out, + uint32_t* yStride_out, + uint32_t* cStride_out, + uint32_t* cHeight_out) { + switch (format) { + case FRAMEWORK_FORMAT_YV12: + case FRAMEWORK_FORMAT_YUV_420_888: + getPlanarYUVSizes(width, height, format, + nBytes_out, + yStride_out, + cStride_out, + cHeight_out); + break; + case FRAMEWORK_FORMAT_GL_COMPATIBLE: + FATAL("Input not a YUV format!"); + } +} + +static void getPlanarYUVOffsets(int width, int height, FrameworkFormat format, + uint32_t* yoff, uint32_t* uoff, uint32_t* voff, + uint32_t* alignwidth, uint32_t* alignwidthc) { + uint32_t totalSize, yStride, cStride, cHeight; + cStride = 0; + yStride = 0; + totalSize = 0; + getYUVSizes(width, height, format, &totalSize, &yStride, &cStride, &cHeight); + int cSize = cStride * height / 2; + + switch (format) { + case FRAMEWORK_FORMAT_YV12: + // In our use cases (so far), the buffer should + // always begin with Y. + *yoff = 0; + // The U and V planes are switched around so physically + // YV12 is more of a "YVU" format + *voff = (*yoff) + yStride * height; + *uoff = (*voff) + cSize; + *alignwidth = yStride; + *alignwidthc = cStride; + break; + case FRAMEWORK_FORMAT_YUV_420_888: + *yoff = 0; + *uoff = (*yoff) + yStride * height; + *voff = (*uoff) + cSize; + *alignwidth = yStride; + *alignwidthc = cStride; + break; + case FRAMEWORK_FORMAT_GL_COMPATIBLE: + FATAL("Input not a YUV format!"); + } +} + +// getYUVOffsets(), given a YUV-formatted buffer that is arranged +// according to the spec +// https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV +// In particular, Android YUV widths are aligned to 16 pixels. +// Inputs: +// |yv12|: the YUV-formatted buffer +// Outputs: +// |yoff|: offset into |yv12| of the start of the Y component +// |uoff|: offset into |yv12| of the start of the U component +// |voff|: offset into |yv12| of the start of the V component +static void getYUVOffsets(int width, int height, FrameworkFormat format, + uint32_t* yoff, uint32_t* uoff, uint32_t* voff, + uint32_t* alignwidth, uint32_t* alignwidthc) { + switch (format) { + case FRAMEWORK_FORMAT_YV12: + case FRAMEWORK_FORMAT_YUV_420_888: + getPlanarYUVOffsets(width, height, format, + yoff, uoff, voff, + alignwidth, alignwidthc); + break; + case FRAMEWORK_FORMAT_GL_COMPATIBLE: + FATAL("Input not a YUV format!"); + } +} + +// createYUVGLTex() allocates GPU memory that is enough +// to hold the raw data of the YV12 buffer. +// The memory is in the form of an OpenGL texture +// with one component (GL_LUMINANCE) and +// of type GL_UNSIGNED_BYTE. +// In order to process all Y, U, V components +// simultaneously in conversion, the simple thing to do +// is to use multiple texture units, hence +// the |texture_unit| argument. +// Returns a new OpenGL texture object in |texName_out| +// that is to be cleaned up by the caller. +static void createYUVGLTex(GLenum texture_unit, + GLsizei width, + GLsizei height, + GLuint* texName_out) { + assert(texName_out); + + s_gles2.glActiveTexture(texture_unit); + s_gles2.glGenTextures(1, texName_out); + s_gles2.glBindTexture(GL_TEXTURE_2D, *texName_out); + s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, + width, height, 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, + NULL); + s_gles2.glActiveTexture(GL_TEXTURE0); +} + +// subUpdateYUVGLTex() updates a given YUV texture +// at the coordinates (x, y, width, height), +// with the raw YUV data in |pixels|. +// We cannot view the result properly until +// after conversion; this is to be used only +// as input to the conversion shader. +static void subUpdateYUVGLTex(GLenum texture_unit, + GLuint tex, + int x, int y, int width, int height, + void* pixels) { + s_gles2.glActiveTexture(texture_unit); + s_gles2.glBindTexture(GL_TEXTURE_2D, tex); + s_gles2.glTexSubImage2D(GL_TEXTURE_2D, 0, + x, y, width, height, + GL_LUMINANCE, GL_UNSIGNED_BYTE, + pixels); + s_gles2.glActiveTexture(GL_TEXTURE0); +} + +// createYUVGLShader() defines the vertex/fragment +// shader that does the actual work of converting +// YUV to RGB. The resulting shaders and program +// are stored in |vshader_out|, |fshader_out|, +// and |program_out|. +static void createYUVGLShader(GLuint* vshader_out, + GLuint* fshader_out, + GLuint* program_out, + GLint* ywidthcutoffloc_out, + GLint* cwidthcutoffloc_out, + GLint* ysamplerloc_out, + GLint* usamplerloc_out, + GLint* vsamplerloc_out) { + assert(vshader_out); + assert(fshader_out); + assert(program_out); + + static const char kVShader[] = R"( +precision highp float; +attribute mediump vec4 position; +attribute highp vec2 inCoord; +varying highp vec2 outCoord; +void main(void) { + gl_Position = position; + outCoord = inCoord; +} + )"; + const GLchar* const kVShaders = + static_cast<const GLchar*>(kVShader); + + // Based on: + // http://stackoverflow.com/questions/11093061/yv12-to-rgb-using-glsl-in-ios-result-image-attached + // + account for 16-pixel alignment using |yWidthCutoff| / |cWidthCutoff| + // + use conversion matrix in + // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp (YUV420p) + // + more precision from + // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion + static const char kFShader[] = R"( +precision highp float; +varying highp vec2 outCoord; +uniform highp float yWidthCutoff; +uniform highp float cWidthCutoff; +uniform sampler2D ysampler; +uniform sampler2D usampler; +uniform sampler2D vsampler; +void main(void) { + highp vec2 cutoffCoordsY; + highp vec2 cutoffCoordsC; + highp vec3 yuv; + highp vec3 rgb; + cutoffCoordsY.x = outCoord.x * yWidthCutoff; + cutoffCoordsY.y = outCoord.y; + cutoffCoordsC.x = outCoord.x * cWidthCutoff; + cutoffCoordsC.y = outCoord.y; + yuv[0] = texture2D(ysampler, cutoffCoordsY).r - 0.0625; + yuv[1] = texture2D(usampler, cutoffCoordsC).r - 0.5; + yuv[2] = texture2D(vsampler, cutoffCoordsC).r - 0.5; + highp float yscale = 1.1643835616438356; + rgb = mat3(yscale, yscale, yscale, + 0, -0.39176229009491365, 2.017232142857143, + 1.5960267857142856, -0.8129676472377708, 0) * yuv; + gl_FragColor = vec4(rgb, 1); +} + )"; + + const GLchar* const kFShaders = + static_cast<const GLchar*>(kFShader); + + *vshader_out = s_gles2.glCreateShader(GL_VERTEX_SHADER); + *fshader_out = s_gles2.glCreateShader(GL_FRAGMENT_SHADER); + + const GLint vtextLen = strlen(kVShader); + const GLint ftextLen = strlen(kFShader); + s_gles2.glShaderSource(*vshader_out, 1, &kVShaders, &vtextLen); + s_gles2.glShaderSource(*fshader_out, 1, &kFShaders, &ftextLen); + s_gles2.glCompileShader(*vshader_out); + s_gles2.glCompileShader(*fshader_out); + + *program_out = s_gles2.glCreateProgram(); + s_gles2.glAttachShader(*program_out, *vshader_out); + s_gles2.glAttachShader(*program_out, *fshader_out); + s_gles2.glLinkProgram(*program_out); + + s_gles2.glUseProgram(*program_out); + *ywidthcutoffloc_out = s_gles2.glGetUniformLocation(*program_out, "yWidthCutoff"); + *cwidthcutoffloc_out = s_gles2.glGetUniformLocation(*program_out, "cWidthCutoff"); + *ysamplerloc_out = s_gles2.glGetUniformLocation(*program_out, "ysampler"); + *usamplerloc_out = s_gles2.glGetUniformLocation(*program_out, "usampler"); + *vsamplerloc_out = s_gles2.glGetUniformLocation(*program_out, "vsampler"); + s_gles2.glUseProgram(0); +} + +// When converting YUV to RGB with shaders, +// we are using the OpenGL graphics pipeline to do compute, +// so we need to express the place to store the result +// with triangles and draw calls. +// createYUVGLFullscreenQuad() defines a fullscreen quad +// with position and texture coordinates. +// The quad will be textured with the resulting RGB colors, +// and we will read back the pixels from the framebuffer +// to retrieve our RGB result. +static void createYUVGLFullscreenQuad(GLuint* vbuf_out, + GLuint* ibuf_out, + int picture_width, + int aligned_width) { + assert(vbuf_out); + assert(ibuf_out); + + s_gles2.glGenBuffers(1, vbuf_out); + s_gles2.glGenBuffers(1, ibuf_out); + + static const float kVertices[] = { + +1, -1, +0, +1, +0, + +1, +1, +0, +1, +1, + -1, +1, +0, +0, +1, + -1, -1, +0, +0, +0, + }; + + static const GLubyte kIndices[] = { 0, 1, 2, 2, 3, 0 }; + + s_gles2.glBindBuffer(GL_ARRAY_BUFFER, *vbuf_out); + s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, + GL_STATIC_DRAW); + s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ibuf_out); + s_gles2.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndices), kIndices, + GL_STATIC_DRAW); +} + +// doYUVConversionDraw() does the actual work of setting up +// and submitting draw commands to the GPU. +// It uses the textures, shaders, and fullscreen quad defined above +// and executes the pipeline on them. +// Note, however, that it is up to the caller to dig out +// the result of the draw. +static void doYUVConversionDraw(GLuint program, + GLint yWidthCutoffLoc, + GLint cWidthCutoffLoc, + GLint ySamplerLoc, + GLint uSamplerLoc, + GLint vSamplerLoc, + GLuint vbuf, GLuint ibuf, + int width, int ywidth, + int halfwidth, int cwidth, + float yWidthCutoff, + float cWidthCutoff) { + + const GLsizei kVertexAttribStride = 5 * sizeof(GL_FLOAT); + const GLvoid* kVertexAttribPosOffset = (GLvoid*)0; + const GLvoid* kVertexAttribCoordOffset = (GLvoid*)(3 * sizeof(GL_FLOAT)); + + s_gles2.glUseProgram(program); + + GLint posLoc = s_gles2.glGetAttribLocation(program, "position"); + GLint coordLoc = s_gles2.glGetAttribLocation(program, "inCoord"); + + s_gles2.glUniform1f(yWidthCutoffLoc, yWidthCutoff); + s_gles2.glUniform1f(cWidthCutoffLoc, cWidthCutoff); + + s_gles2.glUniform1i(ySamplerLoc, 0); + s_gles2.glUniform1i(uSamplerLoc, 1); + s_gles2.glUniform1i(vSamplerLoc, 2); + + s_gles2.glBindBuffer(GL_ARRAY_BUFFER, vbuf); + s_gles2.glEnableVertexAttribArray(posLoc); + s_gles2.glEnableVertexAttribArray(coordLoc); + + s_gles2.glVertexAttribPointer(posLoc, 3, GL_FLOAT, false, + kVertexAttribStride, + kVertexAttribPosOffset); + s_gles2.glVertexAttribPointer(coordLoc, 2, GL_FLOAT, false, + kVertexAttribStride, + kVertexAttribCoordOffset); + + s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf); + s_gles2.glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); + + s_gles2.glDisableVertexAttribArray(posLoc); + s_gles2.glDisableVertexAttribArray(coordLoc); +} + +// initialize(): allocate GPU memory for YUV components, +// and create shaders and vertex data. +YUVConverter::YUVConverter(int width, int height, FrameworkFormat format) : mFormat(format){ + + uint32_t totalSize, yStride, cStride, cHeight; + totalSize = 0; + getYUVSizes(width, height, mFormat, &totalSize, &yStride, &cStride, &cHeight); + + uint32_t yoff, uoff, voff, + ywidth, cwidth, cheight; + getYUVOffsets(width, height, mFormat, + &yoff, &uoff, &voff, + &ywidth, &cwidth); + cheight = height / 2; + + createYUVGLTex(GL_TEXTURE0, ywidth, height, &mYtex); + createYUVGLTex(GL_TEXTURE1, cwidth, cheight, &mUtex); + createYUVGLTex(GL_TEXTURE2, cwidth, cheight, &mVtex); + + createYUVGLShader(&mVshader, &mFshader, + &mProgram, + &mYWidthCutoffLoc, + &mCWidthCutoffLoc, + &mYSamplerLoc, + &mUSamplerLoc, + &mVSamplerLoc); + + createYUVGLFullscreenQuad(&mVbuf, &mIbuf, width, ywidth); +} + +// drawConvert: per-frame updates. +// Update YUV textures, then draw the fullscreen +// quad set up above, which results in a framebuffer +// with the RGB colors. +void YUVConverter::drawConvert(int x, int y, + int width, int height, + char* pixels) { + s_gles2.glViewport(x, y, width, height); + + uint32_t yoff, uoff, voff, + ywidth, cwidth, cheight; + getYUVOffsets(width, height, mFormat, + &yoff, &uoff, &voff, + &ywidth, &cwidth); + cheight = height / 2; + + subUpdateYUVGLTex(GL_TEXTURE0, mYtex, + x, y, ywidth, height, + pixels + yoff); + subUpdateYUVGLTex(GL_TEXTURE1, mUtex, + x, y, cwidth, cheight, + pixels + uoff); + subUpdateYUVGLTex(GL_TEXTURE2, mVtex, + x, y, cwidth, cheight, + pixels + voff); + + + updateCutoffs(width, ywidth, width / 2, cwidth); + + doYUVConversionDraw(mProgram, + mYWidthCutoffLoc, + mCWidthCutoffLoc, + mYSamplerLoc, + mUSamplerLoc, + mVSamplerLoc, + mVbuf, mIbuf, + width, ywidth, + width / 2, cwidth, + mYWidthCutoff, + mCWidthCutoff); +} + +void YUVConverter::updateCutoffs(float width, float ywidth, + float halfwidth, float cwidth) { + switch (mFormat) { + case FRAMEWORK_FORMAT_YV12: + mYWidthCutoff = ((float)width) / ((float)ywidth); + mCWidthCutoff = ((float)halfwidth) / ((float)cwidth); + break; + case FRAMEWORK_FORMAT_YUV_420_888: + mYWidthCutoff = 1.0f; + mCWidthCutoff = 1.0f; + break; + case FRAMEWORK_FORMAT_GL_COMPATIBLE: + FATAL("Input not a YUV format!"); + } +} + +YUVConverter::~YUVConverter() { + if (mIbuf) s_gles2.glDeleteBuffers(1, &mIbuf); + if (mVbuf) s_gles2.glDeleteBuffers(1, &mVbuf); + if (mProgram) s_gles2.glDeleteProgram(mProgram); + if (mFshader) s_gles2.glDeleteShader(mFshader); + if (mVshader) s_gles2.glDeleteShader(mVshader); + if (mYtex) s_gles2.glDeleteTextures(1, &mYtex); + if (mUtex) s_gles2.glDeleteTextures(1, &mUtex); + if (mVtex) s_gles2.glDeleteTextures(1, &mVtex); +} diff --git a/host/libs/virglrenderer/libOpenglRender/YUVConverter.h b/host/libs/virglrenderer/libOpenglRender/YUVConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..6d773a1b382028911e4839b62a6b8a6a3044f766 --- /dev/null +++ b/host/libs/virglrenderer/libOpenglRender/YUVConverter.h @@ -0,0 +1,77 @@ +/* +* Copyright (C) 2016 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include "FrameworkFormats.h" + +// The purpose of YUVConverter is to use +// OpenGL shaders to convert YUV images to RGB +// images that can be displayed on screen. +// Doing this on the GPU can be much faster than +// on the CPU. + +// Usage: +// 0. Have a current OpenGL context working. +// 1. Constructing the YUVConverter object will allocate +// OpenGL resources needed to convert, given the desired +// |width| and |height| of the buffer. +// 2. To convert a given YUV buffer of |pixels|, call +// the drawConvert method (with x, y, width, and height +// arguments depicting the region to convert). +// The RGB version of the YUV buffer will be drawn +// to the current framebuffer. To retrieve +// the result, if the user of the result is an OpenGL texture, +// it suffices to have that texture be the color attachment +// of the framebuffer object. Or, if you want the results +// on the CPU, call glReadPixels() after the call to drawConvert(). +class YUVConverter { +public: + // call ctor when creating a gralloc buffer + // with YUV format + YUVConverter(int width, int height, FrameworkFormat format); + // destroy when ColorBuffer is destroyed + ~YUVConverter(); + // call when gralloc_unlock updates + // the host color buffer + // (rcUpdateColorBuffer) + void drawConvert(int x, int y, int width, int height, char* pixels); +private: + // For dealing with n-pixel-aligned buffers + void updateCutoffs(float width, float ywidth, float halfwidth, float cwidth); + FrameworkFormat mFormat; + // We need the following GL objects: + GLuint mVshader = 0; + GLuint mFshader = 0; // Fragment shader (does actual conversion) + GLuint mProgram = 0; + GLuint mVbuf = 0; + GLuint mIbuf = 0; + GLuint mYtex = 0; + GLuint mUtex = 0; + GLuint mVtex = 0; + + // shader uniform locations + GLint mYWidthCutoffLoc = -1; + GLint mCWidthCutoffLoc = -1; + GLint mYSamplerLoc = -1; + GLint mUSamplerLoc = -1; + GLint mVSamplerLoc = -1; + float mYWidthCutoff = 1.0; + float mCWidthCutoff = 1.0; +}; diff --git a/host/libs/virglrenderer/libvirglrenderer.lds b/host/libs/virglrenderer/libvirglrenderer.lds new file mode 100644 index 0000000000000000000000000000000000000000..9fc62d540a64b44409954e30aa7a1fd917a939cf --- /dev/null +++ b/host/libs/virglrenderer/libvirglrenderer.lds @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ +global: + # virglrenderer API + virgl_renderer_init; + virgl_renderer_poll; + virgl_renderer_get_cursor_data; + virgl_renderer_resource_create; + virgl_renderer_resource_unref; + virgl_renderer_context_create; + virgl_renderer_context_destroy; + virgl_renderer_submit_cmd; + virgl_renderer_transfer_read_iov; + virgl_renderer_transfer_write_iov; + virgl_renderer_get_cap_set; + virgl_renderer_fill_caps; + virgl_renderer_resource_attach_iov; + virgl_renderer_resource_detach_iov; + virgl_renderer_create_fence; + virgl_renderer_force_ctx_0; + virgl_renderer_ctx_attach_resource; + virgl_renderer_ctx_detach_resource; + virgl_renderer_resource_get_info; + + # fake gralloc1 implementation + hw_get_module; + + # fake libsync implementation + sync_wait; + + # Type-strings and type-infos required by sanitizers + _ZTS*; + _ZTI*; + +local: + *; +}; diff --git a/host/libs/virglrenderer/renderControl_dec/renderControl.attrib b/host/libs/virglrenderer/renderControl_dec/renderControl.attrib new file mode 100644 index 0000000000000000000000000000000000000000..6ff20b66e27801864570a1f069a1526bd0806be1 --- /dev/null +++ b/host/libs/virglrenderer/renderControl_dec/renderControl.attrib @@ -0,0 +1,105 @@ +GLOBAL + base_opcode 10000 + +rcGetEGLVersion + flag custom_decoder + dir major out + len major sizeof(EGLint) + dir minor out + len minor sizeof(EGLint) + +rcQueryEGLString + flag custom_decoder + dir buffer out + len buffer bufferSize + +rcGetGLString + flag custom_decoder + dir buffer out + len buffer bufferSize + +rcGetNumConfigs + dir numAttribs out + len numAttribs sizeof(uint32_t) + +rcGetConfigs + dir buffer out + len buffer bufSize + +rcChooseConfig + flag custom_decoder + dir attribs in + len attribs attribs_size + dir configs out + var_flag configs nullAllowed + len configs configs_size*sizeof(uint32_t) + +rcCreateContext + flag custom_decoder + +rcDestroyContext + flag custom_decoder + +rcCreateWindowSurface + flag custom_decoder + +rcDestroyWindowSurface + flag custom_decoder + +rcCloseColorBuffer + flag flushOnEncode + +rcSetWindowColorBuffer + flag custom_decoder + +rcMakeCurrent + flag custom_decoder + +rcFBSetSwapInterval + flag custom_decoder + +rcBindTexture + flag custom_decoder + +rcBindRenderbuffer + flag custom_decoder + +rcReadColorBuffer + dir pixels out + +rcUpdateColorBuffer + dir pixels in + var_flag pixels isLarge + +rcCreateClientImage + flag custom_decoder + +rcSelectChecksumHelper + flag custom_decoder + +rcCreateSyncKHR + flag custom_decoder + dir attribs in + len attribs num_attribs + dir glsync_out out + len glsync_out sizeof(uint64_t) + dir syncthread_out out + len syncthread_out sizeof(uint64_t) + +rcClientWaitSyncKHR + flag custom_decoder + +rcDestroySyncKHR + flag custom_decoder + +rcSetPuid + flag custom_decoder + +rcUpdateColorBufferDMA + dir pixels in + len pixels pixels_size + var_flag pixels DMA + flag flushOnEncode + +rcWaitSyncKHR + flag custom_decoder diff --git a/host/libs/virglrenderer/renderControl_dec/renderControl.in b/host/libs/virglrenderer/renderControl_dec/renderControl.in new file mode 100644 index 0000000000000000000000000000000000000000..e1dea92c102534f0e815b21a48def38a890845cc --- /dev/null +++ b/host/libs/virglrenderer/renderControl_dec/renderControl.in @@ -0,0 +1,37 @@ +GL_ENRTY(GLint, rcGetRendererVersion) +GL_ENTRY(EGLint, rcGetEGLVersion, EGLint *major, EGLint *minor) +GL_ENTRY(EGLint, rcQueryEGLString, EGLenum name, void *buffer, EGLint bufferSize) +GL_ENTRY(EGLint, rcGetGLString, EGLenum name, void *buffer, EGLint bufferSize) +GL_ENTRY(EGLint, rcGetNumConfigs, uint32_t *numAttribs) +GL_ENTRY(EGLint, rcGetConfigs, uint32_t bufSize, GLuint *buffer) +GL_ENTRY(EGLint, rcChooseConfig, EGLint *attribs, uint32_t attribs_size, uint32_t *configs, uint32_t configs_size) +GL_ENTRY(EGLint, rcGetFBParam, EGLint param) +GL_ENTRY(uint32_t, rcCreateContext, uint32_t config, uint32_t share, uint32_t glVersion) +GL_ENTRY(void, rcDestroyContext, uint32_t context) +GL_ENTRY(uint32_t, rcCreateWindowSurface, uint32_t config, uint32_t width, uint32_t height) +GL_ENTRY(void, rcDestroyWindowSurface, uint32_t windowSurface) +GL_ENTRY(uint32_t, rcCreateColorBuffer, uint32_t width, uint32_t height, GLenum internalFormat) +GL_ENTRY(void, rcOpenColorBuffer, uint32_t colorbuffer) +GL_ENTRY(void, rcCloseColorBuffer, uint32_t colorbuffer) +GL_ENTRY(void, rcSetWindowColorBuffer, uint32_t windowSurface, uint32_t colorBuffer) +GL_ENTRY(int, rcFlushWindowColorBuffer, uint32_t windowSurface) +GL_ENTRY(EGLint, rcMakeCurrent, uint32_t context, uint32_t drawSurf, uint32_t readSurf) +GL_ENTRY(void, rcFBPost, uint32_t colorBuffer) +GL_ENTRY(void, rcFBSetSwapInterval, EGLint interval) +GL_ENTRY(void, rcBindTexture, uint32_t colorBuffer) +GL_ENTRY(void, rcBindRenderbuffer, uint32_t colorBuffer) +GL_ENTRY(EGLint, rcColorBufferCacheFlush, uint32_t colorbuffer, EGLint postCount, int forRead) +GL_ENTRY(void, rcReadColorBuffer, uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void *pixels) +GL_ENTRY(int, rcUpdateColorBuffer, uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void *pixels) +GL_ENTRY(int, rcOpenColorBuffer2, uint32_t colorbuffer) +GL_ENTRY(uint32_t, rcCreateClientImage, uint32_t context, EGLenum target, GLuint buffer) +GL_ENTRY(int, rcDestroyClientImage, uint32_t image) +GL_ENTRY(void, rcSelectChecksumHelper, uint32_t newProtocol, uint32_t reserved) +GL_ENTRY(void, rcCreateSyncKHR, EGLenum type, EGLint* attribs, uint32_t num_attribs, int destroy_when_signaled, uint64_t* glsync_out, uint64_t* syncthread_out) +GL_ENTRY(EGLint, rcClientWaitSyncKHR, uint64_t sync, EGLint flags, uint64_t timeout) +GL_ENTRY(void, rcFlushWindowColorBufferAsync, uint32_t windowSurface) +GL_ENTRY(int, rcDestroySyncKHR, uint64_t sync) +GL_ENTRY(void, rcSetPuid, uint64_t puid) +GL_ENTRY(int, rcUpdateColorBufferDMA, uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void* pixels, uint32_t pixels_size) +GL_ENTRY(uint32_t, rcCreateColorBufferDMA, uint32_t width, uint32_t height, GLenum internalFormat, int frameworkFormat) +GL_ENTRY(void, rcWaitSyncKHR, uint64_t sync, EGLint flags); diff --git a/host/libs/virglrenderer/renderControl_dec/renderControl.types b/host/libs/virglrenderer/renderControl_dec/renderControl.types new file mode 100644 index 0000000000000000000000000000000000000000..578492b621da9d5c59fd989329d25e33ea7a756e --- /dev/null +++ b/host/libs/virglrenderer/renderControl_dec/renderControl.types @@ -0,0 +1,14 @@ +uint32_t 32 0x%08x +uint64_t 64 0x%016lx +EGLint 32 0x%08x +GLint 32 0x%08x +GLuint 32 0x%08x +GLenum 32 0x%08x +EGLenum 32 0x%08x +uint32_t* 32 0x%08x +EGLint* 32 0x%08x +int* 32 0x%08x +GLint* 32 0x%08x +GLuint* 32 0x%08x +void* 32 0x%08x +uint64_t* 32 0x%08x diff --git a/host/libs/virglrenderer/renderControl_dec/renderControl_types.h b/host/libs/virglrenderer/renderControl_dec/renderControl_types.h new file mode 100644 index 0000000000000000000000000000000000000000..dd6b41271acf37c4da1474d9d4bbe551e60b3c9c --- /dev/null +++ b/host/libs/virglrenderer/renderControl_dec/renderControl_types.h @@ -0,0 +1,20 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <EGL/egl.h> + +#include <GLES/gl.h> diff --git a/host/linux_uapi/linux/virtio_gpu.h b/host/linux_uapi/linux/virtio_gpu.h new file mode 100644 index 0000000000000000000000000000000000000000..b43671f42a932c81069a4be7e52a107dafc6b054 --- /dev/null +++ b/host/linux_uapi/linux/virtio_gpu.h @@ -0,0 +1,226 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ +#ifndef VIRTIO_GPU_HW_H +#define VIRTIO_GPU_HW_H +#include <linux/types.h> +#define VIRTIO_GPU_F_VIRGL 0 +enum virtio_gpu_ctrl_type { + VIRTIO_GPU_UNDEFINED = 0, + VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100, + VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, + VIRTIO_GPU_CMD_RESOURCE_UNREF, + VIRTIO_GPU_CMD_SET_SCANOUT, + VIRTIO_GPU_CMD_RESOURCE_FLUSH, + VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, + VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, + VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, + VIRTIO_GPU_CMD_GET_CAPSET_INFO, + VIRTIO_GPU_CMD_GET_CAPSET, + VIRTIO_GPU_CMD_CTX_CREATE = 0x0200, + VIRTIO_GPU_CMD_CTX_DESTROY, + VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, + VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE, + VIRTIO_GPU_CMD_RESOURCE_CREATE_3D, + VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, + VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D, + VIRTIO_GPU_CMD_SUBMIT_3D, + VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300, + VIRTIO_GPU_CMD_MOVE_CURSOR, + VIRTIO_GPU_RESP_OK_NODATA = 0x1100, + VIRTIO_GPU_RESP_OK_DISPLAY_INFO, + VIRTIO_GPU_RESP_OK_CAPSET_INFO, + VIRTIO_GPU_RESP_OK_CAPSET, + VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, + VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY, + VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID, + VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID, + VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID, + VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER, +}; +#define VIRTIO_GPU_FLAG_FENCE (1 << 0) +struct virtio_gpu_ctrl_hdr { + __le32 type; + __le32 flags; + __le64 fence_id; + __le32 ctx_id; + __le32 padding; +}; +struct virtio_gpu_cursor_pos { + __le32 scanout_id; + __le32 x; + __le32 y; + __le32 padding; +}; +struct virtio_gpu_update_cursor { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_cursor_pos pos; + __le32 resource_id; + __le32 hot_x; + __le32 hot_y; + __le32 padding; +}; +struct virtio_gpu_rect { + __le32 x; + __le32 y; + __le32 width; + __le32 height; +}; +struct virtio_gpu_resource_unref { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; + __le32 padding; +}; +struct virtio_gpu_resource_create_2d { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; + __le32 format; + __le32 width; + __le32 height; +}; +struct virtio_gpu_set_scanout { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + __le32 scanout_id; + __le32 resource_id; +}; +struct virtio_gpu_resource_flush { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + __le32 resource_id; + __le32 padding; +}; +struct virtio_gpu_transfer_to_host_2d { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_rect r; + __le64 offset; + __le32 resource_id; + __le32 padding; +}; +struct virtio_gpu_mem_entry { + __le64 addr; + __le32 length; + __le32 padding; +}; +struct virtio_gpu_resource_attach_backing { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; + __le32 nr_entries; +}; +struct virtio_gpu_resource_detach_backing { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; + __le32 padding; +}; +#define VIRTIO_GPU_MAX_SCANOUTS 16 +struct virtio_gpu_resp_display_info { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_display_one { + struct virtio_gpu_rect r; + __le32 enabled; + __le32 flags; + } pmodes[VIRTIO_GPU_MAX_SCANOUTS]; +}; +struct virtio_gpu_box { + __le32 x, y, z; + __le32 w, h, d; +}; +struct virtio_gpu_transfer_host_3d { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_box box; + __le64 offset; + __le32 resource_id; + __le32 level; + __le32 stride; + __le32 layer_stride; +}; +#define VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP (1 << 0) +struct virtio_gpu_resource_create_3d { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; + __le32 target; + __le32 format; + __le32 bind; + __le32 width; + __le32 height; + __le32 depth; + __le32 array_size; + __le32 last_level; + __le32 nr_samples; + __le32 flags; + __le32 padding; +}; +struct virtio_gpu_ctx_create { + struct virtio_gpu_ctrl_hdr hdr; + __le32 nlen; + __le32 padding; + char debug_name[64]; +}; +struct virtio_gpu_ctx_destroy { + struct virtio_gpu_ctrl_hdr hdr; +}; +struct virtio_gpu_ctx_resource { + struct virtio_gpu_ctrl_hdr hdr; + __le32 resource_id; + __le32 padding; +}; +struct virtio_gpu_cmd_submit { + struct virtio_gpu_ctrl_hdr hdr; + __le32 size; + __le32 padding; +}; +#define VIRTIO_GPU_CAPSET_VIRGL 1 +struct virtio_gpu_get_capset_info { + struct virtio_gpu_ctrl_hdr hdr; + __le32 capset_index; + __le32 padding; +}; +struct virtio_gpu_resp_capset_info { + struct virtio_gpu_ctrl_hdr hdr; + __le32 capset_id; + __le32 capset_max_version; + __le32 capset_max_size; + __le32 padding; +}; +struct virtio_gpu_get_capset { + struct virtio_gpu_ctrl_hdr hdr; + __le32 capset_id; + __le32 capset_version; +}; +struct virtio_gpu_resp_capset { + struct virtio_gpu_ctrl_hdr hdr; + __u8 capset_data[]; +}; +#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) +struct virtio_gpu_config { + __u32 events_read; + __u32 events_clear; + __u32 num_scanouts; + __u32 num_capsets; +}; +enum virtio_gpu_formats { + VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1, + VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2, + VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3, + VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4, + VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67, + VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68, + VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121, + VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134, +}; +#endif